meshgeometry.cpp 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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 : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/meshgeometry.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Jani_p $*
  29. * *
  30. * $Modtime:: 11/24/01 5:34p $*
  31. * *
  32. * $Revision:: 14 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * MeshGeometryClass::MeshGeometryClass -- Constructor *
  37. * MeshGeometryClass::MeshGeometryClass -- Copy Constructor *
  38. * -- assignment operator *
  39. * MeshGeometryClass::~MeshGeometryClass -- destructor *
  40. * MeshGeometryClass::Reset_Geometry -- releases current resources and allocates space if ne *
  41. * MeshGeometryClass::Get_Name -- returns the name *
  42. * MeshGeometryClass::Set_Name -- set the name of this model *
  43. * MeshGeometryClass::Get_User_Text -- get the user-text buffer *
  44. * MeshGeometryClass::Set_User_Text -- set the user text buffer *
  45. * MeshGeometryClass::Get_Bounding_Box -- get the bounding box *
  46. * MeshGeometryClass::Get_Bounding_Sphere -- get the bounding sphere *
  47. * MeshGeometryClass::Generate_Rigid_APT -- generate active polygon table *
  48. * MeshGeometryClass::Generate_Skin_APT -- generate an active polygon table *
  49. * MeshGeometryClass::Contains -- test if the mesh contains the given point *
  50. * MeshGeometryClass::Cast_Ray -- compute a ray intersection with this mesh *
  51. * MeshGeometryClass::Cast_AABox -- cast an AABox against this mesh *
  52. * MeshGeometryClass::Cast_OBBox -- Cast an obbox against this mesh *
  53. * MeshGeometryClass::Intersect_OBBox -- test for intersection with the given OBBox *
  54. * MeshGeometryClass::Cast_World_Space_AABox -- test for intersection with a worldspace AABox*
  55. * MeshGeometryClass::cast_semi_infinite_axis_aligned_ray -- casts an axis aligned ray *
  56. * MeshGeometryClass::cast_aabox_identity -- aligned aabox test *
  57. * MeshGeometryClass::cast_aabox_z90 -- aabox test which is rotated about z by 90 *
  58. * MeshGeometryClass::cast_aabox_z180 -- aabox test which is rotated about z by 180 *
  59. * MeshGeometryClass::cast_aabox_z270 -- aabox test which is rotated about z by 270 *
  60. * MeshGeometryClass::cast_ray_brute_force -- brute force ray-cast *
  61. * MeshGeometryClass::cast_aabox_brute_force -- brute force aabox cast *
  62. * MeshGeometryClass::cast_obbox_brute_force -- brute force obbox cast *
  63. * MeshGeometryClass::intersect_obbox_brute_force -- brute force intersection check *
  64. * MeshGeometryClass::Compute_Plane_Equations -- Recalculates the plane equations *
  65. * MeshGeometryClass::Compute_Vertex_Normals -- recompute the vertex normals *
  66. * MeshGeometryClass::Compute_Bounds -- recomputes the bounding volumes *
  67. * MeshGeometryClass::get_vert_normals -- get the vertex normal array *
  68. * MeshGeometryClass::Get_Vertex_Normal_Array -- validates and returns the vertex normal arr *
  69. * MeshGeometryClass::get_planes -- get the plane array memory (internal) *
  70. * MeshGeometryClass::Get_Plane_Array -- validates and returns the array of plane equations *
  71. * MeshGeometryClass::Compute_Plane -- compute the plane equation of a single poly *
  72. * MeshGeometryClass::Generate_Culling_Tree -- Generate an AABTree for this mesh *
  73. * MeshGeometryClass::Load_W3D -- Load a mesh from a w3d *
  74. * MeshGeometryClass::read_chunks -- read w3d chunks *
  75. * MeshGeometryClass::read_vertices -- read the vertex chunk from a W3D file *
  76. * MeshGeometryClass::read_vertex_normals -- read the vertex normals chunk from a w3d file *
  77. * MeshGeometryClass::read_triangles -- read the triangles chunk from a w3d file *
  78. * MeshGeometryClass::read_user_text -- read the user text chunk from a w3d file *
  79. * MeshGeometryClass::read_vertex_influences -- read the vertex influences chunk from a w3d *
  80. * MeshGeometryClass::read_vertex_shade_indices -- read the vertex shade indices chunk *
  81. * MeshGeometryClass::read_aabtree -- read the AABTree chunk from a w3d file *
  82. * MeshGeometryClass::Generate_APT -- generate an apt for a box and view direction *
  83. * MeshGeometryClass::Generate_Rigid_APT -- generate an apt using backface culling *
  84. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  85. #include "meshgeometry.h"
  86. #include "aabtree.h"
  87. #include "chunkio.h"
  88. #include "aabox.h"
  89. #include "obbox.h"
  90. #include "sphere.h"
  91. #include "plane.h"
  92. #include "wwdebug.h"
  93. #include "wwmemlog.h"
  94. #include "w3d_file.h"
  95. #include "vp.h"
  96. #include "htree.h"
  97. #include "matrix4.h"
  98. #include "rinfo.h"
  99. #include "camera.h"
  100. #if (OPTIMIZE_PLANEEQ_RAM)
  101. static SimpleVecClass<Vector4> _PlaneEQArray(1024);
  102. #endif
  103. #if (OPTIMIZE_VNORM_RAM)
  104. static SimpleVecClass<Vector3> _VNormArray(1024);
  105. #endif
  106. /***********************************************************************************************
  107. * MeshGeometryClass::MeshGeometryClass -- Constructor *
  108. * *
  109. * INPUT: *
  110. * *
  111. * OUTPUT: *
  112. * *
  113. * WARNINGS: *
  114. * *
  115. * HISTORY: *
  116. * 11/9/2000 gth : Created. *
  117. *=============================================================================================*/
  118. MeshGeometryClass::MeshGeometryClass(void) :
  119. MeshName(NULL),
  120. UserText(NULL),
  121. Flags(0),
  122. SortLevel(SORT_LEVEL_NONE),
  123. W3dAttributes(0),
  124. PolyCount(0),
  125. VertexCount(0),
  126. Poly(NULL),
  127. PolySurfaceType(NULL),
  128. Vertex(NULL),
  129. VertexNorm(NULL),
  130. PlaneEq(NULL),
  131. VertexShadeIdx(NULL),
  132. VertexBoneLink(NULL),
  133. BoundBoxMin(0,0,0),
  134. BoundBoxMax(1,1,1),
  135. BoundSphereCenter(0,0,0),
  136. BoundSphereRadius(1),
  137. CullTree(NULL)
  138. {
  139. }
  140. /***********************************************************************************************
  141. * MeshGeometryClass::MeshGeometryClass -- Copy Constructor *
  142. * *
  143. * INPUT: *
  144. * *
  145. * OUTPUT: *
  146. * *
  147. * WARNINGS: *
  148. * *
  149. * HISTORY: *
  150. * 11/9/2000 gth : Created. *
  151. *=============================================================================================*/
  152. MeshGeometryClass::MeshGeometryClass(const MeshGeometryClass & that) :
  153. MeshName(NULL),
  154. UserText(NULL),
  155. Flags(0),
  156. SortLevel(SORT_LEVEL_NONE),
  157. W3dAttributes(0),
  158. PolyCount(0),
  159. VertexCount(0),
  160. Poly(NULL),
  161. PolySurfaceType(NULL),
  162. Vertex(NULL),
  163. VertexNorm(NULL),
  164. PlaneEq(NULL),
  165. VertexShadeIdx(NULL),
  166. VertexBoneLink(NULL),
  167. BoundBoxMin(0,0,0),
  168. BoundBoxMax(1,1,1),
  169. BoundSphereCenter(0,0,0),
  170. BoundSphereRadius(1),
  171. CullTree(NULL)
  172. {
  173. *this = that;
  174. }
  175. /***********************************************************************************************
  176. * -- assignment operator *
  177. * *
  178. * INPUT: *
  179. * *
  180. * OUTPUT: *
  181. * *
  182. * WARNINGS: *
  183. * *
  184. * HISTORY: *
  185. * 11/9/2000 gth : Created. *
  186. *=============================================================================================*/
  187. MeshGeometryClass & MeshGeometryClass::operator = (const MeshGeometryClass & that)
  188. {
  189. if (this != &that) {
  190. Flags = that.Flags;
  191. SortLevel = that.SortLevel;
  192. W3dAttributes = that.W3dAttributes;
  193. PolyCount = that.PolyCount;
  194. VertexCount = that.VertexCount;
  195. BoundBoxMin = that.BoundBoxMin;
  196. BoundBoxMax = that.BoundBoxMax;
  197. BoundSphereCenter = that.BoundSphereCenter;
  198. BoundSphereRadius = that.BoundSphereRadius;
  199. REF_PTR_SET(MeshName,that.MeshName);
  200. REF_PTR_SET(UserText,that.UserText);
  201. REF_PTR_SET(Poly,that.Poly);
  202. REF_PTR_SET(PolySurfaceType,that.PolySurfaceType);
  203. REF_PTR_SET(Vertex,that.Vertex);
  204. REF_PTR_SET(VertexNorm,that.VertexNorm);
  205. REF_PTR_SET(PlaneEq,that.PlaneEq);
  206. REF_PTR_SET(VertexShadeIdx,that.VertexShadeIdx);
  207. REF_PTR_SET(VertexBoneLink,that.VertexBoneLink);
  208. // Clone the cull tree..
  209. REF_PTR_RELEASE(CullTree);
  210. if (that.CullTree) {
  211. CullTree = NEW_REF(AABTreeClass, ());
  212. *CullTree = *that.CullTree;
  213. CullTree->Set_Mesh(this);
  214. }
  215. }
  216. return * this;
  217. }
  218. /***********************************************************************************************
  219. * MeshGeometryClass::~MeshGeometryClass -- destructor *
  220. * *
  221. * INPUT: *
  222. * *
  223. * OUTPUT: *
  224. * *
  225. * WARNINGS: *
  226. * *
  227. * HISTORY: *
  228. * 11/9/2000 gth : Created. *
  229. *=============================================================================================*/
  230. MeshGeometryClass::~MeshGeometryClass(void)
  231. {
  232. Reset_Geometry(0,0);
  233. }
  234. /***********************************************************************************************
  235. * MeshGeometryClass::Reset_Geometry -- releases current resources and allocates space if need *
  236. * *
  237. * INPUT: *
  238. * *
  239. * OUTPUT: *
  240. * *
  241. * WARNINGS: *
  242. * *
  243. * HISTORY: *
  244. * 11/9/2000 gth : Created. *
  245. *=============================================================================================*/
  246. void MeshGeometryClass::Reset_Geometry(int polycount,int vertcount)
  247. {
  248. // Release everything we have and reset to initial state
  249. Flags = 0;
  250. PolyCount = 0;
  251. VertexCount = 0;
  252. SortLevel = SORT_LEVEL_NONE;
  253. REF_PTR_RELEASE(MeshName);
  254. REF_PTR_RELEASE(UserText);
  255. REF_PTR_RELEASE(Poly);
  256. REF_PTR_RELEASE(PolySurfaceType);
  257. REF_PTR_RELEASE(Vertex);
  258. REF_PTR_RELEASE(VertexNorm);
  259. REF_PTR_RELEASE(PlaneEq);
  260. REF_PTR_RELEASE(VertexShadeIdx);
  261. REF_PTR_RELEASE(VertexBoneLink);
  262. REF_PTR_RELEASE(CullTree);
  263. PolyCount = polycount;
  264. VertexCount = vertcount;
  265. // allocate new geometry arrays
  266. if ((polycount != 0) && (vertcount != 0)) {
  267. Poly = NEW_REF(ShareBufferClass<TriIndex>,(PolyCount, "MeshGeometryClass::Poly"));
  268. PolySurfaceType = NEW_REF(ShareBufferClass<uint8>,(PolyCount, "MeshGeometryClass::PolySurfaceType"));
  269. Vertex = NEW_REF(ShareBufferClass<Vector3>,(VertexCount, "MeshGeometryClass::Vertex"));
  270. Poly->Clear();
  271. PolySurfaceType->Clear();
  272. Vertex->Clear();
  273. #if (!OPTIMIZE_VNORM_RAM)
  274. VertexNorm = NEW_REF(ShareBufferClass<Vector3>,(VertexCount, "MeshGeometryClass::VertexNorm"));
  275. VertexNorm->Clear();
  276. #endif
  277. }
  278. return ;
  279. }
  280. /***********************************************************************************************
  281. * MeshGeometryClass::Get_Name -- returns the name *
  282. * *
  283. * INPUT: *
  284. * *
  285. * OUTPUT: *
  286. * *
  287. * WARNINGS: *
  288. * *
  289. * HISTORY: *
  290. * 11/9/2000 gth : Created. *
  291. *=============================================================================================*/
  292. const char * MeshGeometryClass::Get_Name(void) const
  293. {
  294. if (MeshName) {
  295. return MeshName->Get_Array();
  296. }
  297. return NULL;
  298. }
  299. /***********************************************************************************************
  300. * MeshGeometryClass::Set_Name -- set the name of this model *
  301. * *
  302. * INPUT: *
  303. * *
  304. * OUTPUT: *
  305. * *
  306. * WARNINGS: *
  307. * *
  308. * HISTORY: *
  309. * 11/9/2000 gth : Created. *
  310. *=============================================================================================*/
  311. void MeshGeometryClass::Set_Name(const char * newname)
  312. {
  313. if (MeshName) {
  314. MeshName->Release_Ref();
  315. }
  316. if (newname) {
  317. MeshName = NEW_REF(ShareBufferClass<char>,(strlen(newname)+1, "MeshGeometryClass::MeshName"));
  318. strcpy(MeshName->Get_Array(),newname);
  319. }
  320. }
  321. /***********************************************************************************************
  322. * MeshGeometryClass::Get_User_Text -- get the user-text buffer *
  323. * *
  324. * INPUT: *
  325. * *
  326. * OUTPUT: *
  327. * *
  328. * WARNINGS: *
  329. * *
  330. * HISTORY: *
  331. * 11/9/2000 gth : Created. *
  332. *=============================================================================================*/
  333. const char * MeshGeometryClass::Get_User_Text(void)
  334. {
  335. if (UserText) {
  336. return UserText->Get_Array();
  337. }
  338. return NULL;
  339. }
  340. /***********************************************************************************************
  341. * MeshGeometryClass::Set_User_Text -- set the user text buffer *
  342. * *
  343. * INPUT: *
  344. * *
  345. * OUTPUT: *
  346. * *
  347. * WARNINGS: *
  348. * *
  349. * HISTORY: *
  350. * 11/9/2000 gth : Created. *
  351. *=============================================================================================*/
  352. void MeshGeometryClass::Set_User_Text(char * usertext)
  353. {
  354. if (UserText) {
  355. UserText->Release_Ref();
  356. }
  357. if (usertext) {
  358. UserText = NEW_REF(ShareBufferClass<char>,(strlen(usertext)+1, "MeshGeometryClass::UserText"));
  359. strcpy(UserText->Get_Array(),usertext);
  360. }
  361. }
  362. /***********************************************************************************************
  363. * MeshGeometryClass::Get_Bounding_Box -- get the bounding box *
  364. * *
  365. * INPUT: *
  366. * *
  367. * OUTPUT: *
  368. * *
  369. * WARNINGS: *
  370. * *
  371. * HISTORY: *
  372. * 11/9/2000 gth : Created. *
  373. *=============================================================================================*/
  374. void MeshGeometryClass::Get_Bounding_Box(AABoxClass * set_box)
  375. {
  376. WWASSERT(set_box != NULL);
  377. set_box->Center = (BoundBoxMax + BoundBoxMin) * 0.5f;
  378. set_box->Extent = (BoundBoxMax - BoundBoxMin) * 0.5f;
  379. }
  380. /***********************************************************************************************
  381. * MeshGeometryClass::Get_Bounding_Sphere -- get the bounding sphere *
  382. * *
  383. * INPUT: *
  384. * *
  385. * OUTPUT: *
  386. * *
  387. * WARNINGS: *
  388. * *
  389. * HISTORY: *
  390. * 11/9/2000 gth : Created. *
  391. *=============================================================================================*/
  392. void MeshGeometryClass::Get_Bounding_Sphere(SphereClass * set_sphere)
  393. {
  394. WWASSERT(set_sphere != NULL);
  395. set_sphere->Center = BoundSphereCenter;
  396. set_sphere->Radius = BoundSphereRadius;
  397. }
  398. /***********************************************************************************************
  399. * MeshGeometryClass::Generate_Rigid_APT -- generate an apt using backface culling *
  400. * *
  401. * INPUT: *
  402. * *
  403. * OUTPUT: *
  404. * *
  405. * WARNINGS: *
  406. * *
  407. * HISTORY: *
  408. * 5/10/2001 gth : Created. *
  409. *=============================================================================================*/
  410. void MeshGeometryClass::Generate_Rigid_APT(const Vector3 & view_dir, SimpleDynVecClass<uint32> & apt)
  411. {
  412. const Vector3 * loc = Get_Vertex_Array();
  413. const Vector4 * norms = Get_Plane_Array();
  414. const TriIndex * polys = Get_Polygon_Array();
  415. TriClass tri;
  416. for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
  417. tri.V[0] = &(loc[ polys[poly_counter][0] ]);
  418. tri.V[1] = &(loc[ polys[poly_counter][1] ]);
  419. tri.V[2] = &(loc[ polys[poly_counter][2] ]);
  420. tri.N = (Vector3*)&(norms[poly_counter]);
  421. if (Vector3::Dot_Product(*tri.N,view_dir) < 0.0f) {
  422. apt.Add(poly_counter);
  423. }
  424. }
  425. }
  426. /***********************************************************************************************
  427. * MeshGeometryClass::Generate_Rigid_APT -- generate active polygon table *
  428. * *
  429. * This function will cull the mesh against the specified volume *
  430. * *
  431. * INPUT: *
  432. * *
  433. * OUTPUT: *
  434. * *
  435. * WARNINGS: *
  436. * *
  437. * HISTORY: *
  438. * 11/9/2000 gth : Created. *
  439. *=============================================================================================*/
  440. void MeshGeometryClass::Generate_Rigid_APT(const OBBoxClass & local_box, SimpleDynVecClass<uint32> & apt)
  441. {
  442. if (CullTree != NULL) {
  443. CullTree->Generate_APT(local_box, apt);
  444. } else {
  445. // Beware, this is gonna be expensive!
  446. const Vector3 * loc = Get_Vertex_Array();
  447. const Vector4 * norms = Get_Plane_Array();
  448. const TriIndex * polys = Get_Polygon_Array();
  449. TriClass tri;
  450. for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
  451. tri.V[0] = &(loc[ polys[poly_counter][0] ]);
  452. tri.V[1] = &(loc[ polys[poly_counter][1] ]);
  453. tri.V[2] = &(loc[ polys[poly_counter][2] ]);
  454. tri.N = (Vector3*)&(norms[poly_counter]);
  455. if (CollisionMath::Intersection_Test(local_box, tri)) {;
  456. apt.Add(poly_counter);
  457. }
  458. }
  459. }
  460. }
  461. /***********************************************************************************************
  462. * MeshGeometryClass::Generate_APT -- generate an apt for a box and view direction *
  463. * *
  464. * INPUT: *
  465. * *
  466. * OUTPUT: *
  467. * *
  468. * WARNINGS: *
  469. * *
  470. * HISTORY: *
  471. * 5/10/2001 gth : Created. *
  472. *=============================================================================================*/
  473. void MeshGeometryClass::Generate_Rigid_APT(const OBBoxClass & local_box,const Vector3 & viewdir,SimpleDynVecClass<uint32> & apt)
  474. {
  475. if (CullTree != NULL) {
  476. CullTree->Generate_APT(local_box, viewdir,apt);
  477. } else {
  478. // Beware, this is gonna be expensive!
  479. const Vector3 * loc = Get_Vertex_Array();
  480. const Vector4 * norms = Get_Plane_Array();
  481. const TriIndex * polys = Get_Polygon_Array();
  482. TriClass tri;
  483. for (int poly_counter = 0; poly_counter < PolyCount; poly_counter++) {
  484. tri.V[0] = &(loc[ polys[poly_counter][0] ]);
  485. tri.V[1] = &(loc[ polys[poly_counter][1] ]);
  486. tri.V[2] = &(loc[ polys[poly_counter][2] ]);
  487. tri.N = (Vector3*)&(norms[poly_counter]);
  488. if (Vector3::Dot_Product(*tri.N,viewdir) < 0.0f) {
  489. if (CollisionMath::Intersection_Test(local_box,tri)) {
  490. apt.Add(poly_counter);
  491. }
  492. }
  493. }
  494. }
  495. }
  496. /***********************************************************************************************
  497. * MeshGeometryClass::Generate_Skin_APT -- generate an active polygon table *
  498. * *
  499. * This function culls the mesh against the specified volume *
  500. * *
  501. * INPUT: *
  502. * *
  503. * OUTPUT: *
  504. * *
  505. * WARNINGS: *
  506. * *
  507. * HISTORY: *
  508. * 11/9/2000 gth : Created. *
  509. *=============================================================================================*/
  510. void MeshGeometryClass::Generate_Skin_APT(const OBBoxClass & world_box, SimpleDynVecClass<uint32> & apt, const Vector3 *world_vertex_locs)
  511. {
  512. WWASSERT(world_vertex_locs);
  513. // Beware, this is gonna be expensive!
  514. const TriIndex * polys = Get_Polygon_Array();
  515. TriClass tri;
  516. for (int poly_counter=0; poly_counter < PolyCount; poly_counter++) {
  517. tri.V[0] = &(world_vertex_locs[ polys[poly_counter][0] ]);
  518. tri.V[1] = &(world_vertex_locs[ polys[poly_counter][1] ]);
  519. tri.V[2] = &(world_vertex_locs[ polys[poly_counter][2] ]);
  520. // We would have to do a non-trivial amount of computation to get the triangle normal
  521. // (since this is a skin we have no valid plane equations) and we know that N is not used
  522. // in the Intersection_Test, so we set it to a dummy value.
  523. static const Vector3 dummy_vec(0.0f, 0.0f, 1.0f);
  524. tri.N = &dummy_vec;
  525. if (CollisionMath::Intersection_Test(world_box,tri)) {;
  526. apt.Add(poly_counter);
  527. }
  528. }
  529. }
  530. /***********************************************************************************************
  531. * MeshGeometryClass::Contains -- test if the mesh contains the given point *
  532. * *
  533. * INPUT: *
  534. * *
  535. * OUTPUT: *
  536. * *
  537. * WARNINGS: *
  538. * *
  539. * HISTORY: *
  540. * 11/9/2000 gth : Created. *
  541. *=============================================================================================*/
  542. bool MeshGeometryClass::Contains(const Vector3 &point)
  543. {
  544. // To determine whether the mesh contains a point, we will use the parity method (cast a
  545. // semi-infinite ray from the point and check the number of intersections with the mesh.
  546. // An even number of intersections means the point is outside the mesh, and an odd number
  547. // means the point is inside the mesh. Since we can cast the ray in any direction we will
  548. // use axis-aligned rays for speed.
  549. // The method fails if the ray goes through any triangle edge or corner. For robustness
  550. // we will cast rays in all six axis-aligned directions, and take a majority vote. We will
  551. // significantly reduce the weighting of rays which go through corners/edges.
  552. // Also, if any raycast reports that the point is embedded in a triangle, we will stop and
  553. // report that the point is contained in the mesh (using the normal algorithm in this case
  554. // could lead to errors).
  555. float yes = 0.0f; // weighted sum of rays indicating the point is contained in the mesh
  556. float no = 0.0f; // weighted sum of rays indicating the point is not contained in the mesh
  557. for (int axis_dir = 0; axis_dir < 6; axis_dir++) {
  558. unsigned char flags = TRI_RAYCAST_FLAG_NONE;
  559. int intersections = cast_semi_infinite_axis_aligned_ray(point, axis_dir, flags);
  560. if (flags & TRI_RAYCAST_FLAG_START_IN_TRI) return true;
  561. float weight = flags & TRI_RAYCAST_FLAG_HIT_EDGE ? 0.1f : 1.0f;
  562. if (intersections & 0x01) {
  563. yes += weight;
  564. } else {
  565. no += weight;
  566. }
  567. }
  568. return yes > no;
  569. }
  570. /***********************************************************************************************
  571. * MeshGeometryClass::Cast_Ray -- compute a ray intersection with this mesh *
  572. * *
  573. * INPUT: *
  574. * *
  575. * OUTPUT: *
  576. * *
  577. * WARNINGS: *
  578. * *
  579. * HISTORY: *
  580. * 3/1/2001 NH : Created. *
  581. *=============================================================================================*/
  582. bool MeshGeometryClass::Cast_Ray(RayCollisionTestClass & raytest)
  583. {
  584. bool hit = false;
  585. if (CullTree) {
  586. hit = CullTree->Cast_Ray(raytest);
  587. } else {
  588. hit = cast_ray_brute_force(raytest);
  589. }
  590. return hit;
  591. }
  592. /***********************************************************************************************
  593. * MeshGeometryClass::Cast_AABox -- cast an AABox against this mesh *
  594. * *
  595. * INPUT: *
  596. * *
  597. * OUTPUT: *
  598. * *
  599. * WARNINGS: *
  600. * *
  601. * HISTORY: *
  602. * 3/1/2001 NH : Created. *
  603. *=============================================================================================*/
  604. bool MeshGeometryClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
  605. {
  606. bool hit = false;
  607. if (CullTree) {
  608. hit = CullTree->Cast_AABox(boxtest);
  609. } else {
  610. hit = cast_aabox_brute_force(boxtest);
  611. }
  612. return hit;
  613. }
  614. /***********************************************************************************************
  615. * MeshGeometryClass::Cast_OBBox -- Cast an obbox against this mesh *
  616. * *
  617. * INPUT: *
  618. * *
  619. * OUTPUT: *
  620. * *
  621. * WARNINGS: *
  622. * *
  623. * HISTORY: *
  624. * 3/1/2001 NH : Created. *
  625. *=============================================================================================*/
  626. bool MeshGeometryClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
  627. {
  628. bool hit = false;
  629. if (CullTree) {
  630. hit = CullTree->Cast_OBBox(boxtest);
  631. } else {
  632. hit = cast_obbox_brute_force(boxtest);
  633. }
  634. return hit;
  635. }
  636. /***********************************************************************************************
  637. * MeshGeometryClass::Intersect_OBBox -- test for intersection with the given OBBox *
  638. * *
  639. * INPUT: *
  640. * *
  641. * OUTPUT: *
  642. * *
  643. * WARNINGS: *
  644. * *
  645. * HISTORY: *
  646. * 3/1/2001 NH : Created. *
  647. *=============================================================================================*/
  648. bool MeshGeometryClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
  649. {
  650. bool hit = false;
  651. if (CullTree) {
  652. hit = CullTree->Intersect_OBBox(boxtest);
  653. } else {
  654. hit = intersect_obbox_brute_force(boxtest);
  655. }
  656. return hit;
  657. }
  658. /***********************************************************************************************
  659. * MeshGeometryClass::Cast_World_Space_AABox -- test for intersection with a worldspace AABox*
  660. * *
  661. * INPUT: *
  662. * *
  663. * OUTPUT: *
  664. * *
  665. * WARNINGS: *
  666. * *
  667. * HISTORY: *
  668. * 3/1/2001 NH : Created. *
  669. *=============================================================================================*/
  670. bool MeshGeometryClass::Cast_World_Space_AABox(AABoxCollisionTestClass & boxtest, const Matrix3D &transform)
  671. {
  672. /*
  673. ** Attempt to classify the transform:
  674. ** NOTE: This code assumes that the matrix is orthogonal! Much code in W3D assumes
  675. ** orthogonal matrices, if that convention is broken this code is also broken.
  676. ** Basically what I'm doing here is doing the minimum number of compares needed
  677. ** to identify a transform which is a 90 degree rotation about the z axis.
  678. ** TODO: cache some transform flags somewhere to reduce the number of times
  679. ** that these compares are done
  680. */
  681. bool hit = false;
  682. if ((transform[0][0] == 1.0f) && (transform[1][1] == 1.0f)) {
  683. hit = cast_aabox_identity(boxtest,-transform.Get_Translation());
  684. } else if ((transform[0][1] == -1.0f) && (transform[1][0] == 1.0f)) {
  685. // this mesh has been rotated 90 degrees about z
  686. hit = cast_aabox_z90(boxtest,-transform.Get_Translation());
  687. } else if ((transform[0][0] == -1.0f) && (transform[1][1] == -1.0f)) {
  688. // this mesh has been rotated 180
  689. hit = cast_aabox_z180(boxtest,-transform.Get_Translation());
  690. } else if ((transform[0][1] == 1.0f) && (transform[1][0] == -1.0f)) {
  691. // this mesh has been rotated 270
  692. hit = cast_aabox_z270(boxtest,-transform.Get_Translation());
  693. } else {
  694. /*
  695. ** Ok, we fell through to here, that means there is a more general
  696. ** transform on this mesh. In this case, I create a new test which
  697. ** is an oriented box test in the coordinate system of the mesh and cast it.
  698. */
  699. Matrix3D world_to_obj;
  700. transform.Get_Orthogonal_Inverse(world_to_obj);
  701. OBBoxCollisionTestClass obbox(boxtest, world_to_obj);
  702. if (CullTree) {
  703. hit = CullTree->Cast_OBBox(obbox);
  704. } else {
  705. hit = cast_obbox_brute_force(obbox);
  706. }
  707. /*
  708. ** now, we must transform the results of the test back to the original
  709. ** coordinate system.
  710. */
  711. if (hit) {
  712. Matrix3D::Rotate_Vector(transform, obbox.Result->Normal, &(obbox.Result->Normal));
  713. if (boxtest.Result->ComputeContactPoint) {
  714. Matrix3D::Transform_Vector(transform, obbox.Result->ContactPoint, &(obbox.Result->ContactPoint));
  715. }
  716. }
  717. }
  718. return hit;
  719. }
  720. /***********************************************************************************************
  721. * MeshGeometryClass::cast_semi_infinite_axis_aligned_ray -- casts an axis aligned ray *
  722. * *
  723. * This function is used by the 'Contains' function *
  724. * *
  725. * INPUT: *
  726. * *
  727. * OUTPUT: *
  728. * *
  729. * WARNINGS: *
  730. * *
  731. * HISTORY: *
  732. * 11/9/2000 gth : Created. *
  733. *=============================================================================================*/
  734. int MeshGeometryClass::cast_semi_infinite_axis_aligned_ray(const Vector3 & start_point, int axis_dir,
  735. unsigned char & flags)
  736. {
  737. int count = 0;
  738. if (CullTree) {
  739. count = CullTree->Cast_Semi_Infinite_Axis_Aligned_Ray(start_point, axis_dir, flags);
  740. } else {
  741. const Vector3 * loc = Get_Vertex_Array();
  742. const Vector4 * plane = Get_Plane_Array();
  743. const TriIndex * polyverts = Get_Polygon_Array();
  744. // These tables translate between the axis_dir representation (which is an integer in which 0
  745. // indicates a ray along the positive x axis, 1 along the negative x axis, 2 the positive y
  746. // axis, 3 negative y axis, 4 positive z axis, 5 negative z axis) and a four-integer
  747. // representation (axis_r is the axis number - 0, 1 or 2 - of the axis along which the ray is
  748. // cast; axis_1 and axis_2 are the axis numbers of the other two axes; direction is 0 for
  749. // negative and 1 for positive direction of the ray).
  750. static const int axis_r[6] = { 0, 0, 1, 1, 2, 2 };
  751. static const int axis_1[6] = { 1, 1, 2, 2, 0, 0 };
  752. static const int axis_2[6] = { 2, 2, 0, 0, 1, 1 };
  753. static const int direction[6] = { 1, 0, 1, 0, 1, 0 };
  754. WWASSERT(axis_dir >= 0);
  755. WWASSERT(axis_dir < 6);
  756. // The functions called after this point will 'or' bits into this variable, so it needs to
  757. // be initialized here to TRI_RAYCAST_FLAG_NONE.
  758. flags = TRI_RAYCAST_FLAG_NONE;
  759. /*
  760. ** Loop over each polygon
  761. */
  762. int poly_count = Get_Polygon_Count();
  763. for (int poly_counter=0; poly_counter < poly_count; poly_counter++) {
  764. const Vector3 &v0 = loc[ polyverts[poly_counter][0] ];
  765. const Vector3 &v1 = loc[ polyverts[poly_counter][1] ];
  766. const Vector3 &v2 = loc[ polyverts[poly_counter][2] ];
  767. const Vector4 &tri_plane = plane[poly_counter];
  768. // Since (int)true is defined as 1, and (int)false as 0:
  769. count += (unsigned int)Cast_Semi_Infinite_Axis_Aligned_Ray_To_Triangle(v0, v1, v2,
  770. tri_plane, start_point, axis_r[axis_dir], axis_1[axis_dir], axis_2[axis_dir],
  771. direction[axis_dir], flags);
  772. }
  773. }
  774. return count;
  775. }
  776. /***********************************************************************************************
  777. * MeshGeometryClass::cast_aabox_identity -- aligned aabox test *
  778. * *
  779. * INPUT: *
  780. * *
  781. * OUTPUT: *
  782. * *
  783. * WARNINGS: *
  784. * *
  785. * HISTORY: *
  786. * 3/1/2001 NH : Created. *
  787. *=============================================================================================*/
  788. bool MeshGeometryClass::cast_aabox_identity(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
  789. {
  790. // transform the test into the mesh's coordinate system
  791. AABoxCollisionTestClass newbox(boxtest);
  792. newbox.Translate(translation);
  793. // cast the box against the mesh
  794. if (CullTree) {
  795. return CullTree->Cast_AABox(newbox);
  796. } else {
  797. return cast_aabox_brute_force(newbox);
  798. }
  799. }
  800. /***********************************************************************************************
  801. * MeshGeometryClass::cast_aabox_z90 -- aabox test which is rotated about z by 90 *
  802. * *
  803. * INPUT: *
  804. * *
  805. * OUTPUT: *
  806. * *
  807. * WARNINGS: *
  808. * *
  809. * HISTORY: *
  810. * 3/1/2001 NH : Created. *
  811. *=============================================================================================*/
  812. bool MeshGeometryClass::cast_aabox_z90(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
  813. {
  814. // transform the test into the mesh's coordinate system
  815. AABoxCollisionTestClass newbox(boxtest);
  816. newbox.Translate(translation);
  817. newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z270);
  818. // cast the box against the mesh, using culling if possible
  819. bool hit;
  820. if (CullTree) {
  821. hit = CullTree->Cast_AABox(newbox);
  822. } else {
  823. hit = cast_aabox_brute_force(newbox);
  824. }
  825. // if we hit something, we need to rotate the normal back out of the mesh coordinate system
  826. if (hit) {
  827. // rotating the normal by 90 degrees about Z
  828. float tmp = boxtest.Result->Normal.X;
  829. boxtest.Result->Normal.X = -boxtest.Result->Normal.Y;
  830. boxtest.Result->Normal.Y = tmp;
  831. }
  832. return hit;
  833. }
  834. /***********************************************************************************************
  835. * MeshGeometryClass::cast_aabox_z180 -- aabox test which is rotated about z by 180 *
  836. * *
  837. * INPUT: *
  838. * *
  839. * OUTPUT: *
  840. * *
  841. * WARNINGS: *
  842. * *
  843. * HISTORY: *
  844. * 3/1/2001 NH : Created. *
  845. *=============================================================================================*/
  846. bool MeshGeometryClass::cast_aabox_z180(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
  847. {
  848. // transform the test into the meshes coordinate system
  849. AABoxCollisionTestClass newbox(boxtest);
  850. newbox.Translate(translation);
  851. newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z180);
  852. // cast the box against the mesh, using culling if possible
  853. bool hit;
  854. if (CullTree) {
  855. hit = CullTree->Cast_AABox(newbox);
  856. } else {
  857. hit = cast_aabox_brute_force(newbox);
  858. }
  859. // if we hit something, we need to rotate the normal back out of the mesh coordinate system
  860. if (hit) {
  861. // rotating the normal by 180 degrees about Z
  862. boxtest.Result->Normal.X = -boxtest.Result->Normal.X;
  863. boxtest.Result->Normal.Y = -boxtest.Result->Normal.Y;
  864. }
  865. return hit;
  866. }
  867. /***********************************************************************************************
  868. * MeshGeometryClass::cast_aabox_z270 -- aabox test which is rotated about z by 270 *
  869. * *
  870. * INPUT: *
  871. * *
  872. * OUTPUT: *
  873. * *
  874. * WARNINGS: *
  875. * *
  876. * HISTORY: *
  877. * 3/1/2001 NH : Created. *
  878. *=============================================================================================*/
  879. bool MeshGeometryClass::cast_aabox_z270(AABoxCollisionTestClass & boxtest, const Vector3 & translation)
  880. {
  881. // transform the test into the mesh's coordinate system
  882. AABoxCollisionTestClass newbox(boxtest);
  883. newbox.Translate(translation);
  884. newbox.Rotate(AABoxCollisionTestClass::ROTATE_Z90);
  885. // cast the box against the mesh, using culling if possible
  886. bool hit;
  887. if (CullTree) {
  888. hit = CullTree->Cast_AABox(newbox);
  889. } else {
  890. hit = cast_aabox_brute_force(newbox);
  891. }
  892. // if we hit something, we need to rotate the normal back out of the mesh coordinate system
  893. if (hit) {
  894. // rotating the normal by 270 degrees about Z
  895. float tmp = boxtest.Result->Normal.X;
  896. boxtest.Result->Normal.X = boxtest.Result->Normal.Y;
  897. boxtest.Result->Normal.Y = -tmp;
  898. }
  899. return hit;
  900. }
  901. /***********************************************************************************************
  902. * MeshGeometryClass::intersect_obbox_brute_force -- brute force intersection check *
  903. * *
  904. * This function gets used if the mesh does not have a CullTree *
  905. * *
  906. * INPUT: *
  907. * *
  908. * OUTPUT: *
  909. * *
  910. * WARNINGS: *
  911. * *
  912. * HISTORY: *
  913. * 3/1/2001 NH : Created. *
  914. *=============================================================================================*/
  915. bool MeshGeometryClass::intersect_obbox_brute_force(OBBoxIntersectionTestClass & localtest)
  916. {
  917. TriClass tri;
  918. const Vector3 * loc = Get_Vertex_Array();
  919. const TriIndex * polyverts = Get_Polygon_Array();
  920. #ifndef COMPUTE_NORMALS
  921. const Vector4 * norms = Get_Plane_Array();
  922. #endif
  923. /*
  924. ** Loop over each polygon
  925. */
  926. for (int srtri=0; srtri < Get_Polygon_Count(); srtri++) {
  927. tri.V[0] = &(loc[ polyverts[srtri][0] ]);
  928. tri.V[1] = &(loc[ polyverts[srtri][1] ]);
  929. tri.V[2] = &(loc[ polyverts[srtri][2] ]);
  930. #ifdef COMPUTE_NORMALS
  931. static Vector3 _normal;
  932. tri.N = &_normal;
  933. tri.Compute_Normal();
  934. #else
  935. tri.N = (Vector3 *)&(norms[srtri]);
  936. #endif
  937. if (CollisionMath::Intersection_Test(localtest.Box, tri)) {
  938. return true;
  939. }
  940. }
  941. return false;
  942. }
  943. /***********************************************************************************************
  944. * MeshGeometryClass::cast_ray_brute_force -- brute force ray-cast *
  945. * *
  946. * This function gets used if the mesh does not have a CullTree *
  947. * *
  948. * INPUT: *
  949. * *
  950. * OUTPUT: *
  951. * *
  952. * WARNINGS: *
  953. * *
  954. * HISTORY: *
  955. * 3/1/2001 NH : Created. *
  956. *=============================================================================================*/
  957. bool MeshGeometryClass::cast_ray_brute_force(RayCollisionTestClass & raytest)
  958. {
  959. int srtri;
  960. TriClass tri;
  961. const Vector3 * loc = Get_Vertex_Array();
  962. const TriIndex * polyverts = Get_Polygon_Array();
  963. #ifndef COMPUTE_NORMALS
  964. const Vector4 * norms = Get_Plane_Array();
  965. #endif
  966. /*
  967. ** Loop over each polygon
  968. */
  969. bool hit = false;
  970. for (srtri=0; srtri < Get_Polygon_Count(); srtri++) {
  971. // TODO: find a better way to do this?
  972. tri.V[0] = &(loc[ polyverts[srtri][0] ]);
  973. tri.V[1] = &(loc[ polyverts[srtri][1] ]);
  974. tri.V[2] = &(loc[ polyverts[srtri][2] ]);
  975. #ifdef COMPUTE_NORMALS
  976. static Vector3 _normal;
  977. tri.N = &_normal;
  978. tri.Compute_Normal();
  979. #else
  980. tri.N = (Vector3 *)&(norms[srtri]);
  981. #endif
  982. if (CollisionMath::Collide(raytest.Ray, tri, raytest.Result)) {
  983. hit = true;
  984. raytest.Result->SurfaceType = Get_Poly_Surface_Type (srtri);
  985. }
  986. if (raytest.Result->StartBad) return true;
  987. }
  988. return hit;
  989. }
  990. /***********************************************************************************************
  991. * MeshGeometryClass::cast_aabox_brute_force -- brute force aabox cast *
  992. * *
  993. * This function gets used only if the mesh doesn't have a CullTree *
  994. * *
  995. * INPUT: *
  996. * *
  997. * OUTPUT: *
  998. * *
  999. * WARNINGS: *
  1000. * *
  1001. * HISTORY: *
  1002. * 3/1/2001 NH : Created. *
  1003. *=============================================================================================*/
  1004. bool MeshGeometryClass::cast_aabox_brute_force(AABoxCollisionTestClass & boxtest)
  1005. {
  1006. /*
  1007. ** Loop over each polygon
  1008. */
  1009. TriClass tri;
  1010. int polyhit = -1;
  1011. const Vector3 * loc = Get_Vertex_Array();
  1012. const TriIndex * polyverts = Get_Polygon_Array();
  1013. #ifndef COMPUTE_NORMALS
  1014. const Vector4 * norms = Get_Plane_Array();
  1015. #endif
  1016. for (int srtri = 0; srtri < Get_Polygon_Count(); srtri++) {
  1017. tri.V[0] = &(loc[ polyverts[srtri][0] ]);
  1018. tri.V[1] = &(loc[ polyverts[srtri][1] ]);
  1019. tri.V[2] = &(loc[ polyverts[srtri][2] ]);
  1020. #ifdef COMPUTE_NORMALS
  1021. static Vector3 _normal;
  1022. tri.N = &_normal;
  1023. tri.Compute_Normal();
  1024. #else
  1025. tri.N = (Vector3 *)&(norms[srtri]);
  1026. #endif
  1027. if (CollisionMath::Collide(boxtest.Box, boxtest.Move, tri, boxtest.Result)) {
  1028. polyhit = srtri;
  1029. }
  1030. if (boxtest.Result->StartBad) {
  1031. return true;
  1032. }
  1033. }
  1034. if (polyhit != -1) {
  1035. boxtest.Result->SurfaceType = Get_Poly_Surface_Type(polyhit);
  1036. return true;
  1037. }
  1038. return false;
  1039. }
  1040. /***********************************************************************************************
  1041. * MeshGeometryClass::cast_obbox_brute_force -- brute force obbox cast *
  1042. * *
  1043. * This function gets used only if the mesh doesn't have a CullTree *
  1044. * *
  1045. * INPUT: *
  1046. * *
  1047. * OUTPUT: *
  1048. * *
  1049. * WARNINGS: *
  1050. * *
  1051. * HISTORY: *
  1052. * 3/1/2001 NH : Created. *
  1053. *=============================================================================================*/
  1054. bool MeshGeometryClass::cast_obbox_brute_force(OBBoxCollisionTestClass & boxtest)
  1055. {
  1056. /*
  1057. ** Loop over each polygon
  1058. */
  1059. TriClass tri;
  1060. int polyhit = -1;
  1061. const Vector3 * loc = Get_Vertex_Array();
  1062. const TriIndex * polyverts = Get_Polygon_Array();
  1063. #ifndef COMPUTE_NORMALS
  1064. const Vector4 * norms = Get_Plane_Array();
  1065. #endif
  1066. for (int srtri = 0; srtri < Get_Polygon_Count(); srtri++) {
  1067. tri.V[0] = &(loc[ polyverts[srtri][0] ]);
  1068. tri.V[1] = &(loc[ polyverts[srtri][1] ]);
  1069. tri.V[2] = &(loc[ polyverts[srtri][2] ]);
  1070. #ifdef COMPUTE_NORMALS
  1071. static Vector3 _normal;
  1072. tri.N = &_normal;
  1073. tri.Compute_Normal();
  1074. #else
  1075. tri.N = (Vector3 *)&(norms[srtri]);
  1076. #endif
  1077. if (CollisionMath::Collide(boxtest.Box, boxtest.Move, tri, Vector3(0,0,0), boxtest.Result)) {
  1078. polyhit = srtri;
  1079. }
  1080. if (boxtest.Result->StartBad) {
  1081. return true;
  1082. }
  1083. }
  1084. if (polyhit != -1) {
  1085. boxtest.Result->SurfaceType = Get_Poly_Surface_Type(polyhit);
  1086. return true;
  1087. }
  1088. return false;
  1089. }
  1090. /***********************************************************************************************
  1091. * MeshGeometryClass::Compute_Plane_Equations -- Recalculates the plane equations *
  1092. * *
  1093. * INPUT: *
  1094. * *
  1095. * OUTPUT: *
  1096. * *
  1097. * WARNINGS: *
  1098. * This function should not normally be needed during run-time. *
  1099. * The array pointer must point to enough memory to hold a plane equation per polygon *
  1100. * *
  1101. * HISTORY: *
  1102. * 11/9/2000 gth : Created. *
  1103. *=============================================================================================*/
  1104. void MeshGeometryClass::Compute_Plane_Equations(Vector4 * peq)
  1105. {
  1106. WWASSERT(peq!=NULL);
  1107. TriIndex * poly = Poly->Get_Array();
  1108. Vector3 * vert = Vertex->Get_Array();
  1109. for(int pidx = 0; pidx < PolyCount; pidx++)
  1110. {
  1111. Vector3 a,b,normal;
  1112. const Vector3 & p0= vert[poly[pidx][0]];
  1113. Vector3::Subtract(vert[poly[pidx][1]],p0,&a);
  1114. Vector3::Subtract(vert[poly[pidx][2]],p0,&b);
  1115. Vector3::Cross_Product(a,b,&normal);
  1116. normal.Normalize();
  1117. peq[pidx].Set( normal.X, normal.Y, normal.Z, -(Vector3::Dot_Product(p0,normal)) );
  1118. }
  1119. Set_Flag(DIRTY_PLANES,false);
  1120. }
  1121. /***********************************************************************************************
  1122. * MeshGeometryClass::Compute_Vertex_Normals -- recompute the vertex normals *
  1123. * *
  1124. * INPUT: *
  1125. * *
  1126. * OUTPUT: *
  1127. * *
  1128. * WARNINGS: *
  1129. * This function should not normally be needed during run-time. *
  1130. * The array pointer must point to an array of Vector3's of size NumVerts *
  1131. * *
  1132. * HISTORY: *
  1133. * 11/9/2000 gth : Created. *
  1134. *=============================================================================================*/
  1135. void MeshGeometryClass::Compute_Vertex_Normals(Vector3 * vnorm)
  1136. {
  1137. WWASSERT(vnorm != NULL);
  1138. if ((PolyCount == 0)|| (VertexCount == 0)) {
  1139. return;
  1140. }
  1141. const Vector4 * peq = Get_Plane_Array();
  1142. TriIndex * poly = Poly->Get_Array();
  1143. const uint32 * shadeIx = Get_Vertex_Shade_Index_Array(false);
  1144. // Two cases, with or without vertex shade indices. The vertex shade indices
  1145. // implicitly contain the smoothing groups information from the original mesh.
  1146. // In their abscesnce, the entire mesh is smoothed.
  1147. if (!shadeIx) {
  1148. VectorProcessorClass::Clear(vnorm, VertexCount);
  1149. for(int pidx = 0; pidx < PolyCount; pidx++) {
  1150. vnorm[poly[pidx].I].X += peq[pidx].X;
  1151. vnorm[poly[pidx].I].Y += peq[pidx].Y;
  1152. vnorm[poly[pidx].I].Z += peq[pidx].Z;
  1153. vnorm[poly[pidx].J].X += peq[pidx].X;
  1154. vnorm[poly[pidx].J].Y += peq[pidx].Y;
  1155. vnorm[poly[pidx].J].Z += peq[pidx].Z;
  1156. vnorm[poly[pidx].K].X += peq[pidx].X;
  1157. vnorm[poly[pidx].K].Y += peq[pidx].Y;
  1158. vnorm[poly[pidx].K].Z += peq[pidx].Z;
  1159. }
  1160. } else {
  1161. VectorProcessorClass::Clear (vnorm, VertexCount);
  1162. for (int pidx = 0; pidx < PolyCount; pidx++) {
  1163. vnorm[shadeIx[poly[pidx].I]].X += peq[pidx].X;
  1164. vnorm[shadeIx[poly[pidx].I]].Y += peq[pidx].Y;
  1165. vnorm[shadeIx[poly[pidx].I]].Z += peq[pidx].Z;
  1166. vnorm[shadeIx[poly[pidx].J]].X += peq[pidx].X;
  1167. vnorm[shadeIx[poly[pidx].J]].Y += peq[pidx].Y;
  1168. vnorm[shadeIx[poly[pidx].J]].Z += peq[pidx].Z;
  1169. vnorm[shadeIx[poly[pidx].K]].X += peq[pidx].X;
  1170. vnorm[shadeIx[poly[pidx].K]].Y += peq[pidx].Y;
  1171. vnorm[shadeIx[poly[pidx].K]].Z += peq[pidx].Z;
  1172. }
  1173. // normalize the "master" vertex normals and copy the smoothed ones
  1174. // (note: we always encounter the "master" ones first)
  1175. for (unsigned vidx = 0; vidx < (unsigned)VertexCount; vidx ++) {
  1176. if (shadeIx[vidx] == vidx) {
  1177. vnorm[vidx].Normalize();
  1178. } else {
  1179. vnorm[vidx] = vnorm[shadeIx[vidx]];
  1180. }
  1181. }
  1182. }
  1183. VectorProcessorClass::Normalize(vnorm, VertexCount);
  1184. Set_Flag(DIRTY_VNORMALS,false);
  1185. }
  1186. /***********************************************************************************************
  1187. * MeshGeometryClass::Compute_Bounds -- recomputes the bounding volumes *
  1188. * *
  1189. * INPUT: *
  1190. * *
  1191. * OUTPUT: *
  1192. * *
  1193. * WARNINGS: *
  1194. * This function should not normally be needed during run-time. *
  1195. * *
  1196. * HISTORY: *
  1197. * 11/9/2000 gth : Created. *
  1198. *=============================================================================================*/
  1199. void MeshGeometryClass::Compute_Bounds(Vector3 * verts)
  1200. {
  1201. BoundBoxMin.Set(0,0,0);
  1202. BoundBoxMax.Set(0,0,0);
  1203. BoundSphereCenter.Set(0,0,0);
  1204. BoundSphereRadius = 0.0;
  1205. if (VertexCount == 0) {
  1206. return;
  1207. }
  1208. // find bounding box minimum and maximum
  1209. if (verts == NULL) {
  1210. verts = Vertex->Get_Array();
  1211. }
  1212. VectorProcessorClass::MinMax(verts,BoundBoxMin,BoundBoxMax,VertexCount);
  1213. // calculate the bounding sphere
  1214. BoundSphereCenter = (BoundBoxMin + BoundBoxMax)/2.0f;
  1215. BoundSphereRadius = (float)(BoundBoxMax-BoundSphereCenter).Length2();
  1216. BoundSphereRadius = ((float)sqrt(BoundSphereRadius))*1.00001f;
  1217. Set_Flag(DIRTY_BOUNDS,false);
  1218. }
  1219. /***********************************************************************************************
  1220. * MeshGeometryClass::get_vert_normals -- get the vertex normal array *
  1221. * *
  1222. * INPUT: *
  1223. * *
  1224. * OUTPUT: *
  1225. * *
  1226. * WARNINGS: *
  1227. * *
  1228. * HISTORY: *
  1229. * 6/14/2001 gth : Created. *
  1230. *=============================================================================================*/
  1231. Vector3 * MeshGeometryClass::get_vert_normals(void)
  1232. {
  1233. #if (OPTIMIZE_VNORM_RAM)
  1234. _VNormArray.Uninitialised_Grow(VertexCount);
  1235. return &(_VNormArray[0]);
  1236. #else
  1237. WWASSERT(VertexNorm);
  1238. return VertexNorm->Get_Array();
  1239. #endif
  1240. }
  1241. /***********************************************************************************************
  1242. * MeshGeometryClass::Get_Vertex_Normal_Array -- validates and returns the vertex normal array *
  1243. * *
  1244. * INPUT: *
  1245. * *
  1246. * OUTPUT: *
  1247. * *
  1248. * WARNINGS: *
  1249. * *
  1250. * HISTORY: *
  1251. * 6/14/2001 gth : Created. *
  1252. *=============================================================================================*/
  1253. const Vector3 * MeshGeometryClass::Get_Vertex_Normal_Array(void)
  1254. {
  1255. #if (OPTIMIZE_VNORM_RAM)
  1256. Compute_Vertex_Normals(get_vert_normals());
  1257. return get_vert_normals();
  1258. #else
  1259. if (Get_Flag(DIRTY_VNORMALS)) {
  1260. Compute_Vertex_Normals(get_vert_normals());
  1261. }
  1262. return get_vert_normals();
  1263. #endif
  1264. }
  1265. /***********************************************************************************************
  1266. * MeshGeometryClass::get_planes -- get the plane array memory (internal) *
  1267. * *
  1268. * INPUT: *
  1269. * *
  1270. * OUTPUT: *
  1271. * *
  1272. * WARNINGS: *
  1273. * *
  1274. * HISTORY: *
  1275. * 6/14/2001 gth : Created. *
  1276. *=============================================================================================*/
  1277. Vector4 * MeshGeometryClass::get_planes(bool create)
  1278. {
  1279. #if (OPTIMIZE_PLANEEQ_RAM)
  1280. _PlaneEQArray.Uninitialised_Grow(PolyCount);
  1281. return &(_PlaneEQArray[0]);
  1282. #else
  1283. if (create && !PlaneEq) {
  1284. PlaneEq = NEW_REF(ShareBufferClass<Vector4>,(PolyCount, "MeshGeometryClass::PlaneEq"));
  1285. }
  1286. if (PlaneEq) {
  1287. return PlaneEq->Get_Array();
  1288. }
  1289. return NULL;
  1290. #endif
  1291. }
  1292. /***********************************************************************************************
  1293. * MeshGeometryClass::Get_Plane_Array -- validates and returns the array of plane equations *
  1294. * *
  1295. * INPUT: *
  1296. * *
  1297. * OUTPUT: *
  1298. * *
  1299. * WARNINGS: *
  1300. * *
  1301. * HISTORY: *
  1302. * 6/14/2001 gth : Created. *
  1303. *=============================================================================================*/
  1304. const Vector4 * MeshGeometryClass::Get_Plane_Array(bool create)
  1305. {
  1306. #if (OPTIMIZE_PLANEEQ_RAM)
  1307. Vector4 * planes = get_planes(create);
  1308. Compute_Plane_Equations(planes);
  1309. return planes;
  1310. #else
  1311. Vector4 * planes = get_planes(create);
  1312. if (planes && Get_Flag(DIRTY_PLANES)) {
  1313. Compute_Plane_Equations(planes);
  1314. }
  1315. return planes;
  1316. #endif
  1317. }
  1318. /***********************************************************************************************
  1319. * MeshGeometryClass::Compute_Plane -- compute the plane equation of a single poly *
  1320. * *
  1321. * INPUT: *
  1322. * *
  1323. * OUTPUT: *
  1324. * *
  1325. * WARNINGS: *
  1326. * *
  1327. * HISTORY: *
  1328. * 6/14/2001 gth : Created. *
  1329. *=============================================================================================*/
  1330. void MeshGeometryClass::Compute_Plane(int pidx,PlaneClass * set_plane) const
  1331. {
  1332. WWASSERT(pidx >= 0);
  1333. WWASSERT(pidx < PolyCount);
  1334. TriIndex & poly = Poly->Get_Array()[pidx];
  1335. Vector3 * verts = Vertex->Get_Array();
  1336. set_plane->Set(verts[poly.I],verts[poly.J],verts[poly.K]);
  1337. }
  1338. /***********************************************************************************************
  1339. * MeshGeometryClass::Generate_Culling_Tree -- Generate an AABTree for this mesh *
  1340. * *
  1341. * INPUT: *
  1342. * *
  1343. * OUTPUT: *
  1344. * *
  1345. * WARNINGS: *
  1346. * This function should not normally be needed during run-time. *
  1347. * *
  1348. * HISTORY: *
  1349. * 11/9/2000 gth : Created. *
  1350. *=============================================================================================*/
  1351. void MeshGeometryClass::Generate_Culling_Tree(void)
  1352. {
  1353. WWMEMLOG(MEM_CULLINGDATA);
  1354. {
  1355. AABTreeBuilderClass builder;
  1356. builder.Build_AABTree(PolyCount,Poly->Get_Array(),VertexCount,Vertex->Get_Array());
  1357. CullTree = NEW_REF(AABTreeClass,(&builder));
  1358. CullTree->Set_Mesh(this);
  1359. }
  1360. }
  1361. /***********************************************************************************************
  1362. * MeshGeometryClass::Load_W3D -- Load a mesh from a w3d file *
  1363. * *
  1364. * This function will extract just the geometry information from a W3D mesh. It must *
  1365. * be completely replaced by any derived classes that want to handle all of the chunks. *
  1366. * *
  1367. * INPUT: *
  1368. * *
  1369. * OUTPUT: *
  1370. * *
  1371. * WARNINGS: *
  1372. * *
  1373. * HISTORY: *
  1374. * 11/9/2000 gth : Created. *
  1375. *=============================================================================================*/
  1376. WW3DErrorType MeshGeometryClass::Load_W3D(ChunkLoadClass & cload)
  1377. {
  1378. /*
  1379. ** This function will initialize this MeshGeometryClass from the contents of a W3D file.
  1380. ** Note that derived classes need to completely replace this function; only re-using the individual
  1381. ** chunk handling functions.
  1382. */
  1383. /*
  1384. ** Open the first chunk, it should be the mesh header
  1385. */
  1386. cload.Open_Chunk();
  1387. if (cload.Cur_Chunk_ID() != W3D_CHUNK_MESH_HEADER3) {
  1388. WWDEBUG_SAY(("Old format mesh mesh, no longer supported.\n"));
  1389. goto Error;
  1390. }
  1391. W3dMeshHeader3Struct header;
  1392. if (cload.Read(&header,sizeof(W3dMeshHeader3Struct)) != sizeof(W3dMeshHeader3Struct)) {
  1393. goto Error;
  1394. }
  1395. cload.Close_Chunk();
  1396. /*
  1397. ** Process the header
  1398. */
  1399. char * tmpname;
  1400. int namelen;
  1401. Reset_Geometry(header.NumTris,header.NumVertices);
  1402. namelen = strlen(header.ContainerName);
  1403. namelen += strlen(header.MeshName);
  1404. namelen += 2;
  1405. W3dAttributes = header.Attributes;
  1406. SortLevel = header.SortLevel;
  1407. tmpname = W3DNEWARRAY char[namelen];
  1408. memset(tmpname,0,namelen);
  1409. if (strlen(header.ContainerName) > 0) {
  1410. strcpy(tmpname,header.ContainerName);
  1411. strcat(tmpname,".");
  1412. }
  1413. strcat(tmpname,header.MeshName);
  1414. Set_Name(tmpname);
  1415. delete[] tmpname;
  1416. tmpname = NULL;
  1417. /*
  1418. ** Set Bounding Info
  1419. */
  1420. BoundBoxMin.Set(header.Min.X,header.Min.Y,header.Min.Z);
  1421. BoundBoxMax.Set(header.Max.X,header.Max.Y,header.Max.Z);
  1422. BoundSphereCenter.Set(header.SphCenter.X,header.SphCenter.Y,header.SphCenter.Z);
  1423. BoundSphereRadius = header.SphRadius;
  1424. /*
  1425. ** Flags
  1426. */
  1427. if (header.Version >= W3D_MAKE_VERSION(4,1)) {
  1428. int geometry_type = header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
  1429. switch (geometry_type)
  1430. {
  1431. case W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL:
  1432. break;
  1433. case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED:
  1434. Set_Flag(ALIGNED,true);
  1435. break;
  1436. case W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED:
  1437. Set_Flag(ORIENTED,true);
  1438. break;
  1439. case W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN:
  1440. Set_Flag(SKIN,true);
  1441. break;
  1442. }
  1443. }
  1444. if (header.Attributes & W3D_MESH_FLAG_TWO_SIDED) {
  1445. Set_Flag(TWO_SIDED,true);
  1446. }
  1447. if (header.Attributes & W3D_MESH_FLAG_CAST_SHADOW) {
  1448. Set_Flag(CAST_SHADOW,true);
  1449. }
  1450. read_chunks(cload);
  1451. /*
  1452. ** If this is a pre-3.0 mesh and it has vertex influences,
  1453. ** fixup the bone indices to account for the new root node
  1454. */
  1455. if ((header.Version < W3D_MAKE_VERSION(3,0)) && (Get_Flag(SKIN))) {
  1456. uint16 * links = get_bone_links();
  1457. WWASSERT(links);
  1458. for (int bi = 0; bi < Get_Vertex_Count(); bi++) {
  1459. links[bi] += 1;
  1460. }
  1461. }
  1462. /*
  1463. ** If this mesh is collideable and no AABTree was in the file, generate one now
  1464. */
  1465. if ( (((W3dAttributes & W3D_MESH_FLAG_COLLISION_TYPE_MASK) >> W3D_MESH_FLAG_COLLISION_TYPE_SHIFT) != 0) &&
  1466. (CullTree == NULL))
  1467. {
  1468. Generate_Culling_Tree();
  1469. }
  1470. return WW3D_ERROR_OK;
  1471. Error:
  1472. return WW3D_ERROR_LOAD_FAILED;
  1473. }
  1474. /***********************************************************************************************
  1475. * MeshGeometryClass::read_chunks -- read w3d chunks *
  1476. * *
  1477. * Again, derived classes must replace this function with one that handles all of their *
  1478. * chunks in addition to calling to this class for the individual chunks that it handles. *
  1479. * *
  1480. * INPUT: *
  1481. * *
  1482. * OUTPUT: *
  1483. * *
  1484. * WARNINGS: *
  1485. * *
  1486. * HISTORY: *
  1487. * 11/9/2000 gth : Created. *
  1488. *=============================================================================================*/
  1489. WW3DErrorType MeshGeometryClass::read_chunks(ChunkLoadClass & cload)
  1490. {
  1491. /*
  1492. ** Read in the chunk header
  1493. ** If there are no more chunks within the mesh chunk,
  1494. ** we are done.
  1495. */
  1496. while (cload.Open_Chunk()) {
  1497. /*
  1498. ** Process the chunk
  1499. */
  1500. WW3DErrorType error = WW3D_ERROR_OK;
  1501. switch (cload.Cur_Chunk_ID()) {
  1502. case W3D_CHUNK_VERTICES:
  1503. error = read_vertices(cload);
  1504. break;
  1505. case W3D_CHUNK_SURRENDER_NORMALS:
  1506. case W3D_CHUNK_VERTEX_NORMALS:
  1507. error = read_vertex_normals(cload);
  1508. break;
  1509. case W3D_CHUNK_TRIANGLES:
  1510. error = read_triangles(cload);
  1511. break;
  1512. case W3D_CHUNK_MESH_USER_TEXT:
  1513. error = read_user_text(cload);
  1514. break;
  1515. case W3D_CHUNK_VERTEX_INFLUENCES:
  1516. error = read_vertex_influences(cload);
  1517. break;
  1518. case W3D_CHUNK_VERTEX_SHADE_INDICES:
  1519. error = read_vertex_shade_indices(cload);
  1520. break;
  1521. case W3D_CHUNK_AABTREE:
  1522. read_aabtree(cload);
  1523. break;
  1524. default:
  1525. break;
  1526. }
  1527. cload.Close_Chunk();
  1528. if (error != WW3D_ERROR_OK) {
  1529. return error;
  1530. }
  1531. }
  1532. return WW3D_ERROR_OK;
  1533. }
  1534. /***********************************************************************************************
  1535. * MeshGeometryClass::read_vertices -- read the vertex chunk from a W3D file *
  1536. * *
  1537. * INPUT: *
  1538. * *
  1539. * OUTPUT: *
  1540. * *
  1541. * WARNINGS: *
  1542. * *
  1543. * HISTORY: *
  1544. * 11/9/2000 gth : Created. *
  1545. *=============================================================================================*/
  1546. WW3DErrorType MeshGeometryClass::read_vertices(ChunkLoadClass & cload)
  1547. {
  1548. W3dVectorStruct vert;
  1549. Vector3 * loc = Vertex->Get_Array();
  1550. assert(loc);
  1551. for (int i=0; i<Get_Vertex_Count(); i++) {
  1552. if (cload.Read(&vert,sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
  1553. return WW3D_ERROR_LOAD_FAILED;
  1554. }
  1555. loc[i].X = vert.X;
  1556. loc[i].Y = vert.Y;
  1557. loc[i].Z = vert.Z;
  1558. }
  1559. return WW3D_ERROR_OK;
  1560. }
  1561. /***********************************************************************************************
  1562. * MeshGeometryClass::read_vertex_normals -- read the vertex normals chunk from a w3d file *
  1563. * *
  1564. * INPUT: *
  1565. * *
  1566. * OUTPUT: *
  1567. * *
  1568. * WARNINGS: *
  1569. * *
  1570. * HISTORY: *
  1571. * 11/9/2000 gth : Created. *
  1572. *=============================================================================================*/
  1573. WW3DErrorType MeshGeometryClass::read_vertex_normals(ChunkLoadClass & cload)
  1574. {
  1575. W3dVectorStruct norm;
  1576. Vector3 * mdlnorms = get_vert_normals();
  1577. WWASSERT(mdlnorms);
  1578. for (int i=0; i<VertexCount; i++) {
  1579. if (cload.Read(&norm,sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
  1580. return WW3D_ERROR_LOAD_FAILED;
  1581. }
  1582. mdlnorms[i].Set(norm.X,norm.Y,norm.Z);
  1583. }
  1584. return WW3D_ERROR_OK;
  1585. }
  1586. /***********************************************************************************************
  1587. * MeshGeometryClass::read_triangles -- read the triangles chunk from a w3d file *
  1588. * *
  1589. * INPUT: *
  1590. * *
  1591. * OUTPUT: *
  1592. * *
  1593. * WARNINGS: *
  1594. * *
  1595. * HISTORY: *
  1596. * 11/9/2000 gth : Created. *
  1597. *=============================================================================================*/
  1598. WW3DErrorType MeshGeometryClass::read_triangles(ChunkLoadClass & cload)
  1599. {
  1600. W3dTriStruct tri;
  1601. // cache pointers to various arrays in the surrender mesh
  1602. TriIndex * vi = get_polys();
  1603. Set_Flag(DIRTY_PLANES,false);
  1604. Vector4 * peq = get_planes();
  1605. uint8 * surface_types = Get_Poly_Surface_Type_Array();
  1606. // read in each polygon one by one
  1607. for (int i=0; i<Get_Polygon_Count(); i++) {
  1608. if (cload.Read(&tri,sizeof(W3dTriStruct)) != sizeof(W3dTriStruct)) {
  1609. return WW3D_ERROR_LOAD_FAILED;
  1610. }
  1611. // set the vertex indices
  1612. vi[i].I = tri.Vindex[0];
  1613. vi[i].J = tri.Vindex[1];
  1614. vi[i].K = tri.Vindex[2];
  1615. // set the normal
  1616. peq[i].X = tri.Normal.X;
  1617. peq[i].Y = tri.Normal.Y;
  1618. peq[i].Z = tri.Normal.Z;
  1619. peq[i].W = -tri.Dist;
  1620. // set the surface type
  1621. WWASSERT(tri.Attributes < 256);
  1622. surface_types[i] = (uint8)(tri.Attributes);
  1623. }
  1624. return WW3D_ERROR_OK;
  1625. }
  1626. /***********************************************************************************************
  1627. * MeshGeometryClass::read_user_text -- read the user text chunk from a w3d file *
  1628. * *
  1629. * INPUT: *
  1630. * *
  1631. * OUTPUT: *
  1632. * *
  1633. * WARNINGS: *
  1634. * *
  1635. * HISTORY: *
  1636. * 11/9/2000 gth : Created. *
  1637. *=============================================================================================*/
  1638. WW3DErrorType MeshGeometryClass::read_user_text(ChunkLoadClass & cload)
  1639. {
  1640. unsigned int textlen = cload.Cur_Chunk_Length();
  1641. /*
  1642. ** This shouldn't happen but if there are more than one
  1643. ** USER_TEXT chunks in the mesh file, store only the first
  1644. ** one. I am assuming that if the UserText buffer is not
  1645. ** NULL, then a previous user text chunk has been read in...
  1646. */
  1647. if (UserText != NULL) {
  1648. return WW3D_ERROR_OK;
  1649. }
  1650. /*
  1651. ** Allocate the buffer and read in the text
  1652. */
  1653. UserText = NEW_REF(ShareBufferClass<char>,(textlen, "MeshGeometryClass::UserText"));
  1654. if (cload.Read(UserText->Get_Array(),textlen) != textlen) {
  1655. return WW3D_ERROR_LOAD_FAILED;
  1656. }
  1657. return WW3D_ERROR_OK;
  1658. }
  1659. /***********************************************************************************************
  1660. * MeshGeometryClass::read_vertex_influences -- read the vertex influences chunk from a w3d fi *
  1661. * *
  1662. * INPUT: *
  1663. * *
  1664. * OUTPUT: *
  1665. * *
  1666. * WARNINGS: *
  1667. * *
  1668. * HISTORY: *
  1669. * 11/9/2000 gth : Created. *
  1670. *=============================================================================================*/
  1671. WW3DErrorType MeshGeometryClass::read_vertex_influences(ChunkLoadClass & cload)
  1672. {
  1673. W3dVertInfStruct vinf;
  1674. uint16 * links = get_bone_links(true);
  1675. WWASSERT(links);
  1676. for (int i=0; i<Get_Vertex_Count(); i++) {
  1677. if (cload.Read(&vinf,sizeof(W3dVertInfStruct)) != sizeof(W3dVertInfStruct)) {
  1678. return WW3D_ERROR_LOAD_FAILED;
  1679. }
  1680. links[i] = vinf.BoneIdx;
  1681. }
  1682. Set_Flag(SKIN,true);
  1683. return WW3D_ERROR_OK;
  1684. }
  1685. /***********************************************************************************************
  1686. * MeshGeometryClass::read_vertex_shade_indices -- read the vertex shade indices chunk *
  1687. * *
  1688. * INPUT: *
  1689. * *
  1690. * OUTPUT: *
  1691. * *
  1692. * WARNINGS: *
  1693. * *
  1694. * HISTORY: *
  1695. * 11/9/2000 gth : Created. *
  1696. *=============================================================================================*/
  1697. WW3DErrorType MeshGeometryClass::read_vertex_shade_indices(ChunkLoadClass & cload)
  1698. {
  1699. uint32 * shade_index = get_shade_indices(true);
  1700. uint32 si;
  1701. for (int i=0; i<Get_Vertex_Count(); i++) {
  1702. if (cload.Read(&si,sizeof(uint32)) != sizeof(uint32)) {
  1703. return WW3D_ERROR_LOAD_FAILED;
  1704. }
  1705. shade_index[i] = si;
  1706. }
  1707. return WW3D_ERROR_OK;
  1708. }
  1709. /***********************************************************************************************
  1710. * MeshGeometryClass::read_aabtree -- read the AABTree chunk from a w3d file *
  1711. * *
  1712. * INPUT: *
  1713. * *
  1714. * OUTPUT: *
  1715. * *
  1716. * WARNINGS: *
  1717. * *
  1718. * HISTORY: *
  1719. * 11/9/2000 gth : Created. *
  1720. *=============================================================================================*/
  1721. WW3DErrorType MeshGeometryClass::read_aabtree(ChunkLoadClass &cload)
  1722. {
  1723. REF_PTR_RELEASE(CullTree);
  1724. CullTree = NEW_REF(AABTreeClass,());
  1725. CullTree->Load_W3D(cload);
  1726. CullTree->Set_Mesh(this);
  1727. return (WW3D_ERROR_OK);
  1728. }
  1729. void MeshGeometryClass::Scale(const Vector3 &sc)
  1730. {
  1731. WWASSERT(Vertex);
  1732. Vector3 * vert = Vertex->Get_Array();
  1733. for (int i=0;i<VertexCount; i++) {
  1734. vert[i].X *= sc.X;
  1735. vert[i].Y *= sc.Y;
  1736. vert[i].Z *= sc.Z;
  1737. }
  1738. BoundBoxMin.Scale(sc);
  1739. BoundBoxMax.Scale(sc);
  1740. BoundSphereCenter.Scale(sc);
  1741. float max;
  1742. max = (sc.X > sc.Y) ? sc.X : sc.Y;
  1743. max = (max > sc.Z) ? max : sc.Z;
  1744. BoundSphereRadius *= max;
  1745. // If scaling uniformly normals are OK:
  1746. if (sc.X != sc.Y || sc.Y != sc.Z) {
  1747. Set_Flag(DIRTY_VNORMALS,true);
  1748. }
  1749. // pnormals are plane equations...
  1750. Set_Flag(DIRTY_PLANES,true);
  1751. // the cull tree is invalid, release it and make a new one
  1752. if (CullTree) {
  1753. // If the scale is uniform, we can scale the cull tree, which is a lot faster than creating a new one
  1754. if (fabs(sc[0]-sc[1])<WWMATH_EPSILON && fabs(sc[0]-sc[2])<WWMATH_EPSILON) {
  1755. // create a copy of the old culltree
  1756. AABTreeClass *temp = NEW_REF(AABTreeClass, ());
  1757. *temp = *CullTree;
  1758. temp->Set_Mesh(this);
  1759. REF_PTR_SET(CullTree, temp);
  1760. REF_PTR_RELEASE(temp);
  1761. CullTree->Scale(sc[0]);
  1762. }
  1763. else {
  1764. REF_PTR_RELEASE(CullTree);
  1765. Generate_Culling_Tree();
  1766. }
  1767. }
  1768. }
  1769. // Destination pointers MUST point to arrays large enough to hold all vertices
  1770. void MeshGeometryClass::get_deformed_vertices(Vector3 *dst_vert,const HTreeClass * htree)
  1771. {
  1772. Vector3 * src_vert = Vertex->Get_Array();
  1773. uint16 * bonelink = VertexBoneLink->Get_Array();
  1774. for (int vi = 0; vi < Get_Vertex_Count(); vi++) {
  1775. const Matrix3D & tm = htree->Get_Transform(bonelink[vi]);
  1776. Matrix3D::Transform_Vector(tm, src_vert[vi], &(dst_vert[vi]));
  1777. }
  1778. }
  1779. // Destination pointers MUST point to arrays large enough to hold all vertices
  1780. void MeshGeometryClass::get_deformed_vertices(Vector3 *dst_vert, Vector3 *dst_norm,const HTreeClass * htree)
  1781. {
  1782. int vi;
  1783. int vertex_count=Get_Vertex_Count();
  1784. Vector3 * src_vert = Vertex->Get_Array();
  1785. #if (OPTIMIZE_VNORMS)
  1786. Vector3 * src_norm = (Vector3 *)Get_Vertex_Normal_Array();
  1787. #else
  1788. Vector3 * src_norm = VertexNorm->Get_Array();
  1789. #endif
  1790. uint16 * bonelink = VertexBoneLink->Get_Array();
  1791. for (vi = 0; vi < vertex_count;) {
  1792. const Matrix3D & tm = htree->Get_Transform(bonelink[vi]);
  1793. // Make a copy so we can set the translation to zero
  1794. Matrix3D mytm=tm;
  1795. int idx=bonelink[vi];
  1796. int cnt;
  1797. for (cnt = vi; cnt < vertex_count; cnt++) {
  1798. if (idx!=bonelink[cnt]) {
  1799. break;
  1800. }
  1801. }
  1802. VectorProcessorClass::Transform(dst_vert+vi,src_vert+vi,mytm,cnt-vi);
  1803. mytm.Set_Translation(Vector3(0.0f,0.0f,0.0f));
  1804. VectorProcessorClass::Transform(dst_norm+vi,src_norm+vi,mytm,cnt-vi);
  1805. vi=cnt;
  1806. }
  1807. }
  1808. // Destination pointers MUST point to arrays large enough to hold all vertices
  1809. void MeshGeometryClass::get_deformed_screenspace_vertices(Vector4 *dst_vert,const RenderInfoClass & rinfo,const Matrix3D & mesh_transform,const HTreeClass * htree)
  1810. {
  1811. Matrix4x4 prj = rinfo.Camera.Get_Projection_Matrix() * rinfo.Camera.Get_View_Matrix() * mesh_transform;
  1812. Vector3 * src_vert = Vertex->Get_Array();
  1813. int vertex_count=Get_Vertex_Count();
  1814. if (Get_Flag(SKIN) && VertexBoneLink && htree) {
  1815. uint16 * bonelink = VertexBoneLink->Get_Array();
  1816. for (int vi = 0; vi < vertex_count;) {
  1817. int idx=bonelink[vi];
  1818. Matrix4x4 tm = prj * htree->Get_Transform(idx);
  1819. // Count equal matrices (the vertices should be pre-sorted by matrices they use)
  1820. for (int cnt = vi; cnt < vertex_count; cnt++) if (idx!=bonelink[cnt]) break;
  1821. // Transform to screenspace (x,y,z,w)
  1822. VectorProcessorClass::Transform(
  1823. dst_vert+vi,
  1824. src_vert+vi,
  1825. tm,
  1826. cnt-vi);
  1827. vi=cnt;
  1828. }
  1829. } else {
  1830. VectorProcessorClass::Transform(
  1831. dst_vert,
  1832. src_vert,
  1833. prj,
  1834. vertex_count);
  1835. }
  1836. }