mesh.cpp 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  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. /* $Header: /Commando/Code/ww3d2/mesh.cpp 70 3/14/02 2:39p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G 3D engine *
  24. * *
  25. * File Name : MESH.CPP *
  26. * *
  27. * Programmer : Greg Hjelstrom *
  28. * *
  29. * Start Date : 06/11/97 *
  30. * *
  31. * Last Update : June 12, 1997 [GH] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * MeshClass::MeshClass -- Constructor for MeshClass *
  36. * MeshClass::MeshClass -- Copy Constructor for MeshClass *
  37. * MeshClass::operator == -- assignment operator for MeshClass *
  38. * MeshClass::~MeshClass -- destructor *
  39. * MeshClass::Contains -- Determines whether mesh contains a (worldspace) point. *
  40. * MeshClass::Free -- Releases all memory/assets in use by this mesh *
  41. * MeshClass::Clone -- Creates a clone of this mesh *
  42. * MeshClass::Get_Name -- returns the name of the mesh *
  43. * MeshClass::Set_Name -- sets the name of this mesh *
  44. * MeshClass::Get_W3D_Flags -- access to the W3D flags *
  45. * MeshClass::Get_User_Text -- access to the text buffer *
  46. * MeshClass::Scale -- Scales the mesh *
  47. * MeshClass::Scale -- Scales the mesh *
  48. * MeshClass::Init -- Init the mesh from a MeshBuilder object *
  49. * MeshClass::Load -- creates a mesh out of a mesh chunk in a .w3d file *
  50. * MeshClass::Cast_Ray -- compute a ray intersection with this mesh *
  51. * MeshClass::Cast_AABox -- cast an AABox against this mesh *
  52. * MeshClass::Cast_OBBox -- Cast an obbox against this mesh *
  53. * MeshClass::Intersect_AABox -- test for intersection with given AABox *
  54. * MeshClass::Intersect_OBBox -- test for intersection with the given OBBox *
  55. * MeshClass::Generate_Culling_Tree -- Generates a hierarchical culling tree for the mesh *
  56. * MeshClass::Direct_Load -- read the w3d file directly into this mesh object *
  57. * MeshClass::read_chunks -- read all of the chunks from the .wtm file *
  58. * MeshClass::read_vertices -- reads the vertex chunk *
  59. * MeshClass::read_texcoords -- read in the texture coordinates chunk *
  60. * MeshClass::install_texture_coordinates -- installs the given u-v's in each channel that is*
  61. * MeshClass::read_vertex_normals -- reads a surrender normal chunk from the wtm file *
  62. * MeshClass::read_v3_materials -- Reads in version 3 materials. *
  63. * MeshClass::read_map -- Reads definition of a texture map from the file *
  64. * MeshClass::read_triangles -- read the triangles chunk *
  65. * MeshClass::read_per_tri_materials -- read the material indices for each triangle *
  66. * MeshClass::read_user_text -- read in the user text chunk *
  67. * MeshClass::read_vertex_colors -- read in the vertex colors chunk *
  68. * MeshClass::read_vertex_influences -- read in the vertex influences chunk *
  69. * MeshClass::Get_Material_Info -- returns a pointer to the material info *
  70. * MeshClass::Create_Decal -- creates a decal on this mesh *
  71. * MeshClass::Delete_Decal -- removes a decal from this mesh *
  72. * MeshClass::Get_Num_Polys -- returns the number of polys (tris) in this mesh *
  73. * MeshClass::Render -- renders this mesh *
  74. * MeshClass::Special_Render -- special render function for meshes *
  75. * MeshClass::update_skin -- deforms the mesh *
  76. * MeshClass::clone_materials -- clone the materials for this mesh *
  77. * MeshClass::install_materials -- transfers the materials into the mesh *
  78. * MeshClass::Get_Model -- user access to the mesh model *
  79. * MeshClass::Get_Obj_Space_Bounding_Sphere -- returns obj-space bounding sphere *
  80. * MeshClass::Get_Obj_Space_Bounding_Box -- returns the obj-space bounding box *
  81. * MeshClass::Get_Deformed_Vertices -- Gets the deformed vertices for a skin *
  82. * MeshClass::Get_Deformed_Vertices -- Gets the deformed vertices for a skin *
  83. * MeshClass::Render_Material_Pass -- Render a procedural material pass for this mesh *
  84. * MeshClass::Replace_VertexMaterial -- Replaces existing vertex material with a new one. Wi *
  85. * MeshClass::Make_Unique -- Makes mesh unique in the renderer, but still shares system ram *
  86. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  87. #include "mesh.h"
  88. #include <assert.h>
  89. #include <string.h>
  90. #include "w3d_file.h"
  91. #include "assetmgr.h"
  92. #include "w3derr.h"
  93. #include "wwdebug.h"
  94. #include "vertmaterial.h"
  95. #include "shader.h"
  96. #include "matinfo.h"
  97. #include "htree.h"
  98. #include "meshbuild.h"
  99. #include "tri.h"
  100. #include "aaplane.h"
  101. #include "aabtree.h"
  102. #include "chunkio.h"
  103. #include "w3d_util.h"
  104. #include "meshmdl.h"
  105. #include "meshgeometry.h"
  106. #include "ww3d.h"
  107. #include "camera.h"
  108. #include "texture.h"
  109. #include "rinfo.h"
  110. #include "coltest.h"
  111. #include "inttest.h"
  112. #include "decalmsh.h"
  113. #include "decalsys.h"
  114. #include "dx8polygonrenderer.h"
  115. #include "dx8indexbuffer.h"
  116. #include "dx8renderer.h"
  117. #include "visrasterizer.h"
  118. #include "wwmemlog.h"
  119. #include "dx8rendererdebugger.h"
  120. #include <stdio.h>
  121. #include <wwprofile.h>
  122. static unsigned MeshDebugIdCount;
  123. bool MeshClass::Legacy_Meshes_Fogged = true;
  124. static SimpleDynVecClass<uint32> temp_apt;
  125. /*
  126. ** This #define causes the collision code to always recompute the triangle normals rather
  127. ** than using the ones in the model.
  128. ** TODO: ensure that the models have unit normals and start re-using them again or write
  129. ** collision code to handle non-unit normals!
  130. */
  131. #if (OPTIMIZE_PLANEEQ_RAM)
  132. #define COMPUTE_NORMALS
  133. #endif
  134. /*
  135. ** Temporary storage used during decal creation
  136. */
  137. static DynamicVectorClass<Vector3> _TempVertexBuffer;
  138. /*
  139. ** Chunk ID's for saving user lighting
  140. */
  141. enum
  142. {
  143. CHUNKID_USER_LIGHTING_ARRAY = 0x07520213,
  144. };
  145. /***********************************************************************************************
  146. * MeshClass::MeshClass -- Constructor for MeshClass *
  147. * *
  148. * Initializes an empty mesh class *
  149. * *
  150. * INPUT: *
  151. * *
  152. * OUTPUT: *
  153. * *
  154. * WARNINGS: *
  155. * *
  156. * HISTORY: *
  157. * 1/6/98 GTH : Created. *
  158. *=============================================================================================*/
  159. MeshClass::MeshClass(void) :
  160. Model(NULL),
  161. DecalMesh(NULL),
  162. LightEnvironment(NULL),
  163. BaseVertexOffset(0),
  164. NextVisibleSkin(NULL),
  165. IsDisabledByDebugger(false),
  166. MeshDebugId(MeshDebugIdCount++),
  167. UserLighting(NULL)
  168. {
  169. }
  170. /***********************************************************************************************
  171. * MeshClass::MeshClass -- Copy Constructor for MeshClass *
  172. * *
  173. * Creates a mesh which is a copy of the given mesh *
  174. * *
  175. * INPUT: *
  176. * *
  177. * OUTPUT: *
  178. * *
  179. * WARNINGS: *
  180. * *
  181. * HISTORY: *
  182. *=============================================================================================*/
  183. MeshClass::MeshClass(const MeshClass & that) :
  184. RenderObjClass(that),
  185. Model(NULL),
  186. DecalMesh(NULL),
  187. LightEnvironment(NULL),
  188. BaseVertexOffset(that.BaseVertexOffset),
  189. NextVisibleSkin(NULL),
  190. IsDisabledByDebugger(false),
  191. MeshDebugId(MeshDebugIdCount++),
  192. UserLighting(NULL)
  193. {
  194. REF_PTR_SET(Model,that.Model); // mesh instances share models by default
  195. }
  196. /***********************************************************************************************
  197. * operator == -- assignment operator for MeshClass *
  198. * *
  199. * INPUT: *
  200. * *
  201. * OUTPUT: *
  202. * *
  203. * WARNINGS: *
  204. * *
  205. * HISTORY: *
  206. * 1/6/98 GTH : Created. *
  207. *=============================================================================================*/
  208. MeshClass & MeshClass::operator = (const MeshClass & that)
  209. {
  210. if (this != &that) {
  211. TheDX8MeshRenderer.Unregister_Mesh_Type(this);
  212. RenderObjClass::operator = (that);
  213. REF_PTR_SET(Model,that.Model); // mesh instances share models by default
  214. BaseVertexOffset = that.BaseVertexOffset;
  215. // just dont copy the decals or light environment
  216. REF_PTR_RELEASE(DecalMesh);
  217. LightEnvironment = NULL;
  218. if (UserLighting != NULL) {
  219. delete[] UserLighting;
  220. UserLighting = NULL;
  221. }
  222. }
  223. return * this;
  224. }
  225. /***********************************************************************************************
  226. * MeshClass::~MeshClass -- destructor *
  227. * *
  228. * INPUT: *
  229. * *
  230. * OUTPUT: *
  231. * *
  232. * WARNINGS: *
  233. * *
  234. * HISTORY: *
  235. * 1/6/98 GTH : Created. *
  236. *=============================================================================================*/
  237. MeshClass::~MeshClass(void)
  238. {
  239. TheDX8MeshRenderer.Unregister_Mesh_Type(this);
  240. Free();
  241. }
  242. /***********************************************************************************************
  243. * MeshClass::Contains -- Determines whether mesh contains a (worldspace) point. *
  244. * *
  245. * INPUT: *
  246. * *
  247. * OUTPUT: *
  248. * *
  249. * WARNINGS: Assumes mesh is a closed manifold - results are undefined otherwise *
  250. * This function will NOT work for skins *
  251. * *
  252. * HISTORY: *
  253. * 8/30/00 NH : Created. *
  254. *=============================================================================================*/
  255. bool MeshClass::Contains(const Vector3 &point)
  256. {
  257. // Transform point to object space and pass on to model
  258. Vector3 obj_point;
  259. Matrix3D::Inverse_Transform_Vector(Transform, point, &obj_point);
  260. return Model->Contains(obj_point);
  261. }
  262. /***********************************************************************************************
  263. * MeshClass::Free -- Releases all memory/assets in use by this mesh *
  264. * *
  265. * INPUT: *
  266. * *
  267. * OUTPUT: *
  268. * *
  269. * WARNINGS: *
  270. * *
  271. * HISTORY: *
  272. * 1/6/98 GTH : Created. *
  273. *=============================================================================================*/
  274. void MeshClass::Free(void)
  275. {
  276. REF_PTR_RELEASE(Model);
  277. REF_PTR_RELEASE(DecalMesh);
  278. if (UserLighting != NULL) {
  279. delete[] UserLighting;
  280. UserLighting = NULL;
  281. }
  282. }
  283. /***********************************************************************************************
  284. * MeshClass::Clone -- Creates a clone of this mesh *
  285. * *
  286. * INPUT: *
  287. * *
  288. * OUTPUT: *
  289. * *
  290. * WARNINGS: *
  291. * *
  292. * HISTORY: *
  293. * 1/6/98 GTH : Created. *
  294. *=============================================================================================*/
  295. RenderObjClass * MeshClass::Clone(void) const
  296. {
  297. return NEW_REF( MeshClass, (*this));
  298. }
  299. /***********************************************************************************************
  300. * MeshClass::Get_Name -- returns the name of the mesh *
  301. * *
  302. * INPUT: *
  303. * *
  304. * OUTPUT: *
  305. * *
  306. * WARNINGS: *
  307. * *
  308. * HISTORY: *
  309. * 5/15/98 GTH : Created. *
  310. *=============================================================================================*/
  311. const char * MeshClass::Get_Name(void) const
  312. {
  313. return Model->Get_Name();
  314. }
  315. /***********************************************************************************************
  316. * MeshClass::Set_Name -- sets the name of this mesh *
  317. * *
  318. * INPUT: *
  319. * *
  320. * OUTPUT: *
  321. * *
  322. * WARNINGS: *
  323. * *
  324. * HISTORY: *
  325. * 3/9/99 GTH : Created. *
  326. *=============================================================================================*/
  327. void MeshClass::Set_Name(const char * name)
  328. {
  329. Model->Set_Name(name);
  330. }
  331. /***********************************************************************************************
  332. * MeshClass::Get_W3D_Flags -- access to the W3D flags *
  333. * *
  334. * INPUT: *
  335. * *
  336. * OUTPUT: *
  337. * *
  338. * WARNINGS: *
  339. * *
  340. * HISTORY: *
  341. * 5/15/98 GTH : Created. *
  342. *=============================================================================================*/
  343. uint32 MeshClass::Get_W3D_Flags(void)
  344. {
  345. return Model->W3dAttributes;
  346. }
  347. /***********************************************************************************************
  348. * MeshClass::Get_User_Text -- access to the text buffer *
  349. * *
  350. * INPUT: *
  351. * *
  352. * OUTPUT: *
  353. * *
  354. * WARNINGS: *
  355. * *
  356. * HISTORY: *
  357. * 5/15/98 GTH : Created. *
  358. *=============================================================================================*/
  359. const char * MeshClass::Get_User_Text(void) const
  360. {
  361. return Model->Get_User_Text();
  362. }
  363. /***********************************************************************************************
  364. * MeshClass::Get_Material_Info -- returns a pointer to the material info *
  365. * *
  366. * INPUT: *
  367. * *
  368. * OUTPUT: *
  369. * *
  370. * WARNINGS: *
  371. * *
  372. * HISTORY: *
  373. * 5/20/98 GTH : Created. *
  374. *=============================================================================================*/
  375. MaterialInfoClass * MeshClass::Get_Material_Info(void)
  376. {
  377. if (Model) {
  378. if (Model->MatInfo) {
  379. Model->MatInfo->Add_Ref();
  380. return Model->MatInfo;
  381. }
  382. }
  383. return NULL;
  384. }
  385. /***********************************************************************************************
  386. * MeshClass::Get_Model -- user access to the mesh model *
  387. * *
  388. * INPUT: *
  389. * *
  390. * OUTPUT: *
  391. * *
  392. * WARNINGS: *
  393. * *
  394. * HISTORY: *
  395. * 2/4/99 GTH : Created. *
  396. *=============================================================================================*/
  397. MeshModelClass * MeshClass::Get_Model(void)
  398. {
  399. if (Model != NULL) {
  400. Model->Add_Ref();
  401. }
  402. return Model;
  403. }
  404. /***********************************************************************************************
  405. * MeshClass::Scale -- Scales the mesh *
  406. * *
  407. * INPUT: *
  408. * *
  409. * OUTPUT: *
  410. * *
  411. * WARNINGS: *
  412. * *
  413. * HISTORY: *
  414. *=============================================================================================*/
  415. void MeshClass::Scale(float scale)
  416. {
  417. if (scale==1.0f) return;
  418. Vector3 sc;
  419. sc.X = sc.Y = sc.Z = scale;
  420. Make_Unique();
  421. Model->Make_Geometry_Unique();
  422. Model->Scale(sc);
  423. Invalidate_Cached_Bounding_Volumes();
  424. // Now update the object space bounding volumes of this object's container:
  425. RenderObjClass *container = Get_Container();
  426. if (container) container->Update_Obj_Space_Bounding_Volumes();
  427. }
  428. /***********************************************************************************************
  429. * MeshClass::Scale -- Scales the mesh *
  430. * *
  431. * INPUT: *
  432. * *
  433. * OUTPUT: *
  434. * *
  435. * WARNINGS: *
  436. * *
  437. * HISTORY: *
  438. * 1/6/98 GTH : Created. *
  439. * 12/8/98 GTH : Modified the box scaling to use the non-uniform parameters *
  440. *=============================================================================================*/
  441. void MeshClass::Scale(float scalex, float scaley, float scalez)
  442. {
  443. // scale the surrender mesh model
  444. Vector3 sc;
  445. sc.X = scalex;
  446. sc.Y = scaley;
  447. sc.Z = scalez;
  448. Make_Unique();
  449. Model->Make_Geometry_Unique();
  450. Model->Scale(sc);
  451. Invalidate_Cached_Bounding_Volumes();
  452. // Now update the object space bounding volumes of this object's container:
  453. RenderObjClass *container = Get_Container();
  454. if (container) container->Update_Obj_Space_Bounding_Volumes();
  455. }
  456. /***********************************************************************************************
  457. * MeshClass::Get_Deformed_Vertices -- Gets the deformed vertices for a skin *
  458. * *
  459. * INPUT: *
  460. * *
  461. * OUTPUT: *
  462. * *
  463. * WARNINGS: *
  464. * *
  465. * HISTORY: *
  466. * 3/4/2001 gth : Created. *
  467. *=============================================================================================*/
  468. void MeshClass::Get_Deformed_Vertices(Vector3 *dst_vert, Vector3 *dst_norm)
  469. {
  470. WWASSERT(Model->Get_Flag(MeshGeometryClass::SKIN));
  471. Model->get_deformed_vertices(dst_vert,dst_norm,Container->Get_HTree());
  472. }
  473. /***********************************************************************************************
  474. * MeshClass::Get_Deformed_Vertices -- Gets the deformed vertices for a skin *
  475. * *
  476. * INPUT: *
  477. * *
  478. * OUTPUT: *
  479. * *
  480. * WARNINGS: *
  481. * *
  482. * HISTORY: *
  483. * 3/4/2001 gth : Created. *
  484. *=============================================================================================*/
  485. void MeshClass::Get_Deformed_Vertices(Vector3 *dst_vert)
  486. {
  487. WWASSERT(Model->Get_Flag(MeshGeometryClass::SKIN));
  488. WWASSERT(Container != NULL);
  489. WWASSERT(Container->Get_HTree() != NULL);
  490. Model->get_deformed_vertices(dst_vert,Container->Get_HTree());
  491. }
  492. void MeshClass::Compose_Deformed_Vertex_Buffer(
  493. VertexFormatXYZNDUV2* verts,
  494. const Vector2* uv0,
  495. const Vector2* uv1,
  496. const unsigned* diffuse)
  497. {
  498. WWASSERT(Model->Get_Flag(MeshGeometryClass::SKIN));
  499. Model->compose_deformed_vertex_buffer(verts,uv0,uv1,diffuse,Container->Get_HTree());
  500. }
  501. /***********************************************************************************************
  502. * MeshClass::Create_Decal -- creates a decal on this mesh *
  503. * *
  504. * INPUT: *
  505. * *
  506. * OUTPUT: *
  507. * *
  508. * WARNINGS: *
  509. * *
  510. * HISTORY: *
  511. * 1/26/00 gth : Created. *
  512. *=============================================================================================*/
  513. void MeshClass::Create_Decal(DecalGeneratorClass * generator)
  514. {
  515. WWMEMLOG(MEM_GEOMETRY);
  516. if (WW3D::Are_Decals_Enabled() == false) {
  517. return;
  518. }
  519. if (Is_Translucent() && (generator->Is_Applied_To_Translucent_Meshes() == false)) {
  520. return;
  521. }
  522. if (!Model->Get_Flag(MeshGeometryClass::SKIN)) {
  523. // Rigid mesh
  524. Matrix3D modeltm_inv;
  525. OBBoxClass localbox;
  526. Get_Transform().Get_Orthogonal_Inverse(modeltm_inv);
  527. OBBoxClass::Transform(modeltm_inv, generator->Get_Bounding_Volume(), &localbox);
  528. // generate apt, if it is not empty, add a decal.
  529. temp_apt.Delete_All(false); // reset contents
  530. Model->Generate_Rigid_APT(localbox, temp_apt);
  531. if (temp_apt.Count() > 0) {
  532. if (DecalMesh == NULL) {
  533. DecalMesh = NEW_REF(RigidDecalMeshClass, (this, generator->Peek_Decal_System()));
  534. }
  535. DecalMesh->Create_Decal(generator, localbox, temp_apt);
  536. }
  537. } else {
  538. WWDEBUG_SAY(("PERFORMANCE WARNING: Decal being applied to a SKIN mesh!\r\n"));
  539. // Skin
  540. // The deformed worldspace vertices are used both for the APT and in Create_Decal() to
  541. // generate the texture coordinates.
  542. int vertex_count = Model->Get_Vertex_Count();
  543. if (_TempVertexBuffer.Count() < vertex_count) _TempVertexBuffer.Resize(vertex_count);
  544. Vector3 *dst_vert = &(_TempVertexBuffer[0]);
  545. Get_Deformed_Vertices(dst_vert);
  546. // generate apt, if it is not empty, add a decal.
  547. temp_apt.Delete_All(false);
  548. OBBoxClass worldbox = generator->Get_Bounding_Volume();
  549. // We compare the worldspace box vs. the worldspace vertices
  550. Model->Generate_Skin_APT(worldbox, temp_apt, dst_vert);
  551. // if it is not empty, add a decal
  552. if (temp_apt.Count() > 0) {
  553. if (DecalMesh == NULL) {
  554. DecalMesh = NEW_REF(SkinDecalMeshClass, (this, generator->Peek_Decal_System()));
  555. }
  556. DecalMesh->Create_Decal(generator, worldbox, temp_apt, &_TempVertexBuffer);
  557. }
  558. }
  559. }
  560. /***********************************************************************************************
  561. * MeshClass::Delete_Decal -- removes a decal from this mesh *
  562. * *
  563. * INPUT: *
  564. * *
  565. * OUTPUT: *
  566. * *
  567. * WARNINGS: *
  568. * *
  569. * HISTORY: *
  570. * 1/26/00 gth : Created. *
  571. *=============================================================================================*/
  572. void MeshClass::Delete_Decal(uint32 decal_id)
  573. {
  574. if (DecalMesh != NULL) {
  575. DecalMesh->Delete_Decal(decal_id);
  576. }
  577. }
  578. /***********************************************************************************************
  579. * MeshClass::Get_Num_Polys -- returns the number of polys (tris) in this mesh *
  580. * *
  581. * INPUT: *
  582. * *
  583. * OUTPUT: *
  584. * *
  585. * WARNINGS: *
  586. * *
  587. * HISTORY: *
  588. * 1/6/98 GTH : Created. *
  589. *=============================================================================================*/
  590. int MeshClass::Get_Num_Polys(void) const
  591. {
  592. if (Model) {
  593. int num_passes=Model->Get_Pass_Count();
  594. WWASSERT(num_passes>0);
  595. int poly_count=Model->Get_Polygon_Count();
  596. return num_passes*poly_count;
  597. } else {
  598. return 0;
  599. }
  600. }
  601. /***********************************************************************************************
  602. * MeshClass::Render -- renders this mesh *
  603. * *
  604. * INPUT: *
  605. * *
  606. * OUTPUT: *
  607. * *
  608. * WARNINGS: *
  609. * *
  610. * HISTORY: *
  611. * 12/10/98 GTH : Created. *
  612. *=============================================================================================*/
  613. void MeshClass::Render(RenderInfoClass & rinfo)
  614. {
  615. WWPROFILE("Mesh::Render");
  616. if (Is_Not_Hidden_At_All() == false) {
  617. return;
  618. }
  619. // If static sort lists are enabled and this mesh has a sort level, put it on the list instead
  620. // of rendering it.
  621. unsigned int sort_level = (unsigned int)Model->Get_Sort_Level();
  622. if (WW3D::Are_Static_Sort_Lists_Enabled() && sort_level != SORT_LEVEL_NONE) {
  623. WW3D::Add_To_Static_Sort_List(this, sort_level);
  624. /*
  625. ** Plug in lighting so that when this mesh gets rendered later
  626. */
  627. Set_Lighting_Environment(rinfo.light_environment);
  628. } else {
  629. /*
  630. ** Plug in the lighting environment unless we arrived here as part of the static
  631. ** sorting system being flushed
  632. */
  633. if (WW3D::Are_Static_Sort_Lists_Enabled()) {
  634. Set_Lighting_Environment(rinfo.light_environment);
  635. }
  636. const FrustumClass & frustum=rinfo.Camera.Get_Frustum();
  637. if ( Model->Get_Flag(MeshGeometryClass::SKIN) ||
  638. CollisionMath::Overlap_Test(frustum,Get_Bounding_Box())!=CollisionMath::OUTSIDE )
  639. {
  640. bool rendered_something = false;
  641. /*
  642. ** If this mesh model has never been rendered, we need to generate the DX8 datastructures
  643. */
  644. if (PolygonRendererList.Is_Empty()) {
  645. Model->Register_For_Rendering();
  646. TheDX8MeshRenderer.Register_Mesh_Type(this);
  647. }
  648. /*
  649. ** Process texture reductions:
  650. */
  651. // Model->Process_Texture_Reduction();
  652. /*
  653. ** Look up the FVF container that this mesh is in
  654. */
  655. DX8FVFCategoryContainer * fvf_container = PolygonRendererList.Peek_Head()->Get_Texture_Category()->Get_Container();
  656. /*
  657. ** Check if we should render the base passes. One special case here: if
  658. ** the mesh is translucent (alpha) and the base passes are disabled but we
  659. ** are rendering a shadow, we go ahead and render the base pass. This is an ugly way
  660. ** to get our tree shadows and other alpha textured shadows to work.
  661. */
  662. bool render_base_passes = ((rinfo.Current_Override_Flags() & RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY) == 0);
  663. bool is_alpha = (Model->Get_Single_Shader().Get_Alpha_Test() == ShaderClass::ALPHATEST_ENABLE) ||
  664. (Model->Get_Single_Shader().Get_Src_Blend_Func() == ShaderClass::SRCBLEND_SRC_ALPHA);
  665. if ( (rinfo.Current_Override_Flags() & RenderInfoClass::RINFO_OVERRIDE_SHADOW_RENDERING) &&
  666. (is_alpha == true))
  667. {
  668. render_base_passes = true;
  669. }
  670. if (render_base_passes) {
  671. /*
  672. ** Link each polygon renderer for this mesh into the visible list
  673. */
  674. DX8PolygonRendererListIterator it(&(PolygonRendererList));
  675. while (!it.Is_Done()) {
  676. DX8PolygonRendererClass* polygon_renderer=it.Peek_Obj();
  677. polygon_renderer->Get_Texture_Category()->Add_Render_Task(polygon_renderer,this);
  678. it.Next();
  679. }
  680. rendered_something = true;
  681. }
  682. /*
  683. ** If the rendering context specifies procedural material passes, register them
  684. ** for rendering
  685. */
  686. for (int i=0; i<rinfo.Additional_Pass_Count(); i++) {
  687. MaterialPassClass * matpass = rinfo.Peek_Additional_Pass(i);
  688. if ((!Is_Translucent()) || (matpass->Is_Enabled_On_Translucent_Meshes())) {
  689. /*
  690. ** If the base pass for this mesh has been disabled, we have to make sure
  691. ** the procedural material pass is rendered after everything else has rendered
  692. */
  693. if (rinfo.Current_Override_Flags() & RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY) {
  694. fvf_container->Add_Delayed_Visible_Material_Pass(matpass, this);
  695. } else {
  696. fvf_container->Add_Visible_Material_Pass(matpass,this);
  697. }
  698. rendered_something = true;
  699. }
  700. }
  701. /*
  702. ** If we rendered any base or procedural passes and this is a skin, we need
  703. ** to tell the mesh rendering system to process this skin
  704. */
  705. if (rendered_something && Model->Get_Flag(MeshGeometryClass::SKIN)) {
  706. //WWASSERT(dynamic_cast<DX8SkinFVFCategoryContainer *>(fvf_container) != NULL);
  707. static_cast<DX8SkinFVFCategoryContainer*>(fvf_container)->Add_Visible_Skin(this);
  708. }
  709. /*
  710. ** If we have a decal mesh, link it into the mesh rendering system
  711. */
  712. if ( (DecalMesh != NULL) &&
  713. ((rinfo.Current_Override_Flags() & RenderInfoClass::RINFO_OVERRIDE_ADDITIONAL_PASSES_ONLY) == 0))
  714. {
  715. const SphereClass & ws_sphere = Get_Bounding_Sphere();
  716. Vector3 cam_space_sphere_center;
  717. rinfo.Camera.Transform_To_View_Space(cam_space_sphere_center,ws_sphere.Center);
  718. if (-cam_space_sphere_center.Z - ws_sphere.Radius < WW3D::Get_Decal_Rejection_Distance()) {
  719. TheDX8MeshRenderer.Add_To_Render_List(DecalMesh);
  720. }
  721. }
  722. DX8RendererDebugger::Add_Mesh(this);
  723. }
  724. }
  725. }
  726. /***********************************************************************************************
  727. * MeshClass::Render_Material_Pass -- Render a procedural material pass for this mesh *
  728. * *
  729. * INPUT: *
  730. * *
  731. * OUTPUT: *
  732. * *
  733. * WARNINGS: *
  734. * *
  735. * HISTORY: *
  736. * 3/4/2001 gth : Created. *
  737. *=============================================================================================*/
  738. void MeshClass::Render_Material_Pass(MaterialPassClass * pass,IndexBufferClass * ib)
  739. {
  740. if (LightEnvironment != NULL) {
  741. DX8Wrapper::Set_Light_Environment(LightEnvironment);
  742. }
  743. if (Model->Get_Flag(MeshModelClass::SKIN)) {
  744. /*
  745. ** In the case of skin meshes, we need to render our polys with the identity transform
  746. */
  747. pass->Install_Materials();
  748. DX8Wrapper::Set_Index_Buffer(ib,0);
  749. SNAPSHOT_SAY(("Set_World_Identity\n"));
  750. DX8Wrapper::Set_World_Identity();
  751. DX8PolygonRendererListIterator it(&PolygonRendererList);
  752. while (!it.Is_Done()) {
  753. it.Peek_Obj()->Render(BaseVertexOffset);
  754. it.Next();
  755. }
  756. } else if ((pass->Get_Cull_Volume() != NULL) && (MaterialPassClass::Is_Per_Polygon_Culling_Enabled())) {
  757. /*
  758. ** Generate the APT
  759. */
  760. temp_apt.Delete_All(false);
  761. Matrix3D modeltminv;
  762. Get_Transform().Get_Orthogonal_Inverse(modeltminv);
  763. OBBoxClass localbox;
  764. OBBoxClass::Transform(modeltminv,*(pass->Get_Cull_Volume()),&localbox);
  765. Vector3 view_dir;
  766. localbox.Basis.Get_Z_Vector(&view_dir);
  767. view_dir = -view_dir;
  768. if (Model->Has_Cull_Tree()) {
  769. Model->Generate_Rigid_APT(localbox,view_dir,temp_apt);
  770. } else {
  771. Model->Generate_Rigid_APT(view_dir,temp_apt);
  772. }
  773. if (temp_apt.Count() > 0) {
  774. int buftype = BUFFER_TYPE_DYNAMIC_DX8;
  775. if (Model->Get_Flag(MeshGeometryClass::SORT) && WW3D::Is_Sorting_Enabled()) {
  776. buftype = BUFFER_TYPE_DYNAMIC_SORTING;
  777. }
  778. /*
  779. ** Spew triangles in the APT into the dynamic index buffer
  780. */
  781. int min_v = Model->Get_Vertex_Count();
  782. int max_v = 0;
  783. DynamicIBAccessClass dynamic_ib(buftype,temp_apt.Count() * 3);
  784. {
  785. DynamicIBAccessClass::WriteLockClass lock(&dynamic_ib);
  786. unsigned short * indices = lock.Get_Index_Array();
  787. const TriIndex * polys = Model->Get_Polygon_Array();
  788. for (int i=0; i < temp_apt.Count(); i++)
  789. {
  790. unsigned v0 = polys[temp_apt[i]].I;
  791. unsigned v1 = polys[temp_apt[i]].J;
  792. unsigned v2 = polys[temp_apt[i]].K;
  793. indices[i*3 + 0] = (unsigned short)v0;
  794. indices[i*3 + 1] = (unsigned short)v1;
  795. indices[i*3 + 2] = (unsigned short)v2;
  796. min_v = WWMath::Min(v0,min_v);
  797. min_v = WWMath::Min(v1,min_v);
  798. min_v = WWMath::Min(v2,min_v);
  799. max_v = WWMath::Max(v0,max_v);
  800. max_v = WWMath::Max(v1,max_v);
  801. max_v = WWMath::Max(v2,max_v);
  802. }
  803. }
  804. /*
  805. ** Render
  806. */
  807. int vertex_offset = PolygonRendererList.Peek_Head()->Get_Vertex_Offset();
  808. pass->Install_Materials();
  809. DX8Wrapper::Set_Transform(D3DTS_WORLD,Get_Transform());
  810. DX8Wrapper::Set_Index_Buffer(dynamic_ib,vertex_offset);
  811. DX8Wrapper::Draw_Triangles(
  812. 0,
  813. temp_apt.Count(),
  814. min_v,
  815. max_v-min_v+1);
  816. }
  817. } else {
  818. /*
  819. ** Normal mesh case, render polys with this mesh's transform
  820. */
  821. pass->Install_Materials();
  822. DX8Wrapper::Set_Index_Buffer(ib,0);
  823. SNAPSHOT_SAY(("Set_World_Transform\n"));
  824. DX8Wrapper::Set_Transform(D3DTS_WORLD,Transform);
  825. DX8PolygonRendererListIterator it(&PolygonRendererList);
  826. while (!it.Is_Done()) {
  827. it.Peek_Obj()->Render(BaseVertexOffset);
  828. it.Next();
  829. }
  830. }
  831. }
  832. /***********************************************************************************************
  833. * MeshClass::Special_Render -- special render function for meshes *
  834. * *
  835. * INPUT: *
  836. * *
  837. * OUTPUT: *
  838. * *
  839. * WARNINGS: *
  840. * *
  841. * HISTORY: *
  842. * 12/10/98 GTH : Created. *
  843. *=============================================================================================*/
  844. void MeshClass::Special_Render(SpecialRenderInfoClass & rinfo)
  845. {
  846. if ((Is_Not_Hidden_At_All() == false) && (rinfo.RenderType != SpecialRenderInfoClass::RENDER_SHADOW)) {
  847. return;
  848. }
  849. if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_VIS) {
  850. WWASSERT(rinfo.VisRasterizer != NULL);
  851. rinfo.VisRasterizer->Enable_Two_Sided_Rendering(!!Model->Get_Flag(MeshGeometryClass::TWO_SIDED));
  852. if (Model->Get_Flag(MeshModelClass::SKIN) == 0) {
  853. rinfo.VisRasterizer->Set_Model_Transform(Transform);
  854. rinfo.VisRasterizer->Render_Triangles( Model->Get_Vertex_Array(),
  855. Model->Get_Vertex_Count(),
  856. Model->Get_Polygon_Array(),
  857. Model->Get_Polygon_Count(),
  858. Get_Bounding_Box() );
  859. } else {
  860. int vertex_count = Model->Get_Vertex_Count();
  861. if (_TempVertexBuffer.Count() < vertex_count) _TempVertexBuffer.Resize(vertex_count);
  862. Vector3 *dst_vert = &(_TempVertexBuffer[0]);
  863. Get_Deformed_Vertices(dst_vert);
  864. rinfo.VisRasterizer->Set_Model_Transform(Matrix3D::Identity);
  865. rinfo.VisRasterizer->Render_Triangles( dst_vert,
  866. Model->Get_Vertex_Count(),
  867. Model->Get_Polygon_Array(),
  868. Model->Get_Polygon_Count(),
  869. Get_Bounding_Box() );
  870. }
  871. rinfo.VisRasterizer->Enable_Two_Sided_Rendering(false);
  872. }
  873. if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_SHADOW) {
  874. const HTreeClass * htree = NULL;
  875. if (Container!=NULL) {
  876. htree = Container->Get_HTree();
  877. }
  878. Model->Shadow_Render(rinfo,Transform,htree);
  879. }
  880. }
  881. void MeshClass::Replace_Texture(TextureClass* texture,TextureClass* new_texture)
  882. {
  883. Model->Replace_Texture(texture,new_texture);
  884. }
  885. /***********************************************************************************************
  886. * MeshClass::Replace_VertexMaterial -- Replaces existing vertex material with a new one. Will *
  887. * *
  888. * *
  889. * *
  890. * *
  891. * INPUT: *
  892. * *
  893. * OUTPUT: *
  894. * *
  895. * WARNINGS: *
  896. * *
  897. * HISTORY: *
  898. * 4/2/2001 hy : Created. *
  899. *=============================================================================================*/
  900. void MeshClass::Replace_VertexMaterial(VertexMaterialClass* vmat,VertexMaterialClass* new_vmat)
  901. {
  902. Model->Replace_VertexMaterial(vmat,new_vmat);
  903. }
  904. /***********************************************************************************************
  905. * MeshClass::Make_Unique -- Makes mesh unique in the renderer, but still shares system ram ge *
  906. * *
  907. * *
  908. * *
  909. * *
  910. * INPUT: *
  911. * *
  912. * OUTPUT: *
  913. * *
  914. * WARNINGS: *
  915. * *
  916. * HISTORY: *
  917. * 4/2/2001 hy : Created. *
  918. *=============================================================================================*/
  919. void MeshClass::Make_Unique()
  920. {
  921. if (Model->Num_Refs()==1) return;
  922. MeshModelClass *newmesh=NEW_REF(MeshModelClass,(*Model));
  923. REF_PTR_SET(Model,newmesh);
  924. REF_PTR_RELEASE(newmesh);
  925. }
  926. /***********************************************************************************************
  927. * MeshClass::Load -- creates a mesh out of a mesh chunk in a .w3d file *
  928. * *
  929. * INPUT: *
  930. * *
  931. * OUTPUT: *
  932. * *
  933. * WARNINGS: *
  934. * *
  935. * HISTORY: *
  936. * 06/12/1997 GH : Created. *
  937. *=============================================================================================*/
  938. WW3DErrorType MeshClass::Load_W3D(ChunkLoadClass & cload)
  939. {
  940. Vector3 boxmin,boxmax;
  941. /*
  942. ** Make sure this mesh is "empty"
  943. */
  944. Free();
  945. /*
  946. ** Create empty MaterialInfo and Model
  947. */
  948. Model = NEW_REF(MeshModelClass,());
  949. if (Model == NULL) {
  950. WWDEBUG_SAY(("MeshClass::Load - Failed to allocate model\r\n"));
  951. return WW3D_ERROR_LOAD_FAILED;
  952. }
  953. /*
  954. ** Create and read in the model...
  955. */
  956. if (Model->Load_W3D(cload) != WW3D_ERROR_OK) {
  957. Free();
  958. return WW3D_ERROR_LOAD_FAILED;
  959. }
  960. /*
  961. ** Pull interesting stuff out of the w3d attributes bits
  962. */
  963. int col_bits = (Model->W3dAttributes & W3D_MESH_FLAG_COLLISION_TYPE_MASK) >> W3D_MESH_FLAG_COLLISION_TYPE_SHIFT;
  964. Set_Collision_Type( col_bits << 1 );
  965. Set_Hidden(Model->W3dAttributes & W3D_MESH_FLAG_HIDDEN);
  966. /*
  967. ** Indicate whether this mesh is translucent. The mesh is considered translucent
  968. ** if sorting has been enabled (alpha blending on pass 0) or if pass0 contains alpha-test.
  969. ** This flag is mainly being used by visibility preprocessing code in Renegade.
  970. */
  971. int is_translucent = Model->Get_Flag(MeshModelClass::SORT);
  972. if (Model->Has_Shader_Array(0)) {
  973. for (int i=0; i<Model->Get_Polygon_Count(); i++) {
  974. ShaderClass shader = Model->Get_Shader(i,0);
  975. is_translucent |= (shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_ENABLE);
  976. is_translucent |= (shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO);
  977. }
  978. } else {
  979. ShaderClass shader = Model->Get_Single_Shader(0);
  980. is_translucent |= (shader.Get_Alpha_Test() == ShaderClass::ALPHATEST_ENABLE);
  981. is_translucent |= (shader.Get_Dst_Blend_Func() != ShaderClass::DSTBLEND_ZERO);
  982. }
  983. Set_Translucent(is_translucent);
  984. return WW3D_ERROR_OK;
  985. }
  986. /***********************************************************************************************
  987. * MeshClass::Cast_Ray -- compute a ray intersection with this mesh *
  988. * *
  989. * INPUT: *
  990. * *
  991. * OUTPUT: *
  992. * *
  993. * WARNINGS: *
  994. * *
  995. * HISTORY: *
  996. * 6/17/98 GTH : Created. *
  997. *=============================================================================================*/
  998. bool MeshClass::Cast_Ray(RayCollisionTestClass & raytest)
  999. {
  1000. if ((Get_Collision_Type() & raytest.CollisionType) == 0) return false;
  1001. if (raytest.IgnoreTranslucentMeshes && Is_Translucent()!=0) return false;
  1002. if (Is_Animation_Hidden()) return false;
  1003. if (raytest.Result->StartBad) return false;
  1004. Matrix3D world_to_obj;
  1005. Matrix3D world=Get_Transform();
  1006. // if aligned or oriented rotate the mesh so that it's aligned to the ray
  1007. if (Model->Get_Flag(MeshModelClass::ALIGNED)) {
  1008. Vector3 mesh_position;
  1009. world.Get_Translation(&mesh_position);
  1010. world.Obj_Look_At(mesh_position,mesh_position - raytest.Ray.Get_Dir(),0.0f);
  1011. } else if (Model->Get_Flag(MeshModelClass::ORIENTED)) {
  1012. Vector3 mesh_position;
  1013. world.Get_Translation(&mesh_position);
  1014. world.Obj_Look_At(mesh_position,raytest.Ray.Get_P0(),0.0f);
  1015. }
  1016. world.Get_Orthogonal_Inverse(world_to_obj);
  1017. RayCollisionTestClass objray(raytest,world_to_obj);
  1018. WWASSERT(Model);
  1019. bool hit = Model->Cast_Ray(objray);
  1020. // transform result back into original coordinate system
  1021. if (hit) {
  1022. raytest.CollidedRenderObj = this;
  1023. Matrix3D::Rotate_Vector(world,raytest.Result->Normal, &(raytest.Result->Normal));
  1024. if (raytest.Result->ComputeContactPoint) {
  1025. Matrix3D::Transform_Vector(world,raytest.Result->ContactPoint, &(raytest.Result->ContactPoint));
  1026. }
  1027. }
  1028. return hit;
  1029. }
  1030. /***********************************************************************************************
  1031. * MeshClass::Cast_AABox -- cast an AABox against this mesh *
  1032. * *
  1033. * INPUT: *
  1034. * *
  1035. * OUTPUT: *
  1036. * *
  1037. * WARNINGS: *
  1038. * *
  1039. * HISTORY: *
  1040. * 6/17/98 GTH : Created. *
  1041. *=============================================================================================*/
  1042. bool MeshClass::Cast_AABox(AABoxCollisionTestClass & boxtest)
  1043. {
  1044. if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
  1045. if (boxtest.Result->StartBad) return false;
  1046. WWASSERT(Model);
  1047. // This function analyses the tranform to call optimized functions in certain cases
  1048. bool hit = Model->Cast_World_Space_AABox(boxtest, Get_Transform());
  1049. if (hit) {
  1050. boxtest.CollidedRenderObj = this;
  1051. }
  1052. return hit;
  1053. }
  1054. /***********************************************************************************************
  1055. * Cast_OBBox -- Cast an obbox against this mesh *
  1056. * *
  1057. * INPUT: *
  1058. * *
  1059. * OUTPUT: *
  1060. * *
  1061. * WARNINGS: *
  1062. * *
  1063. * HISTORY: *
  1064. * 6/17/98 GTH : Created. *
  1065. *=============================================================================================*/
  1066. bool MeshClass::Cast_OBBox(OBBoxCollisionTestClass & boxtest)
  1067. {
  1068. if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
  1069. if (boxtest.Result->StartBad) return false;
  1070. /*
  1071. ** transform into the local coordinate system of the mesh.
  1072. */
  1073. const Matrix3D & tm = Get_Transform();
  1074. Matrix3D world_to_obj;
  1075. tm.Get_Orthogonal_Inverse(world_to_obj);
  1076. OBBoxCollisionTestClass localtest(boxtest,world_to_obj);
  1077. WWASSERT(Model);
  1078. bool hit = Model->Cast_OBBox(localtest);
  1079. /*
  1080. ** If we hit, transform the result of the test back to the original coordinate system.
  1081. */
  1082. if (hit) {
  1083. boxtest.CollidedRenderObj = this;
  1084. Matrix3D::Rotate_Vector(tm,boxtest.Result->Normal, &(boxtest.Result->Normal));
  1085. if (boxtest.Result->ComputeContactPoint) {
  1086. Matrix3D::Transform_Vector(tm,boxtest.Result->ContactPoint, &(boxtest.Result->ContactPoint));
  1087. }
  1088. }
  1089. return hit;
  1090. }
  1091. /***********************************************************************************************
  1092. * MeshClass::Intersect_AABox -- test for intersection with given AABox *
  1093. * *
  1094. * The AAbox given is assumed to be in world space. Since meshes aren't generally in world *
  1095. * space, the test must be transformed into our local coordinate system (which turns it into *
  1096. * an OBBox...) *
  1097. * *
  1098. * INPUT: *
  1099. * *
  1100. * OUTPUT: *
  1101. * *
  1102. * WARNINGS: *
  1103. * *
  1104. * HISTORY: *
  1105. * 1/19/00 gth : Created. *
  1106. *=============================================================================================*/
  1107. bool MeshClass::Intersect_AABox(AABoxIntersectionTestClass & boxtest)
  1108. {
  1109. if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
  1110. Matrix3D inv_tm;
  1111. Get_Transform().Get_Orthogonal_Inverse(inv_tm);
  1112. OBBoxIntersectionTestClass local_test(boxtest,inv_tm);
  1113. WWASSERT(Model);
  1114. return Model->Intersect_OBBox(local_test);
  1115. }
  1116. /***********************************************************************************************
  1117. * MeshClass::Intersect_OBBox -- test for intersection with the given OBBox *
  1118. * *
  1119. * The given OBBox is assumed to be in world space so we need to transform it into the mesh's *
  1120. * local coordinate system. *
  1121. * *
  1122. * INPUT: *
  1123. * *
  1124. * OUTPUT: *
  1125. * *
  1126. * WARNINGS: *
  1127. * *
  1128. * HISTORY: *
  1129. * 1/19/00 gth : Created. *
  1130. *=============================================================================================*/
  1131. bool MeshClass::Intersect_OBBox(OBBoxIntersectionTestClass & boxtest)
  1132. {
  1133. if ((Get_Collision_Type() & boxtest.CollisionType) == 0) return false;
  1134. Matrix3D inv_tm;
  1135. Get_Transform().Get_Orthogonal_Inverse(inv_tm);
  1136. OBBoxIntersectionTestClass local_test(boxtest,inv_tm);
  1137. WWASSERT(Model);
  1138. return Model->Intersect_OBBox(local_test);
  1139. }
  1140. /***********************************************************************************************
  1141. * MeshClass::Get_Obj_Space_Bounding_Sphere -- returns obj-space bounding sphere *
  1142. * *
  1143. * INPUT: *
  1144. * *
  1145. * OUTPUT: *
  1146. * *
  1147. * WARNINGS: *
  1148. * *
  1149. * HISTORY: *
  1150. * 1/19/00 gth : Created. *
  1151. *=============================================================================================*/
  1152. void MeshClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
  1153. {
  1154. if (Model) {
  1155. Model->Get_Bounding_Sphere(&sphere);
  1156. } else {
  1157. sphere.Center.Set(0,0,0);
  1158. sphere.Radius = 1.0f;
  1159. }
  1160. }
  1161. /***********************************************************************************************
  1162. * MeshClass::Get_Obj_Space_Bounding_Box -- returns the obj-space bounding box *
  1163. * *
  1164. * INPUT: *
  1165. * *
  1166. * OUTPUT: *
  1167. * *
  1168. * WARNINGS: *
  1169. * *
  1170. * HISTORY: *
  1171. * 1/19/00 gth : Created. *
  1172. *=============================================================================================*/
  1173. void MeshClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  1174. {
  1175. if (Model) {
  1176. Model->Get_Bounding_Box(&box);
  1177. } else {
  1178. box.Init(Vector3(0,0,0),Vector3(1,1,1));
  1179. }
  1180. }
  1181. /***********************************************************************************************
  1182. * MeshClass::Generate_Culling_Tree -- Generates a hierarchical culling tree for the mesh *
  1183. * *
  1184. * INPUT: *
  1185. * *
  1186. * OUTPUT: *
  1187. * *
  1188. * WARNINGS: *
  1189. * *
  1190. * HISTORY: *
  1191. * 6/18/98 GTH : Created. *
  1192. *=============================================================================================*/
  1193. void MeshClass::Generate_Culling_Tree(void)
  1194. {
  1195. Model->Generate_Culling_Tree();
  1196. }
  1197. /***********************************************************************************************
  1198. * MeshClass::Add_Dependencies_To_List -- Add dependent files to the list. *
  1199. * *
  1200. * INPUT: *
  1201. * *
  1202. * OUTPUT: *
  1203. * *
  1204. * WARNINGS: *
  1205. * *
  1206. * HISTORY: *
  1207. * 3/18/99 PDS : Created. *
  1208. *=============================================================================================*/
  1209. void MeshClass::Add_Dependencies_To_List
  1210. (
  1211. DynamicVectorClass<StringClass> &file_list,
  1212. bool textures_only
  1213. )
  1214. {
  1215. //
  1216. // Get a pointer to this mesh's material information object
  1217. //
  1218. MaterialInfoClass *material = Get_Material_Info ();
  1219. if (material != NULL) {
  1220. //
  1221. // Loop through all the textures and add their filenames to our list
  1222. //
  1223. for (int index = 0; index < material->Texture_Count (); index ++) {
  1224. //
  1225. // Add this texture's filename to the list
  1226. //
  1227. TextureClass *texture = material->Peek_Texture (index);
  1228. if (texture != NULL) {
  1229. file_list.Add (texture->Get_Full_Path ());
  1230. }
  1231. }
  1232. //
  1233. // Release our hold on the material information object
  1234. //
  1235. material->Release_Ref ();
  1236. }
  1237. RenderObjClass::Add_Dependencies_To_List (file_list, textures_only);
  1238. return ;
  1239. }
  1240. /***********************************************************************************************
  1241. * MeshClass::Update_Cached_Bounding_Volumes -- default collision sphere. *
  1242. * *
  1243. * INPUT: *
  1244. * *
  1245. * OUTPUT: *
  1246. * *
  1247. * WARNINGS: *
  1248. * *
  1249. * HISTORY: *
  1250. * 5/14/2001 NH : Created. *
  1251. *=============================================================================================*/
  1252. void MeshClass::Update_Cached_Bounding_Volumes(void) const
  1253. {
  1254. Get_Obj_Space_Bounding_Sphere(CachedBoundingSphere);
  1255. CachedBoundingSphere.Center = Get_Transform() * CachedBoundingSphere.Center;
  1256. // If we are camera-aligned or -oriented, we don't know which way we are facing at this point,
  1257. // so the box we return needs to contain the sphere. Otherewise do the normal computation.
  1258. if (Model->Get_Flag(MeshModelClass::ALIGNED) || Model->Get_Flag(MeshModelClass::ORIENTED)) {
  1259. CachedBoundingBox.Center = CachedBoundingSphere.Center;
  1260. CachedBoundingBox.Extent.Set(CachedBoundingSphere.Radius, CachedBoundingSphere.Radius, CachedBoundingSphere.Radius);
  1261. } else {
  1262. Get_Obj_Space_Bounding_Box(CachedBoundingBox);
  1263. CachedBoundingBox.Transform(Get_Transform());
  1264. }
  1265. Validate_Cached_Bounding_Volumes();
  1266. }
  1267. // This utility function recurses throughout the subobjects of a renderobject, and for each
  1268. // MeshClass it finds it sets the given MeshModel flag on its model. This is useful for stuff
  1269. // like making a RenderObjects' polys sort.
  1270. void Set_MeshModel_Flag(RenderObjClass *robj, int flag, int onoff)
  1271. {
  1272. if (robj->Class_ID() == RenderObjClass::CLASSID_MESH) {
  1273. // Set flag on model (the assumption is that meshes don't have subobjects)
  1274. MeshClass *mesh = (MeshClass *)robj;
  1275. MeshModelClass *model = mesh->Get_Model();
  1276. model->Set_Flag((MeshModelClass::FlagsType)flag, onoff != 0);
  1277. model->Release_Ref();
  1278. } else {
  1279. // Recurse to subobjects (if any)
  1280. int num_obj = robj->Get_Num_Sub_Objects();
  1281. RenderObjClass *sub_obj;
  1282. for (int i = 0; i < num_obj; i++) {
  1283. sub_obj = robj->Get_Sub_Object(i);
  1284. if (sub_obj) {
  1285. Set_MeshModel_Flag(sub_obj, flag, onoff);
  1286. sub_obj->Release_Ref();
  1287. }
  1288. }
  1289. }
  1290. }
  1291. int MeshClass::Get_Sort_Level(void) const
  1292. {
  1293. if (Model) {
  1294. return (Model->Get_Sort_Level());
  1295. }
  1296. return(SORT_LEVEL_NONE);
  1297. }
  1298. void MeshClass::Set_Sort_Level(int level)
  1299. {
  1300. if (Model) {
  1301. Model->Set_Sort_Level(level);
  1302. }
  1303. }
  1304. unsigned int * MeshClass::Get_User_Lighting_Array(bool alloc)
  1305. {
  1306. if (alloc && (UserLighting == NULL)) {
  1307. UserLighting = new unsigned int[Model->Get_Vertex_Count()];
  1308. }
  1309. return UserLighting;
  1310. }
  1311. DX8FVFCategoryContainer* MeshClass::Peek_FVF_Category_Container()
  1312. {
  1313. if (PolygonRendererList.Is_Empty()) return NULL;
  1314. DX8PolygonRendererClass* polygon_renderer=PolygonRendererList.Get_Head();
  1315. WWASSERT(polygon_renderer);
  1316. DX8TextureCategoryClass* texture_category=polygon_renderer->Get_Texture_Category();
  1317. WWASSERT(texture_category);
  1318. DX8FVFCategoryContainer* fvf_category=texture_category->Get_Container();
  1319. WWASSERT(fvf_category);
  1320. return fvf_category;
  1321. }
  1322. void MeshClass::Install_User_Lighting_Array(Vector4 * lighting)
  1323. {
  1324. Get_User_Lighting_Array(true);
  1325. for (int vi=0; vi<Model->Get_Vertex_Count(); vi++) {
  1326. UserLighting[vi] = DX8Wrapper::Convert_Color(lighting[vi]);
  1327. }
  1328. setup_materials_for_user_lighting();
  1329. }
  1330. void MeshClass::setup_materials_for_user_lighting(void)
  1331. {
  1332. /*
  1333. ** Modify the vertex materials to use the solve if necessary
  1334. */
  1335. for (int pass=0; pass<Model->Get_Pass_Count(); pass++) {
  1336. if (Model->Has_Material_Array(pass)) {
  1337. int vidx = 0;
  1338. VertexMaterialClass * mtl = Model->Peek_Material(0,pass);
  1339. setup_material_for_user_lighting(mtl);
  1340. while (vidx < Model->Get_Vertex_Count()) {
  1341. VertexMaterialClass * next_mtl = Model->Peek_Material(vidx,pass);
  1342. if (next_mtl != mtl) {
  1343. setup_material_for_user_lighting(next_mtl);
  1344. mtl = next_mtl;
  1345. }
  1346. vidx++;
  1347. }
  1348. } else {
  1349. setup_material_for_user_lighting(Model->Peek_Single_Material(pass));
  1350. }
  1351. }
  1352. }
  1353. void MeshClass::setup_material_for_user_lighting(VertexMaterialClass * mtl)
  1354. {
  1355. // (gth) The terrain pre-lit stuff *must* use the diffuse and ambient arrays (to get vertex alpha
  1356. // working). So, for now we'll plug the color array into diffuse and ambient and the light
  1357. // environment will be set up so that ambient_light = 1,1,1
  1358. Vector3 emissive;
  1359. mtl->Get_Emissive(&emissive);
  1360. if (emissive == Vector3(0,0,0)) {
  1361. mtl->Set_Ambient_Color_Source(VertexMaterialClass::COLOR1);
  1362. mtl->Set_Diffuse_Color_Source(VertexMaterialClass::COLOR1);
  1363. }
  1364. }
  1365. void MeshClass::Save_User_Lighting (ChunkSaveClass & csave)
  1366. {
  1367. if (UserLighting != NULL) {
  1368. csave.Begin_Chunk(CHUNKID_USER_LIGHTING_ARRAY);
  1369. csave.Write(&(UserLighting[0]),Model->Get_Vertex_Count() * 4);
  1370. csave.End_Chunk();
  1371. }
  1372. }
  1373. void MeshClass::Load_User_Lighting (ChunkLoadClass & cload)
  1374. {
  1375. while (cload.Open_Chunk()) {
  1376. if ( (cload.Cur_Chunk_ID() == CHUNKID_USER_LIGHTING_ARRAY) &&
  1377. (cload.Cur_Chunk_Length() == (unsigned)(Model->Get_Vertex_Count() * 4)) )
  1378. {
  1379. unsigned int * lighting = Get_User_Lighting_Array(true);
  1380. cload.Read(lighting,Model->Get_Vertex_Count() * 4);
  1381. setup_materials_for_user_lighting();
  1382. }
  1383. cload.Close_Chunk();
  1384. }
  1385. Set_Has_User_Lighting(true);
  1386. }