main.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWMath Test Program *
  23. * *
  24. * $Archive:: /Commando/Code/Tests/mathtest/main.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 10/03/01 12:52p $*
  29. * *
  30. * $Revision:: 47 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "matrix4.h"
  36. #include "matrix3d.h"
  37. #include "vector3.h"
  38. #include "euler.h"
  39. #include "ode.h"
  40. #include "obbox.h"
  41. #include "plane.h"
  42. #include "colmath.h"
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <math.h>
  46. #include <assert.h>
  47. #include "p_timer.h"
  48. #include "output.h"
  49. #include "odetest.h"
  50. #include "raytest.h"
  51. #include "aaboxtest.h"
  52. #include "obboxtest.h"
  53. #include "uarraytest.h"
  54. #include "lineseg.h"
  55. #include "mempooltest.h"
  56. #include "tri.h"
  57. #include "frustum.h"
  58. #include "jan_math.h"
  59. #include <windows.h>
  60. const double TOLERANCE = 0.00001;
  61. static int _Global;
  62. void test_lookat(void);
  63. void test_vectors(void);
  64. void test_eulers(void);
  65. void test_matrix3(void);
  66. void test_ode_systems(void);
  67. void test_quaternions(void);
  68. void test_planes(void);
  69. void test_animation(void);
  70. void test_concatenation(void);
  71. void test_sphere_intersection(void);
  72. void test_aabox_transform(void);
  73. void test_vector_quick_length(void);
  74. void test_sqrt_time(void);
  75. void test_windows(void);
  76. void test_point_containment(void);
  77. void test_fast_trig(void);
  78. float gaussian_function(float x);
  79. float integrate(float (*f)(float),float start,float end,int slices);
  80. Matrix3D random_matrix(void);
  81. void print_matrix(const Matrix3D & m);
  82. void Transform_Min_Max_AABox_Brute_Force(const Matrix3D & tm,const Vector3 & min,const Vector3 & max,
  83. Vector3 & newmin,Vector3 & newmax);
  84. void Bug_Function(const Matrix3D & A,const Matrix3D & B,Matrix3D * set_res);
  85. /*
  86. This really needs to become a rigorous test of the math library...
  87. So far, I've only added random stuff as I find bugs...
  88. */
  89. void main(void)
  90. {
  91. WWMath::Init();
  92. Matrix4 tm(1);
  93. tm[0][3] = 1.0f;
  94. tm[1][3] = 2.0f;
  95. tm[2][3] = 3.0f;
  96. Matrix4 invtm = tm.Inverse();
  97. float area = integrate(gaussian_function,-10.0f,10.0f,1000);
  98. float e = exp(1.0f);
  99. #if 0
  100. Vector3 array[3];
  101. printf("%f",array[2].Y);
  102. array[1] = Vector3(1,1,1);
  103. array[2].X = 5.0f;
  104. for (int i=0; i<3; i++) {
  105. array[i].Set(rand() & 0xFF,rand() & 0xFF,rand() & 0xFF);
  106. }
  107. #endif
  108. #if 0
  109. PlaneClass plane;
  110. plane.N.Set(rand() & 0xFF,rand() & 0xFF,rand() & 0xFF);
  111. plane.D = rand() & 0xFF;
  112. if (plane.In_Front(Vector3(5,5,5))) {
  113. printf("hi");
  114. } else {
  115. printf("a");
  116. }
  117. #endif
  118. test_fast_trig();
  119. #if 0
  120. Test_AABoxes();
  121. test_point_containment();
  122. Test_Rays();
  123. test_mempool();
  124. Test_OBBoxes();
  125. test_lookat();
  126. test_vectors();
  127. test_eulers();
  128. test_matrix3();
  129. test_quaternions();
  130. test_animation();
  131. test_ode_systems();
  132. Test_Rays();
  133. test_planes();
  134. test_concatenation();
  135. Test_Uarray();
  136. test_sphere_intersection();
  137. test_aabox_transform();
  138. test_vector_quick_length();
  139. test_sqrt_time();
  140. #endif
  141. WWMath::Shutdown();
  142. }
  143. void test_fast_trig(void)
  144. {
  145. Print_Title("Testing table-based trig code.");
  146. float max_sin_error = 0.0f;
  147. float max_cos_error = 0.0f;
  148. float max_asin_error = 0.0f;
  149. float max_acos_error = 0.0f;
  150. const float STEPS=32000.0f;
  151. float START = -8.0f * WWMATH_PI;
  152. float STOP = 8.0f * WWMATH_PI;
  153. float error;
  154. for (float test=START; test < STOP; test+=(STOP-START) / STEPS) {
  155. error = WWMath::Fabs(WWMath::Sin(test) - WWMath::Fast_Sin(test));
  156. if (error > max_sin_error) {
  157. max_sin_error = error;
  158. }
  159. error = WWMath::Fabs(WWMath::Cos(test) - WWMath::Fast_Cos(test));
  160. if (error > max_cos_error) {
  161. max_cos_error = error;
  162. }
  163. }
  164. START=-1.0f;
  165. STOP=1.0f;
  166. for (test=START; test<STOP; test+=(STOP-START)/STEPS) {
  167. error = WWMath::Fabs(WWMath::Asin(test) - WWMath::Fast_Asin(test));
  168. if (error > max_asin_error) {
  169. max_asin_error = error;
  170. }
  171. error = WWMath::Fabs(WWMath::Acos(test) - WWMath::Fast_Acos(test));
  172. if (error > max_acos_error) {
  173. max_acos_error = error;
  174. }
  175. }
  176. printf("max cos error: %f\r\n",max_cos_error);
  177. printf("max sin error: %f\r\n",max_sin_error);
  178. printf("max acos error: %f\r\n",max_acos_error);
  179. printf("max asin error: %f\r\n",max_asin_error);
  180. }
  181. void test_vectors(void)
  182. {
  183. Print_Title("Testing matrix*vector code.");
  184. /*
  185. ** Matrix * Vector (this was demonstrating a compiler bug...)
  186. */
  187. Vector3 vec(5.0,0.0,0.0);
  188. Matrix3D mat(1);
  189. Vector3 tvec = mat*vec;
  190. CHECK(0,((tvec - vec).Length() < TOLERANCE));
  191. /*
  192. ** Timing the difference between operator + and Vector3::Add
  193. */
  194. Vector3 tab[16000];
  195. for (int i=0; i<16000; i++) {
  196. tab[i].Set(WWMath::Random_Float(),WWMath::Random_Float(),WWMath::Random_Float());
  197. }
  198. Vector3 c;
  199. unsigned long op_cycles = Get_CPU_Clock();
  200. for (i=0; i<16000; i++) {
  201. c = tab[0] + tab[i];
  202. }
  203. op_cycles = Get_CPU_Clock() - op_cycles;
  204. c.Normalize();
  205. printf("Vector3::operator + cycles: %d\n",op_cycles);
  206. unsigned long add_cycles = Get_CPU_Clock();
  207. for (i=0; i<16000; i++) {
  208. Vector3::Add(tab[0],tab[i],&c);
  209. }
  210. add_cycles = Get_CPU_Clock() - add_cycles;
  211. c.Normalize();
  212. printf("Vector3::Add cycles: %d\n",add_cycles);
  213. printf("Operator/Add ration: %f\n",(float)op_cycles / (float)add_cycles);
  214. }
  215. void test_lookat(void)
  216. {
  217. int check = 0;
  218. Print_Title("Testing matrix look-at code.");
  219. Matrix3D tm(1);
  220. Matrix3D invtm;
  221. tm.Look_At(Vector3(0,0,0),Vector3(-1,0,0),0);
  222. Quaternion q = Build_Quaternion(tm);
  223. CHECK(check++,(fabs(q[0] - 0.5) < TOLERANCE));
  224. Vector3 pos;
  225. Vector3 tar;
  226. Vector3 test;
  227. pos.Set(0,0,0);
  228. tar.Set(30.0f,10.0f,3.0f);
  229. tm.Look_At(pos,tar,0.0f);
  230. tm.Get_Orthogonal_Inverse(invtm);
  231. test = invtm * tar;
  232. CHECK(check++,(Vector2(test.X,test.Y).Length() < 0.001f));
  233. tar.Set(1,-2,1);
  234. tm.Obj_Look_At(pos,tar,0.0f);
  235. tm.Get_Orthogonal_Inverse(invtm);
  236. test = invtm * tar;
  237. CHECK(check++,(Vector2(test.Y,test.Z).Length() < 0.001f));
  238. }
  239. void test_eulers(void)
  240. {
  241. Print_Title("Testing euler angle conversion code.");
  242. /*
  243. ** Testing Euler angles
  244. */
  245. Matrix3D mat;
  246. float xrot,yrot,zrot;
  247. mat.Rotate_X(0.3f);
  248. mat.Rotate_Z(0.2f);
  249. mat.Rotate_Y(0.1f);
  250. EulerAnglesClass euler(mat,EulerOrderYXYr);
  251. euler.To_Matrix(mat);
  252. Matrix3D mat2(1);
  253. mat2.Rotate_Y(euler.Get_Angle(0));
  254. mat2.Rotate_X(euler.Get_Angle(1));
  255. mat2.Rotate_Y(euler.Get_Angle(2));
  256. CHECK(0,(((mat2[0] - mat[0]).Length() < TOLERANCE) &&
  257. ((mat2[1] - mat[1]).Length() < TOLERANCE) &&
  258. ((mat2[2] - mat[2]).Length() < TOLERANCE)));
  259. mat.Make_Identity();
  260. mat.Rotate_Y(DEG_TO_RADF(12.0f));
  261. mat.Rotate_Z(DEG_TO_RADF(25.0f));
  262. EulerAnglesClass euler2(mat,EulerOrderXYZr);
  263. xrot = euler2.Get_Angle(0);
  264. yrot = euler2.Get_Angle(1);
  265. zrot = euler2.Get_Angle(2);
  266. mat2.Make_Identity();
  267. mat2.Rotate_X(xrot);
  268. mat2.Rotate_Y(yrot);
  269. mat2.Rotate_Z(zrot);
  270. CHECK(0,(((mat2[0] - mat[0]).Length() < TOLERANCE) &&
  271. ((mat2[1] - mat[1]).Length() < TOLERANCE) &&
  272. ((mat2[2] - mat[2]).Length() < TOLERANCE)));
  273. }
  274. void test_matrix3(void)
  275. {
  276. Print_Title("Testing Matrix3 Inversion");
  277. /*
  278. ** Testing Matrix3 Inversion function
  279. */
  280. Matrix3 mat;
  281. mat[0][0] = 6.0f; mat[0][1] = 4.5f; mat[0][2] = -1.2f;
  282. mat[1][0] = -3.0f; mat[1][1] = 0.0f; mat[1][2] = -1.3f;
  283. mat[2][0] = 2.1f; mat[2][1] = 1.5f; mat[2][2] = 17.2f;
  284. Matrix3 invmat = mat.Inverse();
  285. Vector3 a(10.0, 20.0, 30.0);
  286. Vector3 b = mat * a;
  287. Vector3 c = invmat * b;
  288. CHECK(0,((a-c).Length() < TOLERANCE));
  289. }
  290. void test_ode_systems(void)
  291. {
  292. Print_Title("Testing ODE Integrators");
  293. /*
  294. ** Testing the new-style ODE solvers
  295. **
  296. ** Suppose we have a point which is going to move around
  297. ** a 2-D circle.
  298. */
  299. int i;
  300. float error = 0.0f;
  301. float maxerror[4] = {0,0,0,0};
  302. ODETestClass circle_system;
  303. circle_system.Point.Set(1,0,0);
  304. for (i=0; i<100; i++) {
  305. IntegrationSystem::Euler_Integrate(&circle_system,1.0);
  306. error = circle_system.Point.Length() - 1.0;
  307. if (fabs(error) > maxerror[0]) {
  308. maxerror[0] = fabs(error);
  309. }
  310. }
  311. Print("Euler max error = %f\n",maxerror[0]);
  312. circle_system.Point.Set(1,0,0);
  313. for (i=0; i<100; i++) {
  314. IntegrationSystem::Midpoint_Integrate(&circle_system,1.0);
  315. error = circle_system.Point.Length() - 1.0;
  316. if (fabs(error) > maxerror[1]) {
  317. maxerror[1] = fabs(error);
  318. }
  319. }
  320. Print("Midpoint max error = %f\n",maxerror[1]);
  321. circle_system.Point.Set(1,0,0);
  322. for (i=0; i<100; i++) {
  323. IntegrationSystem::Runge_Kutta_Integrate(&circle_system,1.0);
  324. error = circle_system.Point.Length() - 1.0;
  325. if (fabs(error) > maxerror[2]) {
  326. maxerror[2] = fabs(error);
  327. }
  328. }
  329. Print("Runge_Kutta max error = %f\n",maxerror[2]);
  330. circle_system.Point.Set(1,0,0);
  331. for (i=0; i<100; i++) {
  332. IntegrationSystem::Runge_Kutta5_Integrate(&circle_system,1.0);
  333. error = circle_system.Point.Length() - 1.0;
  334. if (fabs(error) > maxerror[3]) {
  335. maxerror[3] = fabs(error);
  336. }
  337. }
  338. Print("Runge_Kutta5 max error = %f\n",maxerror[3]);
  339. }
  340. void test_quaternions(void)
  341. {
  342. Print_Title("Testing Quaternions");
  343. int ci = 0;
  344. Quaternion q,p,pnew;
  345. Matrix3 tm;
  346. Vector3 vnew;
  347. // Testing rotation about the Z axis
  348. q = Axis_To_Quat(Vector3(0,0,1),DEG_TO_RAD(45.0f));
  349. p.Set(1.0,0.0,0.0,0.0);
  350. pnew = q*p*Conjugate(q);
  351. vnew.Set(pnew.X,pnew.Y,pnew.Z);
  352. CHECK(ci++,((vnew - Vector3(0.707f,0.707f,0.0f)).Length() < 0.01f));
  353. tm = Build_Matrix3(q);
  354. vnew = tm * Vector3(p.X,p.Y,p.Z);
  355. CHECK(ci++,((vnew - Vector3(0.707f,0.707f,0.0f)).Length() < 0.01f));
  356. // Testing rotation about the Y axis
  357. q = Axis_To_Quat(Vector3(0,1,0),DEG_TO_RADF(45.0f));
  358. p.Set(0.0f,0.0f,1.0f,0.0f);
  359. pnew = q*p*Conjugate(q);
  360. vnew.Set(pnew.X,pnew.Y,pnew.Z);
  361. CHECK(ci++,((vnew - Vector3(0.707f,0.0f,0.707f)).Length() < 0.01f));
  362. tm = Build_Matrix3(q);
  363. vnew = tm * Vector3(p.X,p.Y,p.Z);
  364. CHECK(ci++,((vnew - Vector3(0.707f,0.0f,0.707f)).Length() < 0.01f));
  365. // Testing rotation about the X axis
  366. q = Axis_To_Quat(Vector3(1,0,0),DEG_TO_RADF(45.0f));
  367. p.Set(0.0f,1.0f,0.0f,0.0f);
  368. pnew = q*p*Conjugate(q);
  369. vnew.Set(pnew.X,pnew.Y,pnew.Z);
  370. CHECK(ci++,((vnew - Vector3(0.0f,0.707f,0.707f)).Length() < 0.01f));
  371. tm = Build_Matrix3(q);
  372. vnew = tm * Vector3(p.X,p.Y,p.Z);
  373. CHECK(ci++,((vnew - Vector3(0.0f,0.707f,0.707f)).Length() < 0.01f));
  374. // Testing Rigid Body Angular momentum:
  375. Vector3 testpoint(1.0,0.0,0.0);
  376. Vector3 newpoint;
  377. Quaternion orientation(0,0,0,1);
  378. Quaternion omega(0.0,0.0,DEG_TO_RAD(45.0f),0.0);
  379. // Euler integrate for 1 second at 45 deg/s
  380. for (int i=0; i<100; i++) {
  381. // deriviative of orientation:
  382. Quaternion dorient = 0.5 * omega * orientation;
  383. // dt
  384. dorient = 0.01f * dorient;
  385. // new orientation
  386. orientation = orientation + dorient;
  387. orientation.Normalize();
  388. }
  389. // transform test point (should be 0.707,0.707,0):
  390. tm = Build_Matrix3(orientation);
  391. newpoint = tm * testpoint;
  392. CHECK(ci++,((newpoint - Vector3(0.707f,0.707f,0.0f)).Length() < 0.01f));
  393. // Get ready for some speed tests
  394. unsigned cycles;
  395. Quaternion input_quats[256];
  396. Quaternion output_quat;
  397. Matrix3D input_tms[256];
  398. Vector3 input_vec(4.5f,-3.7f,2.3f);
  399. Quaternion input_quat(input_vec.X,input_vec.Y,input_vec.Z,0.0f);
  400. Vector3 output_vec;
  401. Matrix3D output_tm;
  402. for (i=0; i<256; i++) {
  403. input_quats[i].Randomize();
  404. input_tms[i] = Build_Matrix3D(input_quats[i]);
  405. }
  406. // test speed of quaternion multiplication:
  407. cycles = Get_CPU_Clock();
  408. for (i=0; i<256; i++) {
  409. output_quat = input_quats[i] * input_quats[(i+5) & 0xFF];
  410. }
  411. cycles = Get_CPU_Clock() - cycles;
  412. Print("quaternion multiply cycles: %d\n",cycles / 256);
  413. // test speed of building a matrix from euler angles
  414. cycles = Get_CPU_Clock();
  415. for (i=0; i<256; i++) {
  416. output_tm.Make_Identity();
  417. output_tm.Rotate_Z(0.123f);
  418. output_tm.Rotate_Y(-0.342f);
  419. output_tm.Rotate_X(1.23f);
  420. }
  421. cycles = Get_CPU_Clock() - cycles;
  422. Print("building matrix cycles: %d\n",cycles / 256);
  423. // test speed of matrix-vector multiplication
  424. cycles = Get_CPU_Clock();
  425. for (i=0; i<256; i++) {
  426. output_vec = input_tms[i] * input_vec;
  427. }
  428. cycles = Get_CPU_Clock() - cycles;
  429. Print("matrix-vector cycles: %d\n",cycles / 256);
  430. // test speed of convert matrix, then matrix-vector multiplication
  431. cycles = Get_CPU_Clock();
  432. for (i=0; i<256; i++) {
  433. tm = Build_Matrix3D(input_quats[i]);
  434. output_vec = tm * input_vec;
  435. }
  436. cycles = Get_CPU_Clock() - cycles;
  437. Print("convert-matrix-vector cycles: %d\n",cycles / 256);
  438. // test speed of naive quat-vector transform
  439. cycles = Get_CPU_Clock();
  440. for (i=0; i<256; i++) {
  441. output_quat = input_quats[i] * input_quat * Conjugate(input_quats[i]);
  442. }
  443. cycles = Get_CPU_Clock() - cycles;
  444. Print("naive quat-vector cycles: %d\n",cycles / 256);
  445. // test speed of quat-vector transform
  446. cycles = Get_CPU_Clock();
  447. for (i=0; i<256; i++) {
  448. output_vec = input_quats[i].Rotate_Vector(input_vec);
  449. }
  450. cycles = Get_CPU_Clock() - cycles;
  451. Print("fast quat-vector cycles: %d\n",cycles / 256);
  452. // test accuracy of the quat-vector transform
  453. Vector3 verify_vec;
  454. Quaternion tmp0,tmp1;
  455. bool success = true;
  456. for (i=0; i<256; i++) {
  457. output_vec = input_quats[i].Rotate_Vector(input_vec);
  458. verify_vec = Build_Matrix3D(input_quats[i]) * input_vec;
  459. tmp0.X = input_vec.X;
  460. tmp0.Y = input_vec.Y;
  461. tmp0.Z = input_vec.Z;
  462. tmp0.W = 0.0f;
  463. tmp1 = input_quats[i] * tmp0 * Conjugate(input_quats[i]);
  464. float delta = (output_vec - verify_vec).Length();
  465. if (delta > 0.001f) success = false;
  466. }
  467. CHECK(ci++,(success));
  468. }
  469. void test_animation(void)
  470. {
  471. Print_Title("Testing animation speed");
  472. int ci = 0;
  473. ///////////////////////////////////////////////////////////////////////
  474. // Animation calculation for a node consists of the following steps:
  475. //
  476. // - concatenate the root transform and the base pose transform
  477. // - grab the translation (possible lerp), concatenate it in
  478. // - grab the rotation (possible slerp), concatenate it in
  479. ///////////////////////////////////////////////////////////////////////
  480. int i;
  481. unsigned cycles;
  482. float percentage = 0.5f;
  483. Matrix3D root_tm;
  484. Matrix3D base_tm;
  485. Matrix3D tm;
  486. Matrix3D tmp;
  487. float euler_x0 = (float)DEG_TO_RAD(24.0f);
  488. float euler_y0 = (float)DEG_TO_RAD(30.0f);
  489. float euler_z0 = (float)DEG_TO_RAD(-12.0f);
  490. float euler_x1 = (float)DEG_TO_RAD(44.0f);
  491. float euler_y1 = (float)DEG_TO_RAD(23.0f);
  492. float euler_z1 = (float)DEG_TO_RAD(0.0f);
  493. float tx0 = 10.0f;
  494. float ty0 = -3.0f;
  495. float tz0 = 2.0f;
  496. float tx1 = 13.0f;
  497. float ty1 = -4.0f;
  498. float tz1 = 1.0f;
  499. Quaternion q0,q1;
  500. // initialization
  501. root_tm.Make_Identity();
  502. root_tm.Rotate_X(DEG_TO_RAD(12.0f));
  503. base_tm.Make_Identity();
  504. base_tm.Rotate_Z(DEG_TO_RAD(-3.0f));
  505. tmp.Make_Identity();
  506. tmp.Rotate_X(euler_x0);
  507. tmp.Rotate_Y(euler_y0);
  508. tmp.Rotate_Z(euler_z0);
  509. q0 = Build_Quaternion(tmp);
  510. tmp.Make_Identity();
  511. tmp.Rotate_X(euler_x1);
  512. tmp.Rotate_Y(euler_y1);
  513. tmp.Rotate_Z(euler_z1);
  514. q1 = Build_Quaternion(tmp);
  515. // anim method, Translation base and euler angles:
  516. cycles = Get_CPU_Clock();
  517. for (i=0; i<256; i++) {
  518. tm = root_tm;
  519. tm.Translate(tx0,ty1,tz0);
  520. Vector3 trans0(tx0,ty0,tz0);
  521. Vector3 trans1(tx1,ty1,tz1);
  522. tm.Translate((1.0 - percentage) * trans0 + (percentage) * trans1);
  523. tm.Rotate_X((1.0 - percentage) * euler_x0 + (percentage) * euler_x1);
  524. tm.Rotate_Y((1.0 - percentage) * euler_y0 + (percentage) * euler_y1);
  525. tm.Rotate_Z((1.0 - percentage) * euler_z0 + (percentage) * euler_z1);
  526. }
  527. cycles = Get_CPU_Clock() - cycles;
  528. printf("Translation Base + Euler animation cycles: %d\n",cycles / 256);
  529. // anim method, Translation base and quaternions:
  530. cycles = Get_CPU_Clock();
  531. for (i=0; i<256; i++) {
  532. tm = root_tm;
  533. tm.Translate(tx0,ty1,tz0);
  534. Vector3 trans0(tx0,ty0,tz0);
  535. Vector3 trans1(tx1,ty1,tz1);
  536. tm.Translate((1.0 - percentage) * trans0 + (percentage) * trans1);
  537. Quaternion q;
  538. Slerp(q,q0,q1,percentage);
  539. Matrix3D::Multiply(tm,Build_Matrix3D(q),&tm);
  540. }
  541. cycles = Get_CPU_Clock() - cycles;
  542. printf("Translation Base + Quaternion animation cycles: %d\n",cycles / 256);
  543. // anim method, Matrix3D base and euler angles:
  544. cycles = Get_CPU_Clock();
  545. for (i=0; i<256; i++) {
  546. Matrix3D::Multiply(root_tm,base_tm,&tm);
  547. Vector3 trans0(tx0,ty0,tz0);
  548. Vector3 trans1(tx1,ty1,tz1);
  549. tm.Translate((1.0 - percentage) * trans0 + (percentage) * trans1);
  550. tm.Rotate_X((1.0 - percentage) * euler_x0 + (percentage) * euler_x1);
  551. tm.Rotate_Y((1.0 - percentage) * euler_y0 + (percentage) * euler_y1);
  552. tm.Rotate_Z((1.0 - percentage) * euler_z0 + (percentage) * euler_z1);
  553. }
  554. cycles = Get_CPU_Clock() - cycles;
  555. printf("Matrix3D Base + Euler animation cycles: %d\n",cycles / 256);
  556. // anim method, Matrix3D base and quaternions:
  557. cycles = Get_CPU_Clock();
  558. for (i=0; i<256; i++) {
  559. Matrix3D::Multiply(root_tm,base_tm,&tm);
  560. Vector3 trans0(tx0,ty0,tz0);
  561. Vector3 trans1(tx1,ty1,tz1);
  562. tm.Translate((1.0 - percentage) * trans0 + (percentage) * trans1);
  563. Quaternion q;
  564. Slerp(q,q0,q1,percentage);
  565. Matrix3D::Multiply(tm,Build_Matrix3D(q),&tm);
  566. }
  567. cycles = Get_CPU_Clock() - cycles;
  568. printf("Matrix3D Base + Quaternion animation cycles: %d\n",cycles / 256);
  569. printf("\n");
  570. }
  571. void test_planes(void)
  572. {
  573. int ci=0;
  574. Print_Title("Testing PlaneClass");
  575. PlaneClass p0(Vector3(-1,0,0),-1);
  576. PlaneClass p1(Vector3(1,0,0),0);
  577. PlaneClass p2(Vector3(1,0,0),5);
  578. PlaneClass p3(Vector3(1,0,0),-5);
  579. SphereClass s0(Vector3(0,0,0),0.5f);
  580. SphereClass s1(Vector3(0,0,0),1.1f);
  581. CHECK(ci++,(p0.In_Front(s0)));
  582. CHECK(ci++,!(p0.In_Front(s1)));
  583. CHECK(ci++,(p0.In_Front_Or_Intersecting(s1)));
  584. CHECK(ci++,!(p1.In_Front(s0)));
  585. CHECK(ci++,!(p1.In_Front(s1)));
  586. CHECK(ci++,(p1.In_Front_Or_Intersecting(s0)));
  587. CHECK(ci++,(p1.In_Front_Or_Intersecting(s1)));
  588. CHECK(ci++,!(p2.In_Front_Or_Intersecting(s0)));
  589. CHECK(ci++,!(p2.In_Front_Or_Intersecting(s1)));
  590. }
  591. void test_concatenation(void)
  592. {
  593. Print_Title("Testing Matrix Concatenation Code");
  594. unsigned operator_cycles;
  595. unsigned concatenate_cycles;
  596. unsigned i;
  597. Matrix3D a,b;
  598. Matrix3D res1,res2;
  599. bool ok;
  600. a.Make_Identity();
  601. a.Rotate_X(20.0f);
  602. b.Make_Identity();
  603. b.Rotate_X(20.0f);
  604. res1 = a*b;
  605. print_matrix(res1);
  606. // Result being placed into a third matrix
  607. printf("\nResult being placed into third matrix c = a*b\n\n");
  608. for (i=0; i<10; i++) {
  609. a = random_matrix();
  610. b = random_matrix();
  611. operator_cycles = Get_CPU_Clock();
  612. res1 = a*b;
  613. operator_cycles = Get_CPU_Clock() - operator_cycles;
  614. concatenate_cycles = Get_CPU_Clock();
  615. Matrix3D::Multiply(a,b,&res2);
  616. concatenate_cycles = Get_CPU_Clock() - concatenate_cycles;
  617. ok = ( (((res1[0] - res2[0]).Length()) < 0.001f) &&
  618. (((res1[1] - res2[1]).Length()) < 0.001f) &&
  619. (((res1[2] - res2[2]).Length()) < 0.001f) );
  620. printf("Test %3d op_cycles: %d\tc_cycles: %d\t",i,operator_cycles,concatenate_cycles);
  621. if (ok) {
  622. printf("passed\n");
  623. } else {
  624. printf("<<FAILED!>>\n");
  625. }
  626. }
  627. // result being placed into one of the operands.
  628. printf("\nResult being placed into one of the operands a = a*b\n\n");
  629. Matrix3D a2,b2;
  630. for (i=0; i<10; i++) {
  631. a = random_matrix();
  632. b = random_matrix();
  633. a2 = a;
  634. b2 = b;
  635. operator_cycles = Get_CPU_Clock();
  636. a = a*b;
  637. operator_cycles = Get_CPU_Clock() - operator_cycles;
  638. concatenate_cycles = Get_CPU_Clock();
  639. Matrix3D::Multiply(a2,b2,&a2);
  640. concatenate_cycles = Get_CPU_Clock() - concatenate_cycles;
  641. bool ok = ( (((res1[0] - res2[0]).Length()) < 0.001f) &&
  642. (((res1[1] - res2[1]).Length()) < 0.001f) &&
  643. (((res1[2] - res2[2]).Length()) < 0.001f) );
  644. printf("Test %3d op_cycles: %d\tc_cycles: %d\t",i+10,operator_cycles,concatenate_cycles);
  645. if (ok) {
  646. printf("passed\n");
  647. } else {
  648. printf("<<FAILED!>>\n");
  649. }
  650. }
  651. }
  652. void print_matrix(const Matrix3D & m)
  653. {
  654. for (int row = 0;row < 3; row++) {
  655. printf("%f %f %f %f\n",m[row][0],m[row][1],m[row][2],m[row][3]);
  656. }
  657. printf("\n");
  658. }
  659. Matrix3D random_matrix(void)
  660. {
  661. Quaternion q;
  662. q.X = WWMath::Random_Float();
  663. q.Y = WWMath::Random_Float();
  664. q.Z = WWMath::Random_Float();
  665. q.W = WWMath::Random_Float() + 0.0001f;
  666. q.Normalize();
  667. Matrix3D m = Build_Matrix3D(q);
  668. m.Set_Translation(Vector3(WWMath::Random_Float(),WWMath::Random_Float(),WWMath::Random_Float()));
  669. return m;
  670. }
  671. void test_sphere_intersection(void)
  672. {
  673. Print_Title("Testing Sphere-LineSegment Intersection Code");
  674. SphereClass sphere(Vector3(0,0,0),1.0f);
  675. LineSegClass seg(Vector3(2,1,0),Vector3(0,0,0));
  676. CastResultStruct res;
  677. if (CollisionMath::Collide(seg,sphere,&res)) {
  678. printf("Test 1 Passed\n");
  679. } else {
  680. printf("Test 1 Failed\n");
  681. }
  682. }
  683. void test_aabox_transform(void)
  684. {
  685. int ci = 0;
  686. Print_Title("Testing AABox Transformation");
  687. Vector3 vmin(-10,-10,-10);
  688. Vector3 vmax(10,10,10);
  689. Matrix3D tm(Matrix3D::RotateZ90);
  690. Vector3 newmin,newmax;
  691. tm.Transform_Min_Max_AABox(vmin,vmax,&newmin,&newmax);
  692. CHECK(ci++, ((newmin - Vector3(-10,-10,-10)).Length() < TOLERANCE) &&
  693. ((newmax - Vector3(10,10,10)).Length() < TOLERANCE));
  694. vmin.Set(-1,-10,-1);
  695. vmax.Set(1,10,1);
  696. tm = Matrix3D::RotateZ90;
  697. tm.Transform_Min_Max_AABox(vmin,vmax,&newmin,&newmax);
  698. CHECK(ci++, ((newmin - Vector3(-10,-1,-1)).Length() < TOLERANCE) &&
  699. ((newmax - Vector3(10,1,1)).Length() < TOLERANCE));
  700. vmin.Set(0,0,0);
  701. vmax.Set(5,3,2);
  702. tm.Make_Identity();
  703. tm.Rotate_Z(DEG_TO_RAD(45.0));
  704. tm.Transform_Min_Max_AABox(vmin,vmax,&newmin,&newmax);
  705. Vector3 center(0,0,0);
  706. Vector3 extent(1,1,1);
  707. Vector3 newcenter,newextent;
  708. tm.Make_Identity();
  709. tm.Rotate_Z(DEG_TO_RAD(45.0f));
  710. tm.Transform_Center_Extent_AABox(center,extent,&newcenter,&newextent);
  711. }
  712. void test_vector_quick_length(void)
  713. {
  714. const int LONGITUDE_SAMPLES = 64;
  715. const int LATITUDE_SAMPLES = 32;
  716. float error;
  717. float max_error = 0.0f;
  718. float avg_error = 0.0f;
  719. double longitude;
  720. double latitude;
  721. for (int long_index=0; long_index<LONGITUDE_SAMPLES; long_index++) {
  722. longitude = 2*WWMATH_PI*((float)long_index/(float)LONGITUDE_SAMPLES);
  723. for (int lat_index=0; lat_index<LATITUDE_SAMPLES; lat_index++) {
  724. latitude = -WWMATH_PI/2.0f + WWMATH_PI*((float)lat_index/(float)LATITUDE_SAMPLES);
  725. Matrix3D tm(1);
  726. tm.Rotate_Z(longitude);
  727. tm.Rotate_Y(latitude);
  728. Vector3 vec = tm * Vector3(1,0,0);
  729. float real_length = vec.Length();
  730. float fake_length = vec.Quick_Length();
  731. error = fabs(fake_length - real_length);
  732. avg_error += error;
  733. if (error > max_error) {
  734. max_error = error;
  735. }
  736. }
  737. }
  738. avg_error = avg_error / (LONGITUDE_SAMPLES * LATITUDE_SAMPLES);
  739. printf("Vector3::Quick_Length Average Error: %f\n",avg_error);
  740. }
  741. void test_sqrt_time(void)
  742. {
  743. Print_Title("Timing some built-in functions");
  744. int i;
  745. unsigned int time;
  746. const int SAMPLES = 100;
  747. float results[SAMPLES];
  748. time = 0;
  749. for (i=0; i<SAMPLES; i++) {
  750. float f = WWMath::Random_Float() * 20000.0f;
  751. unsigned long cycles = Get_CPU_Clock();
  752. float val = sqrt(f);
  753. val+=sqrt(val);
  754. time += Get_CPU_Clock() - cycles;
  755. results[i] = val;
  756. }
  757. for (i=0; i<SAMPLES; i++) _Global+= results[i]; // keeping the compiler from optimizing this away
  758. printf("sqrt average cycles: %d\n",time / SAMPLES);
  759. time = 0;
  760. for (i=0; i<SAMPLES; i++) {
  761. float f = WWMath::Random_Float() * 6.28f;
  762. unsigned long cycles = Get_CPU_Clock();
  763. float val = sin(f);
  764. time += Get_CPU_Clock() - cycles;
  765. results[i] = val;
  766. }
  767. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  768. printf("sin average cycles: %d\n",time / SAMPLES);
  769. time = 0;
  770. for (i=0; i<SAMPLES; i++) {
  771. float f = WWMath::Random_Float() * 6.28f;
  772. unsigned long cycles = Get_CPU_Clock();
  773. float val = cos(f);
  774. time += Get_CPU_Clock() - cycles;
  775. results[i] = val;
  776. }
  777. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  778. printf("cos average cycles: %d\n",time / SAMPLES);
  779. // Time 100 multiplies
  780. time = Get_CPU_Clock();
  781. for (i=0; i<SAMPLES; i++) {
  782. float val = results[i]*results[SAMPLES-i-1];
  783. results[i] = val;
  784. }
  785. time = Get_CPU_Clock() - time;
  786. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  787. printf("multiply cycles: %d\n",time);
  788. // Time 100 adds
  789. time = Get_CPU_Clock();
  790. for (i=0; i<SAMPLES; i++) {
  791. float val = results[i]+results[SAMPLES-i-1];
  792. results[i] = val;
  793. }
  794. time = Get_CPU_Clock() - time;
  795. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  796. printf("add cycles: %d\n",time);
  797. // Time 100 multiplies
  798. time = Get_CPU_Clock();
  799. for (i=0; i<SAMPLES; i++) {
  800. float val = results[i]*results[SAMPLES-i-1];
  801. results[i] = val;
  802. }
  803. time = Get_CPU_Clock() - time;
  804. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  805. printf("multiply cycles: %d\n",time);
  806. // Time 100 adds
  807. time = Get_CPU_Clock();
  808. for (i=0; i<SAMPLES; i++) {
  809. float val = results[i]+results[SAMPLES-i-1];
  810. results[i] = val;
  811. }
  812. time = Get_CPU_Clock() - time;
  813. for (i=0; i<SAMPLES; i++) _Global+= results[i];
  814. printf("add cycles: %d\n",time);
  815. }
  816. void Transform_Min_Max_AABox_Brute_Force
  817. (
  818. const Matrix3D & tm,
  819. const Vector3 & min,
  820. const Vector3 & max,
  821. Vector3 & newmin,
  822. Vector3 & newmax
  823. )
  824. {
  825. int i;
  826. Vector3 pts[8];
  827. pts[0].Set(min.X,min.Y,min.Z);
  828. pts[1].Set(min.X,max.Y,min.Z);
  829. pts[2].Set(max.X,max.Y,min.Z);
  830. pts[3].Set(max.X,min.Y,min.Z);
  831. pts[4].Set(min.X,min.Y,max.Z);
  832. pts[5].Set(min.X,max.Y,max.Z);
  833. pts[6].Set(max.X,max.Y,max.Z);
  834. pts[7].Set(max.X,min.Y,max.Z);
  835. for (i=0; i<8; i++) {
  836. pts[i] = tm * pts[i];
  837. }
  838. newmin = pts[0];
  839. newmax = pts[0];
  840. for (i=1; i<8; i++) {
  841. if (newmin.X >= pts[i].X) newmin.X = pts[i].X;
  842. if (newmin.Y >= pts[i].Y) newmin.Y = pts[i].Y;
  843. if (newmin.Z >= pts[i].Z) newmin.Z = pts[i].Z;
  844. if (newmax.X <= pts[i].X) newmax.X = pts[i].X;
  845. if (newmax.Y <= pts[i].Y) newmax.Y = pts[i].Y;
  846. if (newmax.Z <= pts[i].Z) newmax.Z = pts[i].Z;
  847. }
  848. }
  849. void test_point_containment(void)
  850. {
  851. TriClass tri0,tri1;
  852. Vector3 normal0,normal1;
  853. Vector3 points[4];
  854. points[0].Set(10.6891f,23.5262f,-2.50006f);
  855. points[1].Set(1.0f,37.7164f,-2.50006f);
  856. points[2].Set(10.6566f,30.7858f,-2.50006f);
  857. points[3].Set(1.0f,16.0f,-2.50006f);
  858. for (int vi=0; vi<3; vi++) {
  859. tri0.V[vi] = &(points[vi]);
  860. tri1.V[vi] = &(points[vi+1]);
  861. }
  862. tri0.N = &normal0;
  863. tri1.N = &normal1;
  864. tri0.Compute_Normal();
  865. tri1.Compute_Normal();
  866. bool c0 = tri0.Contains_Point(Vector3(7.9999f,27.1883f,-2.50006f));
  867. bool c1 = tri1.Contains_Point(Vector3(7.9999f,27.1883f,-2.50006f));
  868. tri0.V[0] = &(points[1]);
  869. tri0.V[1] = &(points[0]);
  870. tri0.V[2] = &(points[2]);
  871. tri0.Compute_Normal();
  872. bool alternate_contains = tri0.Contains_Point(Vector3(7.9999f,27.1883f,-2.50006f));
  873. }
  874. float gaussian_function(float x)
  875. {
  876. return exp(-x*x);
  877. }
  878. float integrate(float (*f)(float),float start,float end,int slices)
  879. {
  880. float sum = 0.0f;
  881. float slice_width = (end-start)/slices;
  882. for (float sample = start; sample < end; sample += slice_width) {
  883. sum += f(sample) * slice_width;
  884. }
  885. return sum;
  886. }