dx8renderer.cpp 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284
  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/dx8renderer.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * Author : Kenny Mitchell *
  29. * *
  30. * $Modtime:: 06/27/02 1:27p $*
  31. * *
  32. * $Revision:: 111 $*
  33. * *
  34. * 06/27/02 KM Changes to max texture stage caps *
  35. *---------------------------------------------------------------------------------------------*
  36. * Functions: *
  37. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  38. //#define ENABLE_CATEGORY_LOG
  39. //#define ENABLE_STRIPING
  40. #include "dx8renderer.h"
  41. #include "dx8wrapper.h"
  42. #include "dx8polygonrenderer.h"
  43. #include "dx8vertexbuffer.h"
  44. #include "dx8indexbuffer.h"
  45. #include "dx8fvf.h"
  46. #include "dx8caps.h"
  47. #include "dx8rendererdebugger.h"
  48. #include "wwdebug.h"
  49. #include "wwprofile.h"
  50. #include "wwmemlog.h"
  51. #include "rinfo.h"
  52. #include "statistics.h"
  53. #include "meshmdl.h"
  54. #include "vp.h"
  55. #include "decalmsh.h"
  56. #include "matpass.h"
  57. #include "camera.h"
  58. #include "stripoptimizer.h"
  59. #include "meshgeometry.h"
  60. /*
  61. ** Global Instance of the DX8MeshRender
  62. */
  63. DX8MeshRendererClass TheDX8MeshRenderer;
  64. bool DX8TextureCategoryClass::m_gForceMultiply = false; // Forces opaque materials to use the multiply blend - pseudo transparent effect. jba.
  65. // ----------------------------------------------------------------------------
  66. static DynamicVectorClass<Vector3> _TempVertexBuffer;
  67. static DynamicVectorClass<Vector3> _TempNormalBuffer;
  68. static MultiListClass<MeshModelClass> _RegisteredMeshList;
  69. static TextureCategoryList texture_category_delete_list;
  70. static FVFCategoryList fvf_category_container_delete_list;
  71. // helper data structure
  72. class PolyRemover : public MultiListObjectClass
  73. {
  74. public:
  75. DX8TextureCategoryClass * src;
  76. DX8TextureCategoryClass * dest;
  77. DX8PolygonRendererClass * pr;
  78. };
  79. typedef MultiListClass<PolyRemover> PolyRemoverList;
  80. typedef MultiListIterator<PolyRemover> PolyRemoverListIterator;
  81. #define VERTEX_BUFFER_OVERFLOW 0xffff //'Generals' flag to signal when a mesh didn't fit in streaming vertex buffer.
  82. /**
  83. ** PolyRenderTaskClass
  84. ** This is a record of a polyrendere that needs to be rendered
  85. ** for this frame. Since MeshClass instances can share meshmodels
  86. ** (and therefore their dx8 polygon renderers) this record contains
  87. ** a pointer to the polygon renderer and the MeshClass instance that
  88. ** it is being rendered for.
  89. */
  90. class PolyRenderTaskClass : public AutoPoolClass<PolyRenderTaskClass, 256>
  91. {
  92. public:
  93. PolyRenderTaskClass(DX8PolygonRendererClass * p_renderer,MeshClass * p_mesh) :
  94. Renderer(p_renderer),
  95. Mesh(p_mesh),
  96. NextVisible(NULL)
  97. {
  98. WWASSERT(Renderer != NULL);
  99. WWASSERT(Mesh != NULL);
  100. Mesh->Add_Ref();
  101. }
  102. ~PolyRenderTaskClass(void)
  103. {
  104. Mesh->Release_Ref();
  105. }
  106. DX8PolygonRendererClass * Peek_Polygon_Renderer(void) { return Renderer; }
  107. MeshClass * Peek_Mesh(void) { return Mesh; }
  108. PolyRenderTaskClass * Get_Next_Visible(void) { return NextVisible; }
  109. void Set_Next_Visible(PolyRenderTaskClass * prtc) { NextVisible = prtc; }
  110. protected:
  111. DX8PolygonRendererClass * Renderer;
  112. MeshClass * Mesh;
  113. PolyRenderTaskClass * NextVisible;
  114. };
  115. DEFINE_AUTO_POOL(PolyRenderTaskClass, 256);
  116. /**
  117. ** MatPassTaskClass
  118. ** This is the record of a material pass that needs to be rendered on
  119. ** a particular mesh. These are linked into the FVF container which
  120. ** contains the mesh model. They are also pooled to remove memory
  121. ** allocation overhead.
  122. */
  123. class MatPassTaskClass : public AutoPoolClass<MatPassTaskClass, 256>
  124. {
  125. public:
  126. MatPassTaskClass(MaterialPassClass * pass,MeshClass * mesh) :
  127. MaterialPass(pass),
  128. Mesh(mesh),
  129. NextVisible(NULL)
  130. {
  131. WWASSERT(MaterialPass != NULL);
  132. WWASSERT(Mesh != NULL);
  133. MaterialPass->Add_Ref();
  134. Mesh->Add_Ref();
  135. }
  136. ~MatPassTaskClass(void)
  137. {
  138. MaterialPass->Release_Ref();
  139. Mesh->Release_Ref();
  140. }
  141. MaterialPassClass * Peek_Material_Pass(void) { return MaterialPass; }
  142. MeshClass * Peek_Mesh(void) { return Mesh; }
  143. MatPassTaskClass * Get_Next_Visible(void) { return NextVisible; }
  144. void Set_Next_Visible(MatPassTaskClass * mpr) { NextVisible = mpr; }
  145. private:
  146. MaterialPassClass * MaterialPass;
  147. MeshClass * Mesh;
  148. MatPassTaskClass * NextVisible;
  149. };
  150. DEFINE_AUTO_POOL(MatPassTaskClass, 256);
  151. // ----------------------------------------------------------------------------
  152. inline static bool Equal_Material(const VertexMaterialClass* mat1,const VertexMaterialClass* mat2)
  153. {
  154. int crc0 = mat1 ? mat1->Get_CRC() : 0;
  155. int crc1 = mat2 ? mat2->Get_CRC() : 0;
  156. return (crc0 == crc1);
  157. }
  158. DX8TextureCategoryClass::DX8TextureCategoryClass(
  159. DX8FVFCategoryContainer* container_,
  160. TextureClass** texs,
  161. ShaderClass shd,
  162. VertexMaterialClass* mat,
  163. int pass_)
  164. :
  165. pass(pass_),
  166. shader(shd),
  167. render_task_head(NULL),
  168. material(mat),
  169. container(container_)
  170. {
  171. WWASSERT(pass>=0);
  172. WWASSERT(pass<DX8FVFCategoryContainer::MAX_PASSES);
  173. for (int a=0;a<MeshMatDescClass::MAX_TEX_STAGES;++a)
  174. {
  175. textures[a]=NULL;
  176. REF_PTR_SET(textures[a],texs[a]);
  177. }
  178. if (material) material->Add_Ref();
  179. }
  180. DX8TextureCategoryClass::~DX8TextureCategoryClass()
  181. {
  182. // Unregistering the mesh where polygon renderers are connected to kills all polygon renderers
  183. while (DX8PolygonRendererClass* p_renderer=PolygonRendererList.Get_Head()) {
  184. TheDX8MeshRenderer.Unregister_Mesh_Type(p_renderer->Get_Mesh_Model_Class());
  185. }
  186. for (int a=0;a<MeshMatDescClass::MAX_TEX_STAGES;++a)
  187. {
  188. REF_PTR_RELEASE(textures[a]);
  189. }
  190. REF_PTR_RELEASE(material);
  191. }
  192. void DX8TextureCategoryClass::Add_Render_Task(DX8PolygonRendererClass * p_renderer,MeshClass * p_mesh)
  193. {
  194. PolyRenderTaskClass * new_prt = new PolyRenderTaskClass(p_renderer,p_mesh);
  195. new_prt->Set_Next_Visible(render_task_head);
  196. render_task_head = new_prt;
  197. container->Add_Visible_Texture_Category(this,pass);
  198. }
  199. void DX8TextureCategoryClass::Add_Polygon_Renderer(DX8PolygonRendererClass* p_renderer,DX8PolygonRendererClass* add_after_this)
  200. {
  201. WWASSERT(p_renderer!=NULL);
  202. WWASSERT(!PolygonRendererList.Contains(p_renderer));
  203. if (add_after_this != NULL) {
  204. bool res = PolygonRendererList.Add_After(p_renderer,add_after_this,false);
  205. WWASSERT(res != NULL);
  206. } else {
  207. PolygonRendererList.Add(p_renderer);
  208. }
  209. p_renderer->Set_Texture_Category(this);
  210. }
  211. void DX8TextureCategoryClass::Remove_Polygon_Renderer(DX8PolygonRendererClass* p_renderer)
  212. {
  213. PolygonRendererList.Remove(p_renderer);
  214. p_renderer->Set_Texture_Category(NULL);
  215. if (PolygonRendererList.Peek_Head() == NULL) {
  216. container->Remove_Texture_Category(this);
  217. texture_category_delete_list.Add_Tail(this);
  218. }
  219. }
  220. void DX8FVFCategoryContainer::Remove_Texture_Category(DX8TextureCategoryClass* tex_category)
  221. {
  222. for (unsigned pass=0;pass<passes;++pass) {
  223. texture_category_list[pass].Remove(tex_category);
  224. }
  225. for (pass=0; pass<passes; pass++) {
  226. // If any of the texture category lists has anything in it, no need to delete this container
  227. if (texture_category_list[pass].Peek_Head() != NULL) return;
  228. }
  229. fvf_category_container_delete_list.Add_Tail(this);
  230. }
  231. void DX8FVFCategoryContainer::Add_Visible_Material_Pass(MaterialPassClass * pass,MeshClass * mesh)
  232. {
  233. MatPassTaskClass * new_mpr = new MatPassTaskClass(pass,mesh);
  234. if (visible_matpass_head == NULL) {
  235. WWASSERT(visible_matpass_tail == NULL);
  236. visible_matpass_head = new_mpr;
  237. } else {
  238. WWASSERT(visible_matpass_tail != NULL);
  239. visible_matpass_tail->Set_Next_Visible(new_mpr);
  240. }
  241. visible_matpass_tail = new_mpr;
  242. AnythingToRender=true;
  243. }
  244. void DX8FVFCategoryContainer::Render_Procedural_Material_Passes(void)
  245. {
  246. // additional passes
  247. MatPassTaskClass * mpr = visible_matpass_head;
  248. MatPassTaskClass * last_mpr = NULL;
  249. bool renderTasksRemaining=false;
  250. while (mpr != NULL) {
  251. SNAPSHOT_SAY(("Render_Procedural_Material_Pass\n"));
  252. MeshClass * mesh = mpr->Peek_Mesh();
  253. if (mesh->Get_Base_Vertex_Offset() == VERTEX_BUFFER_OVERFLOW) //check if this mesh is valid
  254. { //skip this mesh so it gets rendered later after vertices are filled in.
  255. last_mpr = mpr;
  256. mpr = mpr->Get_Next_Visible();
  257. renderTasksRemaining = true;
  258. continue;
  259. }
  260. mpr->Peek_Mesh()->Render_Material_Pass(mpr->Peek_Material_Pass(),index_buffer);
  261. MatPassTaskClass * next_mpr = mpr->Get_Next_Visible();
  262. // remove from list, then delete
  263. if (last_mpr == NULL) {
  264. visible_matpass_head = next_mpr;
  265. } else {
  266. last_mpr->Set_Next_Visible(next_mpr);
  267. }
  268. delete mpr;
  269. mpr = next_mpr;
  270. }
  271. visible_matpass_tail = renderTasksRemaining ? last_mpr : NULL;
  272. }
  273. void DX8RigidFVFCategoryContainer::Add_Delayed_Visible_Material_Pass(MaterialPassClass * pass, MeshClass * mesh)
  274. {
  275. MatPassTaskClass * new_mpr = new MatPassTaskClass(pass,mesh);
  276. if (delayed_matpass_head == NULL) {
  277. WWASSERT(delayed_matpass_tail == NULL);
  278. delayed_matpass_head = new_mpr;
  279. } else {
  280. WWASSERT(delayed_matpass_tail != NULL);
  281. delayed_matpass_tail->Set_Next_Visible(new_mpr);
  282. }
  283. delayed_matpass_tail = new_mpr;
  284. AnyDelayedPassesToRender=true;
  285. }
  286. void DX8RigidFVFCategoryContainer::Render_Delayed_Procedural_Material_Passes(void)
  287. {
  288. if (!Any_Delayed_Passes_To_Render()) return;
  289. AnyDelayedPassesToRender=false;
  290. DX8Wrapper::Set_Vertex_Buffer(vertex_buffer);
  291. DX8Wrapper::Set_Index_Buffer(index_buffer,0);
  292. SNAPSHOT_SAY(("DX8RigidFVFCategoryContainer::Render_Delayed_Procedural_Material_Passes()\n"));
  293. // additional passes
  294. MatPassTaskClass * mpr = delayed_matpass_head;
  295. while (mpr != NULL) {
  296. mpr->Peek_Mesh()->Render_Material_Pass(mpr->Peek_Material_Pass(),index_buffer);
  297. MatPassTaskClass * next_mpr = mpr->Get_Next_Visible();
  298. delete mpr;
  299. mpr = next_mpr;
  300. }
  301. delayed_matpass_head = delayed_matpass_tail = NULL;
  302. }
  303. void DX8TextureCategoryClass::Log(bool only_visible)
  304. {
  305. #ifdef ENABLE_CATEGORY_LOG
  306. StringClass work(255,true);
  307. work.Format(" DX8TextureCategoryClass\n");
  308. WWDEBUG_SAY((work));
  309. StringClass work2(255,true);
  310. for (int stage=0;stage<MeshMatDescClass::MAX_TEX_STAGES;++stage) {
  311. work2.Format(" texture[%d]: %x (%s)\n", stage, textures[stage], textures[stage] ? textures[stage]->Get_Name() : "-");
  312. work+=work2;
  313. }
  314. work2.Format(" material: %x (%s)\n shader: %x\n", material, material ? material->Get_Name() : "-", shader);
  315. work+=work2;
  316. WWDEBUG_SAY((work));
  317. work.Format(" %8s %8s %6s %6s %6s %5s %s\n",
  318. "idx_cnt",
  319. "poly_cnt",
  320. "i_offs",
  321. "min_vi",
  322. "vi_rng",
  323. "ident",
  324. "name");
  325. WWDEBUG_SAY((work));
  326. DX8PolygonRendererListIterator it(&PolygonRendererList);
  327. while (!it.Is_Done()) {
  328. DX8PolygonRendererClass* p_renderer = it.Peek_Obj();
  329. PolyRenderTaskClass * prtc=render_task_head;
  330. while (prtc) {
  331. if (prtc->Peek_Polygon_Renderer()==p_renderer) break;
  332. prtc = prtc->Get_Next_Visible();
  333. }
  334. if (prtc != NULL) {
  335. WWDEBUG_SAY(("+"));
  336. p_renderer->Log();
  337. } else {
  338. if (!only_visible) {
  339. WWDEBUG_SAY(("-"));
  340. p_renderer->Log();
  341. }
  342. }
  343. it.Next();
  344. }
  345. #endif
  346. }
  347. // ----------------------------------------------------------------------------
  348. DX8FVFCategoryContainer::DX8FVFCategoryContainer(unsigned FVF_,bool sorting_)
  349. :
  350. FVF(FVF_),
  351. sorting(sorting_),
  352. visible_matpass_head(NULL),
  353. visible_matpass_tail(NULL),
  354. index_buffer(0),
  355. used_indices(0),
  356. passes(MAX_PASSES),
  357. uv_coordinate_channels(0),
  358. AnythingToRender(false),
  359. AnyDelayedPassesToRender(false)
  360. {
  361. if ((FVF&D3DFVF_TEX1)==D3DFVF_TEX1) uv_coordinate_channels=1;
  362. if ((FVF&D3DFVF_TEX2)==D3DFVF_TEX2) uv_coordinate_channels=2;
  363. if ((FVF&D3DFVF_TEX3)==D3DFVF_TEX3) uv_coordinate_channels=3;
  364. if ((FVF&D3DFVF_TEX4)==D3DFVF_TEX4) uv_coordinate_channels=4;
  365. if ((FVF&D3DFVF_TEX5)==D3DFVF_TEX5) uv_coordinate_channels=5;
  366. if ((FVF&D3DFVF_TEX6)==D3DFVF_TEX6) uv_coordinate_channels=6;
  367. if ((FVF&D3DFVF_TEX7)==D3DFVF_TEX7) uv_coordinate_channels=7;
  368. if ((FVF&D3DFVF_TEX8)==D3DFVF_TEX8) uv_coordinate_channels=8;
  369. }
  370. // ----------------------------------------------------------------------------
  371. DX8FVFCategoryContainer::~DX8FVFCategoryContainer()
  372. {
  373. REF_PTR_RELEASE(index_buffer);
  374. for (unsigned p=0;p<passes;++p) {
  375. while (DX8TextureCategoryClass * tex = texture_category_list[p].Remove_Head()) {
  376. delete tex;
  377. }
  378. }
  379. }
  380. // ----------------------------------------------------------------------------
  381. DX8TextureCategoryClass* DX8FVFCategoryContainer::Find_Matching_Texture_Category(
  382. TextureClass* texture,
  383. unsigned pass,
  384. unsigned stage,
  385. DX8TextureCategoryClass* ref_category)
  386. {
  387. // Find texture category which matches ref_category's properties but has 'texture' on given pass and stage.
  388. DX8TextureCategoryClass* dest_tex_category=NULL;
  389. TextureCategoryListIterator dest_it(&texture_category_list[pass]);
  390. while (!dest_it.Is_Done()) {
  391. if (dest_it.Peek_Obj()->Peek_Texture(stage)==texture) {
  392. // Compare all stage's textures
  393. dest_tex_category=dest_it.Peek_Obj();
  394. bool all_textures_same = true;
  395. for (unsigned int s = 0; s < MeshMatDescClass::MAX_TEX_STAGES; s++) {
  396. if (stage!=s) {
  397. all_textures_same = all_textures_same && (dest_tex_category->Peek_Texture(s) == ref_category->Peek_Texture(s));
  398. }
  399. }
  400. if (all_textures_same &&
  401. Equal_Material(dest_tex_category->Peek_Material(),ref_category->Peek_Material()) &&
  402. dest_tex_category->Get_Shader()==ref_category->Get_Shader()) {
  403. return dest_tex_category;
  404. }
  405. }
  406. dest_it.Next();
  407. }
  408. return NULL;
  409. }
  410. DX8TextureCategoryClass* DX8FVFCategoryContainer::Find_Matching_Texture_Category(
  411. VertexMaterialClass* vmat,
  412. unsigned pass,
  413. DX8TextureCategoryClass* ref_category)
  414. {
  415. // Find texture category which matches ref_category's properties but has 'vmat' on given pass
  416. DX8TextureCategoryClass* dest_tex_category=NULL;
  417. TextureCategoryListIterator dest_it(&texture_category_list[pass]);
  418. while (!dest_it.Is_Done()) {
  419. if (Equal_Material(dest_it.Peek_Obj()->Peek_Material(),vmat)) {
  420. // Compare all stage's textures
  421. dest_tex_category=dest_it.Peek_Obj();
  422. bool all_textures_same = true;
  423. for (unsigned int s = 0; s < MeshMatDescClass::MAX_TEX_STAGES; s++)
  424. all_textures_same = all_textures_same && (dest_tex_category->Peek_Texture(s) == ref_category->Peek_Texture(s));
  425. if (all_textures_same &&
  426. dest_tex_category->Get_Shader()==ref_category->Get_Shader()) {
  427. return dest_tex_category;
  428. }
  429. }
  430. dest_it.Next();
  431. }
  432. return NULL;
  433. }
  434. void DX8FVFCategoryContainer::Change_Polygon_Renderer_Texture(
  435. DX8PolygonRendererList& polygon_renderer_list,
  436. TextureClass* texture,
  437. TextureClass* new_texture,
  438. unsigned pass,
  439. unsigned stage)
  440. {
  441. WWASSERT(pass<passes);
  442. PolyRemoverList prl;
  443. bool foundtexture=false;
  444. if (texture==new_texture) return;
  445. // Find source texture category, then find all polygon renderers who belong to that category
  446. // and move them to destination category.
  447. TextureCategoryListIterator src_it(&texture_category_list[pass]);
  448. while (!src_it.Is_Done()) {
  449. DX8TextureCategoryClass* src_tex_category=src_it.Peek_Obj();
  450. if (src_tex_category->Peek_Texture(stage)==texture) {
  451. foundtexture=true;
  452. DX8PolygonRendererListIterator poly_it(&polygon_renderer_list);
  453. while (!poly_it.Is_Done()) {
  454. // If source texture category contains polygon renderer, move to destination category
  455. DX8PolygonRendererClass* polygon_renderer=poly_it.Peek_Obj();
  456. DX8TextureCategoryClass *prc=polygon_renderer->Get_Texture_Category();
  457. if (prc==src_tex_category) {
  458. DX8TextureCategoryClass* dest_tex_category=Find_Matching_Texture_Category(new_texture,pass,stage,src_tex_category);
  459. if (!dest_tex_category) {
  460. TextureClass * tmp_textures[MeshMatDescClass::MAX_TEX_STAGES];
  461. for (int s=0;s<MeshMatDescClass::MAX_TEX_STAGES;++s) {
  462. tmp_textures[s]=src_tex_category->Peek_Texture(s);
  463. }
  464. tmp_textures[stage]=new_texture;
  465. DX8TextureCategoryClass * new_tex_category=W3DNEW DX8TextureCategoryClass(
  466. this,
  467. tmp_textures,
  468. src_tex_category->Get_Shader(),
  469. const_cast<VertexMaterialClass*>(src_tex_category->Peek_Material()),
  470. pass);
  471. /*
  472. ** Add the texture category object into the list, immediately after any existing
  473. ** texture category object which uses the same texture. This will result in
  474. ** the list always having matching texture categories next to each other.
  475. */
  476. bool found_similar_category = false;
  477. TextureCategoryListIterator tex_it(&texture_category_list[pass]);
  478. while (!tex_it.Is_Done()) {
  479. // Categorize according to first stage's texture for now
  480. if (tex_it.Peek_Obj()->Peek_Texture(0) == tmp_textures[0]) {
  481. texture_category_list[pass].Add_After(new_tex_category,tex_it.Peek_Obj());
  482. found_similar_category = true;
  483. break;
  484. }
  485. tex_it.Next();
  486. }
  487. if (!found_similar_category) {
  488. texture_category_list[pass].Add_Tail(new_tex_category);
  489. }
  490. dest_tex_category=new_tex_category;
  491. }
  492. PolyRemover *rem=W3DNEW PolyRemover;
  493. rem->src=src_tex_category;
  494. rem->dest=dest_tex_category;
  495. rem->pr=polygon_renderer;
  496. prl.Add(rem);
  497. }
  498. poly_it.Next();
  499. } // while
  500. } //if src_texture==texture
  501. else
  502. // quit loop if we've got a texture change
  503. if (foundtexture) break;
  504. src_it.Next();
  505. } // while
  506. PolyRemoverListIterator prli(&prl);
  507. while (!prli.Is_Done())
  508. {
  509. PolyRemover *rem=prli.Peek_Obj();
  510. rem->src->Remove_Polygon_Renderer(rem->pr);
  511. rem->dest->Add_Polygon_Renderer(rem->pr);
  512. prli.Remove_Current_Object();
  513. delete rem;
  514. }
  515. }
  516. void DX8FVFCategoryContainer::Change_Polygon_Renderer_Material(
  517. DX8PolygonRendererList& polygon_renderer_list,
  518. VertexMaterialClass* vmat,
  519. VertexMaterialClass* new_vmat,
  520. unsigned pass)
  521. {
  522. WWASSERT(pass<passes);
  523. PolyRemoverList prl;
  524. bool foundtexture=false;
  525. if (vmat==new_vmat) return;
  526. // Find source texture category, then find all polygon renderers who belong to that category
  527. // and move them to destination category.
  528. TextureCategoryListIterator src_it(&texture_category_list[pass]);
  529. while (!src_it.Is_Done()) {
  530. DX8TextureCategoryClass* src_tex_category=src_it.Peek_Obj();
  531. if (src_tex_category->Peek_Material()==vmat) {
  532. DX8PolygonRendererListIterator poly_it(&polygon_renderer_list);
  533. while (!poly_it.Is_Done()) {
  534. // If source texture category contains polygon renderer, move to destination category
  535. DX8PolygonRendererClass* polygon_renderer=poly_it.Peek_Obj();
  536. DX8TextureCategoryClass *prc=polygon_renderer->Get_Texture_Category();
  537. if (prc==src_tex_category) {
  538. foundtexture=true;
  539. DX8TextureCategoryClass* dest_tex_category=Find_Matching_Texture_Category(new_vmat,pass,src_tex_category);
  540. if (!dest_tex_category) {
  541. TextureClass * tmp_textures[MeshMatDescClass::MAX_TEX_STAGES];
  542. for (int s=0;s<MeshMatDescClass::MAX_TEX_STAGES;++s) {
  543. tmp_textures[s]=src_tex_category->Peek_Texture(s);
  544. }
  545. DX8TextureCategoryClass * new_tex_category=W3DNEW DX8TextureCategoryClass(
  546. this,
  547. tmp_textures,
  548. src_tex_category->Get_Shader(),
  549. const_cast<VertexMaterialClass*>(new_vmat),
  550. pass);
  551. /*
  552. ** Add the texture category object into the list, immediately after any existing
  553. ** texture category object which uses the same texture. This will result in
  554. ** the list always having matching texture categories next to each other.
  555. */
  556. bool found_similar_category = false;
  557. TextureCategoryListIterator tex_it(&texture_category_list[pass]);
  558. while (!tex_it.Is_Done()) {
  559. // Categorize according to first stage's texture for now
  560. if (tex_it.Peek_Obj()->Peek_Texture(0) == tmp_textures[0]) {
  561. texture_category_list[pass].Add_After(new_tex_category,tex_it.Peek_Obj());
  562. found_similar_category = true;
  563. break;
  564. }
  565. tex_it.Next();
  566. }
  567. if (!found_similar_category) {
  568. texture_category_list[pass].Add_Tail(new_tex_category);
  569. }
  570. dest_tex_category=new_tex_category;
  571. }
  572. PolyRemover *rem=W3DNEW PolyRemover;
  573. rem->src=src_tex_category;
  574. rem->dest=dest_tex_category;
  575. rem->pr=polygon_renderer;
  576. prl.Add(rem);
  577. }
  578. poly_it.Next();
  579. } // while
  580. } // if
  581. else
  582. if (foundtexture) break;
  583. src_it.Next();
  584. } // while
  585. PolyRemoverListIterator prli(&prl);
  586. while (!prli.Is_Done())
  587. {
  588. PolyRemover *rem=prli.Peek_Obj();
  589. rem->src->Remove_Polygon_Renderer(rem->pr);
  590. rem->dest->Add_Polygon_Renderer(rem->pr);
  591. prli.Remove_Current_Object();
  592. delete rem;
  593. }
  594. }
  595. // ----------------------------------------------------------------------------
  596. unsigned DX8FVFCategoryContainer::Define_FVF(MeshModelClass* mmc,bool enable_lighting)
  597. {
  598. if ((!!mmc->Get_Flag(MeshGeometryClass::SORT)) && WW3D::Is_Sorting_Enabled()) {
  599. return dynamic_fvf_type;
  600. }
  601. unsigned fvf=D3DFVF_XYZ;
  602. int tex_coord_count=mmc->Get_UV_Array_Count();
  603. if (mmc->Get_Color_Array(0,false)) {
  604. fvf|=D3DFVF_DIFFUSE;
  605. }
  606. if (mmc->Get_Color_Array(1,false)) {
  607. fvf|=D3DFVF_SPECULAR;
  608. }
  609. switch (tex_coord_count) {
  610. default:
  611. case 0:
  612. break;
  613. case 1: fvf|=D3DFVF_TEX1; break;
  614. case 2: fvf|=D3DFVF_TEX2; break;
  615. case 3: fvf|=D3DFVF_TEX3; break;
  616. case 4: fvf|=D3DFVF_TEX4; break;
  617. case 5: fvf|=D3DFVF_TEX5; break;
  618. case 6: fvf|=D3DFVF_TEX6; break;
  619. case 7: fvf|=D3DFVF_TEX7; break;
  620. case 8: fvf|=D3DFVF_TEX8; break;
  621. }
  622. if (!mmc->Needs_Vertex_Normals()) { //enable_lighting || mmc->Get_Flag(MeshModelClass::PRELIT_MASK)) {
  623. return fvf;
  624. }
  625. fvf|=D3DFVF_NORMAL; // Realtime-lit
  626. return fvf;
  627. }
  628. // ----------------------------------------------------------------------------
  629. DX8RigidFVFCategoryContainer::DX8RigidFVFCategoryContainer(unsigned FVF,bool sorting_)
  630. :
  631. DX8FVFCategoryContainer(FVF,sorting_),
  632. vertex_buffer(0),
  633. used_vertices(0),
  634. delayed_matpass_head(NULL),
  635. delayed_matpass_tail(NULL)
  636. {
  637. }
  638. // ----------------------------------------------------------------------------
  639. DX8RigidFVFCategoryContainer::~DX8RigidFVFCategoryContainer()
  640. {
  641. REF_PTR_RELEASE(vertex_buffer);
  642. }
  643. // ----------------------------------------------------------------------------
  644. void DX8RigidFVFCategoryContainer::Log(bool only_visible)
  645. {
  646. #ifdef ENABLE_CATEGORY_LOG
  647. StringClass work(255,true);
  648. work.Format("DX8RigidFVFCategoryContainer --------------\n");
  649. WWDEBUG_SAY((work));
  650. if (vertex_buffer) {
  651. StringClass fvfname(255,true);
  652. vertex_buffer->FVF_Info().Get_FVF_Name(fvfname);
  653. work.Format("VB size (used/total): %d/%d FVF: %s\n",used_vertices,vertex_buffer->Get_Vertex_Count(),fvfname);
  654. WWDEBUG_SAY((work));
  655. }
  656. else {
  657. WWDEBUG_SAY(("EMPTY VB\n"));
  658. }
  659. if (index_buffer) {
  660. work.Format("IB size (used/total): %d/%d\n",used_indices,index_buffer->Get_Index_Count());
  661. WWDEBUG_SAY((work));
  662. }
  663. else {
  664. WWDEBUG_SAY(("EMPTY IB\n"));
  665. }
  666. for (unsigned p=0;p<passes;++p) {
  667. WWDEBUG_SAY(("Pass: %d\n",p));
  668. TextureCategoryListIterator it(&texture_category_list[p]);
  669. while (!it.Is_Done()) {
  670. it.Peek_Obj()->Log(only_visible);
  671. it.Next();
  672. }
  673. }
  674. #endif
  675. }
  676. // ----------------------------------------------------------------------------
  677. //
  678. // Generic render function for rigid meshes
  679. //
  680. // ----------------------------------------------------------------------------
  681. void DX8RigidFVFCategoryContainer::Render(void)
  682. {
  683. if (!Anything_To_Render()) return;
  684. AnythingToRender=false;
  685. DX8Wrapper::Set_Vertex_Buffer(vertex_buffer);
  686. DX8Wrapper::Set_Index_Buffer(index_buffer,0);
  687. SNAPSHOT_SAY(("DX8RigidFVFCategoryContainer::Render()\n"));
  688. // The Z-biasing was causing more problems than they solved.
  689. // Disabling it for now HY.
  690. //int zbias=0;
  691. //DX8Wrapper::Set_DX8_ZBias(zbias);
  692. for (unsigned p=0;p<passes;++p) {
  693. SNAPSHOT_SAY(("Pass: %d\n",p));
  694. while (DX8TextureCategoryClass * tex = visible_texture_category_list[p].Remove_Head()) {
  695. tex->Render();
  696. }
  697. //zbias++;
  698. //if (zbias>15) zbias=15;
  699. //DX8Wrapper::Set_DX8_ZBias(zbias);
  700. }
  701. Render_Procedural_Material_Passes();
  702. //DX8Wrapper::Set_DX8_ZBias(0);
  703. }
  704. // ----------------------------------------------------------------------------
  705. bool DX8RigidFVFCategoryContainer::Check_If_Mesh_Fits(MeshModelClass* mmc)
  706. {
  707. if (!vertex_buffer) return true; // No VB created - mesh will fit as a new vb will be created when inserting
  708. unsigned required_vertices=mmc->Get_Vertex_Count();
  709. unsigned available_vertices=vertex_buffer->Get_Vertex_Count()-used_vertices;
  710. unsigned required_polygons=mmc->Get_Polygon_Count();
  711. if (mmc->Get_Gap_Filler()) {
  712. required_polygons+=mmc->Get_Gap_Filler()->Get_Polygon_Count();
  713. }
  714. unsigned required_indices=required_polygons*3*mmc->Get_Pass_Count();
  715. unsigned available_indices=index_buffer->Get_Index_Count()-used_indices;
  716. if (
  717. required_vertices<=available_vertices &&
  718. (required_indices)<=available_indices) {
  719. return true;
  720. }
  721. return false;
  722. }
  723. // ----------------------------------------------------------------------------
  724. class Vertex_Split_Table
  725. {
  726. MeshModelClass* mmc;
  727. bool npatch_enable;
  728. unsigned polygon_count;
  729. TriIndex* polygon_array;
  730. bool allocated_polygon_array;
  731. public:
  732. Vertex_Split_Table(MeshModelClass* mmc_)
  733. :
  734. mmc(mmc_),
  735. npatch_enable(false),
  736. allocated_polygon_array(false)
  737. {
  738. if (DX8Wrapper::Get_Current_Caps()->Support_NPatches() && mmc->Needs_Vertex_Normals()) {
  739. if (mmc->Get_Flag(MeshGeometryClass::ALLOW_NPATCHES)) {
  740. npatch_enable=true;
  741. }
  742. }
  743. const GapFillerClass* gap_filler=mmc->Get_Gap_Filler();
  744. polygon_count=mmc->Get_Polygon_Count();
  745. if (gap_filler) polygon_count+=gap_filler->Get_Polygon_Count();
  746. // if (mmc->Get_Gap_Filler_Polygon_Count()) {
  747. allocated_polygon_array=true;
  748. polygon_array=W3DNEWARRAY TriIndex[polygon_count];
  749. memcpy(
  750. polygon_array,
  751. mmc->Get_Polygon_Array(),
  752. mmc->Get_Polygon_Count()*sizeof(TriIndex));
  753. if (gap_filler) {
  754. memcpy(
  755. polygon_array+mmc->Get_Polygon_Count(),
  756. gap_filler->Get_Polygon_Array(),
  757. gap_filler->Get_Polygon_Count()*sizeof(TriIndex));
  758. }
  759. // }
  760. // else {
  761. // polygon_array=const_cast<TriIndex*>(mmc->Get_Polygon_Array());
  762. // }
  763. }
  764. ~Vertex_Split_Table()
  765. {
  766. if (allocated_polygon_array) {
  767. delete[] polygon_array;
  768. }
  769. }
  770. const Vector3* Get_Vertex_Array() const
  771. {
  772. return mmc->Get_Vertex_Array();
  773. }
  774. const Vector3* Get_Vertex_Normal_Array() const
  775. {
  776. return mmc->Get_Vertex_Normal_Array();
  777. }
  778. const unsigned* Get_Color_Array(unsigned index) const
  779. {
  780. return mmc->Get_Color_Array(index,false);
  781. }
  782. const Vector2* Get_UV_Array(unsigned uv_array_index) const
  783. {
  784. return mmc->Get_UV_Array_By_Index(uv_array_index);
  785. }
  786. unsigned Get_Vertex_Count() const
  787. {
  788. return mmc->Get_Vertex_Count();
  789. }
  790. unsigned Get_Polygon_Count() const
  791. {
  792. return polygon_count;
  793. }
  794. unsigned Get_Pass_Count() const
  795. {
  796. return mmc->Get_Pass_Count();
  797. }
  798. TextureClass* Peek_Texture(unsigned idx,unsigned pass,unsigned stage)
  799. {
  800. if (mmc->Has_Texture_Array(pass,stage)) {
  801. if (idx>=unsigned(mmc->Get_Polygon_Count())) {
  802. WWASSERT(mmc->Get_Gap_Filler());
  803. return mmc->Get_Gap_Filler()->Get_Texture_Array(pass,stage)[idx-mmc->Get_Polygon_Count()];
  804. }
  805. return mmc->Peek_Texture(idx,pass,stage);
  806. }
  807. return mmc->Peek_Single_Texture(pass,stage);
  808. }
  809. VertexMaterialClass* Peek_Material(unsigned idx,unsigned pass)
  810. {
  811. if (mmc->Has_Material_Array(pass)) {
  812. if (idx>=unsigned(mmc->Get_Polygon_Count())) {
  813. WWASSERT(mmc->Get_Gap_Filler());
  814. return mmc->Get_Gap_Filler()->Get_Material_Array(pass)[idx-mmc->Get_Polygon_Count()];
  815. }
  816. return mmc->Peek_Material(mmc->Get_Polygon_Array()[idx][0],pass);
  817. }
  818. return mmc->Peek_Single_Material(pass);
  819. }
  820. ShaderClass Peek_Shader(unsigned idx,unsigned pass)
  821. {
  822. if (mmc->Has_Shader_Array(pass)) {
  823. ShaderClass shader;
  824. if (idx>=unsigned(mmc->Get_Polygon_Count())) {
  825. WWASSERT(mmc->Get_Gap_Filler());
  826. shader=mmc->Get_Gap_Filler()->Get_Shader_Array(pass)[idx-mmc->Get_Polygon_Count()];
  827. }
  828. else shader=mmc->Get_Shader(idx,pass);
  829. if (npatch_enable) {
  830. shader.Set_NPatch_Enable(ShaderClass::NPATCH_ENABLE);
  831. }
  832. return shader;
  833. }
  834. if (!npatch_enable) return mmc->Get_Single_Shader(pass);
  835. ShaderClass shader=mmc->Get_Single_Shader(pass);
  836. shader.Set_NPatch_Enable(ShaderClass::NPATCH_ENABLE);
  837. return shader;
  838. }
  839. MeshModelClass* Get_Mesh_Model_Class()
  840. {
  841. return mmc;
  842. }
  843. unsigned short* Get_Polygon_Array(unsigned pass)
  844. {
  845. return (unsigned short*)polygon_array;
  846. }
  847. };
  848. // ----------------------------------------------------------------------------
  849. void DX8RigidFVFCategoryContainer::Add_Mesh(MeshModelClass* mmc_)
  850. {
  851. WWASSERT(Check_If_Mesh_Fits(mmc_));
  852. Vertex_Split_Table split_table(mmc_);
  853. int needed_vertices=split_table.Get_Vertex_Count();
  854. /*
  855. ** This FVFCategoryContainer doesn't have a vertex buffer yet so allocate one big
  856. ** enough to contain this mesh.
  857. */
  858. if (!vertex_buffer) {
  859. int vb_size=4000;
  860. if (vb_size<needed_vertices) vb_size=needed_vertices;
  861. if (sorting) {
  862. vertex_buffer=NEW_REF(SortingVertexBufferClass,(vb_size));
  863. WWASSERT(vertex_buffer->FVF_Info().Get_FVF()==FVF); // Only one sorting FVF type!
  864. }
  865. else {
  866. vertex_buffer=NEW_REF(DX8VertexBufferClass,(
  867. FVF,
  868. vb_size,
  869. (DX8Wrapper::Get_Current_Caps()->Support_NPatches() && WW3D::Get_NPatches_Level()>1) ? DX8VertexBufferClass::USAGE_NPATCHES : DX8VertexBufferClass::USAGE_DEFAULT));
  870. }
  871. }
  872. /*
  873. ** Append this mesh's vertices to the vertex buffer.
  874. */
  875. VertexBufferClass::AppendLockClass l(vertex_buffer,used_vertices,split_table.Get_Vertex_Count());
  876. const FVFInfoClass fi=vertex_buffer->FVF_Info();
  877. unsigned char *vb=(unsigned char*) l.Get_Vertex_Array();
  878. unsigned int i;
  879. const Vector3 *locs=split_table.Get_Vertex_Array();
  880. const Vector3 *norms=split_table.Get_Vertex_Normal_Array();
  881. const unsigned *diffuse=split_table.Get_Color_Array(0);
  882. const unsigned *specular=split_table.Get_Color_Array(1);
  883. for (i=0; i<split_table.Get_Vertex_Count(); i++)
  884. {
  885. *(Vector3*)(vb+fi.Get_Location_Offset())=locs[i];
  886. if ((FVF&D3DFVF_NORMAL)==D3DFVF_NORMAL && norms) {
  887. *(Vector3*)(vb+fi.Get_Normal_Offset())=norms[i];
  888. }
  889. if ((FVF&D3DFVF_DIFFUSE)==D3DFVF_DIFFUSE) {
  890. if (diffuse) {
  891. *(unsigned int*)(vb+fi.Get_Diffuse_Offset())=diffuse[i];
  892. } else {
  893. *(unsigned int*)(vb+fi.Get_Diffuse_Offset()) = 0xFFFFFFFF;
  894. }
  895. }
  896. if ((FVF&D3DFVF_SPECULAR)==D3DFVF_SPECULAR) {
  897. if (specular) {
  898. *(unsigned int*)(vb+fi.Get_Specular_Offset())=specular[i];
  899. } else {
  900. *(unsigned int*)(vb+fi.Get_Specular_Offset()) = 0xFFFFFFFF;
  901. }
  902. }
  903. vb+=fi.Get_FVF_Size();
  904. }
  905. /*
  906. ** Append the UV coordinates to the vertex buffer
  907. */
  908. int uvcount = 0;
  909. if ((FVF&D3DFVF_TEX1) == D3DFVF_TEX1) {
  910. uvcount = 1;
  911. }
  912. if ((FVF&D3DFVF_TEX2) == D3DFVF_TEX2) {
  913. uvcount = 2;
  914. }
  915. if ((FVF&D3DFVF_TEX3) == D3DFVF_TEX3) {
  916. uvcount = 3;
  917. }
  918. if ((FVF&D3DFVF_TEX4) == D3DFVF_TEX4) {
  919. uvcount = 4;
  920. }
  921. if ((FVF&D3DFVF_TEX5) == D3DFVF_TEX5) {
  922. uvcount = 5;
  923. }
  924. if ((FVF&D3DFVF_TEX6) == D3DFVF_TEX6) {
  925. uvcount = 6;
  926. }
  927. if ((FVF&D3DFVF_TEX7) == D3DFVF_TEX7) {
  928. uvcount = 7;
  929. }
  930. if ((FVF&D3DFVF_TEX8) == D3DFVF_TEX8) {
  931. uvcount = 8;
  932. }
  933. for (int j=0; j<uvcount; j++) {
  934. unsigned char *vb=(unsigned char*) l.Get_Vertex_Array();
  935. const Vector2*uvs=split_table.Get_UV_Array(j);
  936. if (uvs) {
  937. for (i=0; i<split_table.Get_Vertex_Count(); i++)
  938. {
  939. *(Vector2*)(vb+fi.Get_Tex_Offset(j))=uvs[i];
  940. vb+=fi.Get_FVF_Size();
  941. }
  942. }
  943. }
  944. Generate_Texture_Categories(split_table,used_vertices);
  945. used_vertices+=needed_vertices;//vertex_count;
  946. }
  947. void DX8FVFCategoryContainer::Insert_To_Texture_Category(
  948. Vertex_Split_Table& split_table,
  949. TextureClass** texs,
  950. VertexMaterialClass* mat,
  951. ShaderClass shader,
  952. int pass,
  953. unsigned vertex_offset)
  954. {
  955. /*
  956. ** Try to find a DX8TextureCategoryClass in this FVF container which matches the
  957. ** given textures(one per stage), material and shader combination.
  958. */
  959. bool fit_in_existing_category = false;
  960. TextureCategoryListIterator it(&texture_category_list[pass]);
  961. while (!it.Is_Done()) {
  962. DX8TextureCategoryClass * tex_category=it.Peek_Obj();
  963. // Compare all stage's textures
  964. bool all_textures_same = true;
  965. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  966. all_textures_same = all_textures_same && (tex_category->Peek_Texture(stage) == texs[stage]);
  967. }
  968. if (all_textures_same && Equal_Material(tex_category->Peek_Material(),mat) && tex_category->Get_Shader()==shader) {
  969. used_indices+=tex_category->Add_Mesh(split_table,vertex_offset,used_indices,index_buffer,pass);
  970. fit_in_existing_category = true;
  971. break;
  972. }
  973. it.Next();
  974. }
  975. if (!fit_in_existing_category) {
  976. DX8TextureCategoryClass * new_tex_category=W3DNEW DX8TextureCategoryClass(this,texs,shader,mat,pass);
  977. used_indices+=new_tex_category->Add_Mesh(split_table,vertex_offset,used_indices,index_buffer,pass);
  978. /*
  979. ** Add the texture category object into the list, immediately after any existing
  980. ** texture category object which uses the same texture. This will result in
  981. ** the list always having matching texture categories next to each other.
  982. */
  983. bool found_similar_category = false;
  984. TextureCategoryListIterator it(&texture_category_list[pass]);
  985. while (!it.Is_Done()) {
  986. // Categorize according to first stage's texture for now
  987. if (it.Peek_Obj()->Peek_Texture(0) == texs[0]) {
  988. texture_category_list[pass].Add_After(new_tex_category,it.Peek_Obj());
  989. found_similar_category = true;
  990. break;
  991. }
  992. it.Next();
  993. }
  994. if (!found_similar_category) {
  995. texture_category_list[pass].Add_Tail(new_tex_category);
  996. }
  997. }
  998. }
  999. const unsigned MAX_ADDED_TYPE_COUNT=64;
  1000. struct Textures_Material_And_Shader_Booking_Struct
  1001. {
  1002. TextureClass* added_textures[MeshMatDescClass::MAX_TEX_STAGES][MAX_ADDED_TYPE_COUNT];
  1003. VertexMaterialClass* added_materials[MAX_ADDED_TYPE_COUNT];
  1004. ShaderClass added_shaders[MAX_ADDED_TYPE_COUNT];
  1005. unsigned added_type_count;
  1006. Textures_Material_And_Shader_Booking_Struct() : added_type_count(0) {}
  1007. bool Add_Textures_Material_And_Shader(TextureClass** texs, VertexMaterialClass* mat, ShaderClass shd)
  1008. {
  1009. for (unsigned a=0;a<added_type_count;++a) {
  1010. // Compare textures
  1011. bool all_textures_same = true;
  1012. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  1013. all_textures_same = all_textures_same && (texs[stage] == added_textures[stage][a]);
  1014. }
  1015. if (all_textures_same && Equal_Material(mat,added_materials[a]) && shd==added_shaders[a]) {
  1016. return false;
  1017. }
  1018. }
  1019. WWASSERT(added_type_count<MAX_ADDED_TYPE_COUNT);
  1020. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  1021. added_textures[stage][added_type_count]=texs[stage];
  1022. }
  1023. added_materials[added_type_count]=mat;
  1024. added_shaders[added_type_count]=shd;
  1025. added_type_count++;
  1026. return true;
  1027. }
  1028. };
  1029. void DX8FVFCategoryContainer::Generate_Texture_Categories(Vertex_Split_Table& split_table,unsigned vertex_offset)
  1030. {
  1031. int polygon_count=split_table.Get_Polygon_Count();
  1032. int index_count=polygon_count*3*split_table.Get_Pass_Count();
  1033. /*
  1034. ** If we don't have an index buffer yet, allocate one. Make it hold at least 12000 entries,
  1035. ** more if the mesh requires it.
  1036. */
  1037. if (!index_buffer) {
  1038. int ib_size=12000;
  1039. if (ib_size<index_count) ib_size=index_count;
  1040. if (sorting) {
  1041. index_buffer=NEW_REF(SortingIndexBufferClass,(ib_size));
  1042. }
  1043. else {
  1044. index_buffer=NEW_REF(DX8IndexBufferClass,(
  1045. ib_size,
  1046. (DX8Wrapper::Get_Current_Caps()->Support_NPatches() && WW3D::Get_NPatches_Level()>1) ? DX8IndexBufferClass::USAGE_NPATCHES : DX8IndexBufferClass::USAGE_DEFAULT));
  1047. }
  1048. }
  1049. for (unsigned pass=0;pass<split_table.Get_Pass_Count();++pass) {
  1050. Textures_Material_And_Shader_Booking_Struct textures_material_and_shader_booking;
  1051. unsigned old_used_indices=used_indices;
  1052. for (int i=0;i<polygon_count;++i) {
  1053. TextureClass* textures[MeshMatDescClass::MAX_TEX_STAGES];
  1054. // disabled this assert as MAX_TEXTURE_STAGES is now 8, but legacy MeshMat::MAX_TEX_STAGES is still 2
  1055. // WWASSERT(MAX_TEXTURE_STAGES==MeshMatDescClass::MAX_TEX_STAGES);
  1056. for (int stage=0;stage<MeshMatDescClass::MAX_TEX_STAGES;stage++)
  1057. {
  1058. textures[stage]=split_table.Peek_Texture(i,pass,stage);
  1059. }
  1060. VertexMaterialClass* mat=split_table.Peek_Material(i,pass);
  1061. ShaderClass shader=split_table.Peek_Shader(i,pass);
  1062. if (!textures_material_and_shader_booking.Add_Textures_Material_And_Shader(textures,mat,shader)) continue;
  1063. Insert_To_Texture_Category(split_table,textures,mat,shader,pass,vertex_offset);
  1064. }
  1065. int new_inds=used_indices-old_used_indices;
  1066. WWASSERT(new_inds<=polygon_count*3);
  1067. }
  1068. }
  1069. // ----------------------------------------------------------------------------
  1070. DX8SkinFVFCategoryContainer::DX8SkinFVFCategoryContainer(bool sorting)
  1071. :
  1072. DX8FVFCategoryContainer(DX8_FVF_XYZNUV1,sorting),
  1073. VisibleVertexCount(0),
  1074. VisibleSkinHead(NULL),
  1075. VisibleSkinTail(NULL)
  1076. {
  1077. }
  1078. // ----------------------------------------------------------------------------
  1079. DX8SkinFVFCategoryContainer::~DX8SkinFVFCategoryContainer()
  1080. {
  1081. }
  1082. // ----------------------------------------------------------------------------
  1083. void DX8SkinFVFCategoryContainer::Log(bool only_visible)
  1084. {
  1085. #ifdef ENABLE_CATEGORY_LOG
  1086. StringClass work(255,true);
  1087. work.Format("DX8SkinFVFCategoryContainer --------------\n");
  1088. WWDEBUG_SAY((work));
  1089. if (index_buffer) {
  1090. work.Format("IB size (used/total): %d/%d\n",used_indices,index_buffer->Get_Index_Count());
  1091. WWDEBUG_SAY((work));
  1092. }
  1093. else {
  1094. WWDEBUG_SAY(("EMPTY IB\n"));
  1095. }
  1096. for (unsigned pass=0;pass<passes;++pass) {
  1097. TextureCategoryListIterator it(&texture_category_list[pass]);
  1098. while (!it.Is_Done()) {
  1099. it.Peek_Obj()->Log(only_visible);
  1100. it.Next();
  1101. }
  1102. }
  1103. #endif
  1104. }
  1105. // ----------------------------------------------------------------------------
  1106. void DX8SkinFVFCategoryContainer::Render(void)
  1107. {
  1108. SNAPSHOT_SAY(("DX8SkinFVFCategoryContainer::Render()\n"));
  1109. if (!Anything_To_Render()) {
  1110. SNAPSHOT_SAY(("Nothing to render\n"));
  1111. return;
  1112. }
  1113. AnythingToRender=false;
  1114. DX8Wrapper::Set_Vertex_Buffer(NULL); // Free up the reference to the current vertex buffer
  1115. // (in case it is the dynamic, which may have to be resized)
  1116. //'Generals' customization to allow more than 65535 vertices
  1117. unsigned int maxVertexCount=VisibleVertexCount;
  1118. if (maxVertexCount > 65535)
  1119. { //clamp vertex count to maximum size that can be indexed by 16-bit index
  1120. maxVertexCount = 65535;
  1121. }
  1122. DynamicVBAccessClass vb(
  1123. sorting ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8,
  1124. dynamic_fvf_type,
  1125. maxVertexCount);
  1126. SNAPSHOT_SAY(("DynamicVBAccess - %s - %d vertices\n",sorting ? "sorting" : "non-sorting",VisibleVertexCount));
  1127. unsigned int renderedVertexCount=0;
  1128. MeshClass * mesh = VisibleSkinHead;
  1129. MeshClass * remainingMesh = VisibleSkinHead;
  1130. while (renderedVertexCount < VisibleVertexCount)
  1131. { mesh = remainingMesh;
  1132. { DynamicVBAccessClass::WriteLockClass l(&vb);
  1133. VertexFormatXYZNDUV2 * dest_verts = l.Get_Formatted_Vertex_Array();
  1134. unsigned vertex_offset=0;
  1135. remainingMesh = NULL;
  1136. while (mesh != NULL) {
  1137. MeshModelClass * mmc = mesh->Peek_Model();
  1138. int mesh_vertex_count=mmc->Get_Vertex_Count();
  1139. //'Generals' mod to deal with cases where not all meshes fit in VB.
  1140. if (vertex_offset+mesh_vertex_count > maxVertexCount || remainingMesh)
  1141. { //flag mesh so we know it didn't fit in the vertex buffer
  1142. mesh->Set_Base_Vertex_Offset(VERTEX_BUFFER_OVERFLOW);
  1143. if (remainingMesh == NULL)
  1144. remainingMesh = mesh; //start of meshes that didn't fit in buffer
  1145. mesh = mesh->Peek_Next_Visible_Skin(); //skip rendering this mesh
  1146. continue;
  1147. }
  1148. // If this assert hits, a skinned mesh has probably been added to the scene more than once.
  1149. // Example: A skinned mesh was added to the scene then it was attached to a bone without being removed from the scene.
  1150. WWASSERT((vertex_offset+mesh_vertex_count)<=VisibleVertexCount);
  1151. DX8_RECORD_SKIN_RENDER(mesh->Get_Num_Polys(),mesh_vertex_count);
  1152. if (_TempVertexBuffer.Length() < mesh_vertex_count) _TempVertexBuffer.Resize(mesh_vertex_count);
  1153. if (_TempNormalBuffer.Length() < mesh_vertex_count) _TempNormalBuffer.Resize(mesh_vertex_count);
  1154. Vector3* loc=&(_TempVertexBuffer[0]);
  1155. Vector3* norm=&(_TempNormalBuffer[0]);
  1156. const Vector2* uv0=mmc->Get_UV_Array_By_Index(0);
  1157. const Vector2* uv1=mmc->Get_UV_Array_By_Index(1);
  1158. const unsigned* diffuse=mmc->Get_Color_Array(0,false);
  1159. VertexFormatXYZNDUV2* verts=dest_verts+vertex_offset;
  1160. mesh->Get_Deformed_Vertices(loc,norm);
  1161. for (int v=0;v<mesh_vertex_count;++v) {
  1162. verts[v].x=(*loc)[0];
  1163. verts[v].y=(*loc)[1];
  1164. verts[v].z=(*loc)[2];
  1165. verts[v].nx=(*norm)[0];
  1166. verts[v].ny=(*norm)[1];
  1167. verts[v].nz=(*norm)[2];
  1168. if (diffuse) {
  1169. verts[v].diffuse=*diffuse++;
  1170. }
  1171. else {
  1172. verts[v].diffuse=0;
  1173. }
  1174. if (uv0) {
  1175. verts[v].u1=(*uv0)[0];
  1176. verts[v].v1=(*uv0)[1];
  1177. uv0++;
  1178. }
  1179. else {
  1180. verts[v].u1=0.0f;
  1181. verts[v].v1=0.0f;
  1182. }
  1183. if (uv1) {
  1184. verts[v].u2=(*uv1)[0];
  1185. verts[v].v2=(*uv1)[1];
  1186. uv1++;
  1187. }
  1188. else {
  1189. verts[v].u2=0.0f;
  1190. verts[v].v2=0.0f;
  1191. }
  1192. loc++;
  1193. norm++;
  1194. }
  1195. mesh->Set_Base_Vertex_Offset(vertex_offset);
  1196. vertex_offset+=mesh_vertex_count;
  1197. renderedVertexCount += mesh_vertex_count;
  1198. mesh = mesh->Peek_Next_Visible_Skin();
  1199. } //while
  1200. }//lock
  1201. SNAPSHOT_SAY(("Set vb: %x ib: %x\n",vb,index_buffer));
  1202. DX8Wrapper::Set_Vertex_Buffer(vb);
  1203. DX8Wrapper::Set_Index_Buffer(index_buffer,0);
  1204. //Flush the meshes which fit in the vertex buffer, applying all texture variations
  1205. for (unsigned pass=0;pass<passes;++pass) {
  1206. SNAPSHOT_SAY(("Pass: %d\n",pass));
  1207. TextureCategoryListIterator it(&visible_texture_category_list[pass]);
  1208. while (!it.Is_Done()) {
  1209. it.Peek_Obj()->Render();
  1210. it.Next();
  1211. }
  1212. }
  1213. Render_Procedural_Material_Passes();
  1214. }//while
  1215. //remove all the rendered data from queues
  1216. for (unsigned pass=0;pass<passes;++pass) {
  1217. while (DX8TextureCategoryClass * tex = visible_texture_category_list[pass].Remove_Head()) {
  1218. }
  1219. }
  1220. WWASSERT(renderedVertexCount==VisibleVertexCount);
  1221. clearVisibleSkinList();
  1222. }
  1223. bool DX8SkinFVFCategoryContainer::Check_If_Mesh_Fits(MeshModelClass* mmc)
  1224. {
  1225. if (!index_buffer) return true; // No IB created - mesh will fit as a new ib will be created when inserting
  1226. int required_polygons=mmc->Get_Polygon_Count();
  1227. if (mmc->Get_Gap_Filler()) {
  1228. required_polygons+=mmc->Get_Gap_Filler()->Get_Polygon_Count();
  1229. }
  1230. if ((required_polygons*3*mmc->Get_Pass_Count())<=index_buffer->Get_Index_Count()-used_indices) {
  1231. return true;
  1232. }
  1233. return false;
  1234. }
  1235. void DX8SkinFVFCategoryContainer::clearVisibleSkinList()
  1236. {
  1237. while (VisibleSkinHead != NULL)
  1238. {
  1239. MeshClass* next = VisibleSkinHead->Peek_Next_Visible_Skin();
  1240. VisibleSkinHead->Set_Next_Visible_Skin(NULL);
  1241. VisibleSkinHead = next;
  1242. }
  1243. VisibleSkinHead = NULL;
  1244. VisibleSkinTail = NULL;
  1245. VisibleVertexCount = 0;
  1246. }
  1247. void DX8SkinFVFCategoryContainer::Add_Visible_Skin(MeshClass * mesh)
  1248. {
  1249. if (mesh->Peek_Next_Visible_Skin() != NULL || mesh == VisibleSkinTail)
  1250. {
  1251. DEBUG_CRASH(("Mesh %s is already a visible skin, and we tried to add it again... please notify Mark W or Steven J immediately!\n",mesh->Get_Name()));
  1252. return;
  1253. }
  1254. if (VisibleSkinHead == NULL)
  1255. VisibleSkinTail = mesh;
  1256. mesh->Set_Next_Visible_Skin(VisibleSkinHead);
  1257. VisibleSkinHead = mesh;
  1258. VisibleVertexCount += mesh->Peek_Model()->Get_Vertex_Count();
  1259. }
  1260. // ----------------------------------------------------------------------------
  1261. void DX8SkinFVFCategoryContainer::Reset()
  1262. {
  1263. clearVisibleSkinList();
  1264. for (unsigned pass=0;pass<passes;++pass) {
  1265. while (DX8TextureCategoryClass* texture_category=texture_category_list[pass].Peek_Head()) {
  1266. delete texture_category;
  1267. }
  1268. }
  1269. REF_PTR_RELEASE(index_buffer);
  1270. used_indices=0;
  1271. }
  1272. // ----------------------------------------------------------------------------
  1273. void DX8SkinFVFCategoryContainer::Add_Mesh(MeshModelClass* mmc)
  1274. {
  1275. Vertex_Split_Table split_table(mmc);
  1276. Generate_Texture_Categories(split_table,0);
  1277. }
  1278. // ----------------------------------------------------------------------------
  1279. unsigned DX8TextureCategoryClass::Add_Mesh(
  1280. Vertex_Split_Table& split_table,
  1281. unsigned vertex_offset,
  1282. unsigned index_offset,
  1283. IndexBufferClass* index_buffer,
  1284. unsigned pass)
  1285. {
  1286. int poly_count=split_table.Get_Polygon_Count();
  1287. unsigned index_count=0;
  1288. /*
  1289. ** Count the polygons in the given mesh in the given pass which match this texture category
  1290. */
  1291. unsigned polygons=0;
  1292. for (int i=0;i<poly_count;++i) {
  1293. bool all_textures_same = true;
  1294. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  1295. all_textures_same = all_textures_same && (split_table.Peek_Texture(i, pass, stage) == textures[stage]);
  1296. }
  1297. VertexMaterialClass* mat=split_table.Peek_Material(i,pass);
  1298. ShaderClass shd=split_table.Peek_Shader(i,pass);
  1299. if (all_textures_same && Equal_Material(mat,material) && shd==shader) {
  1300. polygons++;
  1301. }
  1302. }
  1303. /*
  1304. ** Add the indices for the polygons that match into this renderer's dx8 index table.
  1305. */
  1306. if (polygons) {
  1307. index_count=polygons*3;
  1308. #ifndef ENABLE_STRIPING
  1309. bool stripify=false;
  1310. #else
  1311. bool stripify=true;
  1312. if (index_buffer->Type()==BUFFER_TYPE_SORTING || index_buffer->Type()==BUFFER_TYPE_DYNAMIC_SORTING) {
  1313. stripify=false;
  1314. }
  1315. #endif;
  1316. const TriIndex* src_indices=(const TriIndex*)split_table.Get_Polygon_Array(pass);//mmc->Get_Polygon_Array();
  1317. if (stripify) {
  1318. int* triangles=W3DNEWARRAY int[index_count];
  1319. int triangle_index_count=0;
  1320. for (int i=0;i<poly_count;++i) {
  1321. bool all_textures_same = true;
  1322. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  1323. all_textures_same = all_textures_same && (split_table.Peek_Texture(i, pass, stage) == textures[stage]);
  1324. }
  1325. VertexMaterialClass* mat=split_table.Peek_Material(i,pass);
  1326. ShaderClass shd=split_table.Peek_Shader(i,pass);
  1327. if (all_textures_same && Equal_Material(mat,material) && shd==shader) {
  1328. triangles[triangle_index_count++]=src_indices[i][0]+vertex_offset;
  1329. triangles[triangle_index_count++]=src_indices[i][1]+vertex_offset;
  1330. triangles[triangle_index_count++]=src_indices[i][2]+vertex_offset;
  1331. }
  1332. }
  1333. int* strips=StripOptimizerClass::Stripify(triangles, triangle_index_count/3);
  1334. delete[] triangles;
  1335. int* strip=StripOptimizerClass::Combine_Strips(strips+1,strips[0]);
  1336. delete[] strips;
  1337. if (index_count<unsigned(strip[0])) {
  1338. stripify=false;
  1339. }
  1340. else {
  1341. index_count=strip[0];
  1342. DX8PolygonRendererClass* p_renderer=W3DNEW DX8PolygonRendererClass(
  1343. index_count,
  1344. split_table.Get_Mesh_Model_Class(),
  1345. this,
  1346. vertex_offset,
  1347. index_offset,
  1348. true,
  1349. pass);
  1350. PolygonRendererList.Add_Tail(p_renderer);
  1351. {
  1352. IndexBufferClass::AppendLockClass l(index_buffer,index_offset,index_count);
  1353. unsigned short* dst_indices=l.Get_Index_Array();
  1354. unsigned short vmin=0xffff;
  1355. unsigned short vmax=0;
  1356. /*
  1357. ** Iterate over the polys for this pass, adding each one that matches this texture+material+shader
  1358. */
  1359. for (unsigned i=0;i<index_count;++i) {
  1360. unsigned short idx;
  1361. idx=unsigned short(strip[i+1]);
  1362. vmin=MIN(vmin,idx);
  1363. vmax=MAX(vmax,idx);
  1364. *dst_indices++=idx;
  1365. }
  1366. /*
  1367. ** Remember the min and max vertex indices that these polygons used (for optimization)
  1368. */
  1369. p_renderer->Set_Vertex_Index_Range(vmin,vmax-vmin+1);
  1370. }
  1371. }
  1372. delete[] strip;
  1373. }
  1374. // Need to check stripify again as it may be changed to false by the previous statement
  1375. if (!stripify ) {
  1376. DX8PolygonRendererClass* p_renderer=W3DNEW DX8PolygonRendererClass(
  1377. index_count,
  1378. split_table.Get_Mesh_Model_Class(),
  1379. this,
  1380. vertex_offset,
  1381. index_offset,
  1382. false,
  1383. pass);
  1384. PolygonRendererList.Add_Tail(p_renderer);
  1385. IndexBufferClass::AppendLockClass l(index_buffer,index_offset,index_count);
  1386. unsigned short* dst_indices=l.Get_Index_Array();
  1387. unsigned short vmin=0xffff;
  1388. unsigned short vmax=0;
  1389. /*
  1390. ** Iterate over the polys for this pass, adding each one that matches this texture+material+shader
  1391. */
  1392. for (int i=0;i<poly_count;++i) {
  1393. bool all_textures_same = true;
  1394. for (unsigned int stage = 0; stage < MeshMatDescClass::MAX_TEX_STAGES; stage++) {
  1395. all_textures_same = all_textures_same && (split_table.Peek_Texture(i, pass, stage) == textures[stage]);
  1396. }
  1397. VertexMaterialClass* mat=split_table.Peek_Material(i,pass);
  1398. ShaderClass shd=split_table.Peek_Shader(i,pass);
  1399. if (all_textures_same && Equal_Material(mat,material) && shd==shader) {
  1400. unsigned short idx;
  1401. idx=unsigned short(src_indices[i][0]+vertex_offset);
  1402. vmin=MIN(vmin,idx);
  1403. vmax=MAX(vmax,idx);
  1404. *dst_indices++=idx;
  1405. // WWDEBUG_SAY(("%d, ",idx));
  1406. idx=unsigned short(src_indices[i][1]+vertex_offset);
  1407. vmin=MIN(vmin,idx);
  1408. vmax=MAX(vmax,idx);
  1409. *dst_indices++=idx;
  1410. // WWDEBUG_SAY(("%d, ",idx));
  1411. idx=unsigned short(src_indices[i][2]+vertex_offset);
  1412. vmin=MIN(vmin,idx);
  1413. vmax=MAX(vmax,idx);
  1414. *dst_indices++=idx;
  1415. // WWDEBUG_SAY(("%d\n",idx));
  1416. }
  1417. }
  1418. WWASSERT((vmax-vmin)<split_table.Get_Mesh_Model_Class()->Get_Vertex_Count());
  1419. /*
  1420. ** Remember the min and max vertex indices that these polygons used (for optimization)
  1421. */
  1422. p_renderer->Set_Vertex_Index_Range(vmin,vmax-vmin+1);
  1423. WWASSERT(index_count<=unsigned(split_table.Get_Polygon_Count()*3));
  1424. }
  1425. }
  1426. return index_count;
  1427. }
  1428. // ----------------------------------------------------------------------------
  1429. void DX8TextureCategoryClass::Render(void)
  1430. {
  1431. #ifdef WWDEBUG
  1432. if (!WW3D::Expose_Prelit()) {
  1433. #endif
  1434. for (unsigned i=0;i<MeshMatDescClass::MAX_TEX_STAGES;++i)
  1435. {
  1436. SNAPSHOT_SAY(("Set_Texture(%d,%s)\n",i,Peek_Texture(i) ? Peek_Texture(i)->Get_Texture_Name() : "NULL"));
  1437. DX8Wrapper::Set_Texture(i,Peek_Texture(i));
  1438. }
  1439. #ifdef WWDEBUG
  1440. }
  1441. #endif
  1442. SNAPSHOT_SAY(("Set_Material(%s)\n",Peek_Material() ? Peek_Material()->Get_Name() : "NULL"));
  1443. VertexMaterialClass *vmaterial=(VertexMaterialClass *)Peek_Material(); //ugly cast from const but we'll restore it after changes so okay. -MW
  1444. DX8Wrapper::Set_Material(vmaterial);
  1445. SNAPSHOT_SAY(("Set_Shader(%x)\n",Get_Shader()));
  1446. ShaderClass theShader = Get_Shader();
  1447. //Setup an alpha blend version of this shader just in case it's needed. -MW
  1448. ShaderClass theAlphaShader = theShader;
  1449. theAlphaShader.Set_Src_Blend_Func(ShaderClass::SRCBLEND_SRC_ALPHA);
  1450. theAlphaShader.Set_Dst_Blend_Func(ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA);
  1451. //if we want to allow other translucent polygons behind this mesh, we need to disable z-write but
  1452. //this will cause sorting errors on this mesh.
  1453. //theAlphaShader.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE);
  1454. DX8Wrapper::Set_Shader(theShader);
  1455. if (m_gForceMultiply && theShader.Get_Dst_Blend_Func() == ShaderClass::DSTBLEND_ZERO) {
  1456. theShader.Set_Dst_Blend_Func(ShaderClass::DSTBLEND_SRC_COLOR);
  1457. theShader.Set_Src_Blend_Func(ShaderClass::SRCBLEND_ZERO);
  1458. DX8Wrapper::Set_Shader(theShader);
  1459. //VertexMaterialClass *material = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  1460. //DX8Wrapper::Set_Material(material);
  1461. //REF_PTR_RELEASE(material);
  1462. DX8Wrapper::Apply_Render_State_Changes();
  1463. DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR);
  1464. }
  1465. bool renderTasksRemaining=false;
  1466. PolyRenderTaskClass * prt = render_task_head;
  1467. PolyRenderTaskClass * last_prt = NULL;
  1468. while (prt) {
  1469. /*
  1470. ** Dig out the parameters for this render task
  1471. */
  1472. DX8PolygonRendererClass * renderer = prt->Peek_Polygon_Renderer();
  1473. MeshClass * mesh = prt->Peek_Mesh();
  1474. if (mesh->Get_Base_Vertex_Offset() == VERTEX_BUFFER_OVERFLOW) //check if this mesh is valid
  1475. { //skip this mesh so it gets rendered later after vertices are filled in.
  1476. last_prt = prt;
  1477. prt = prt->Get_Next_Visible();
  1478. renderTasksRemaining = true;
  1479. continue;
  1480. }
  1481. SNAPSHOT_SAY(("mesh = %s\n",mesh->Get_Name()));
  1482. #ifdef WWDEBUG
  1483. // Debug rendering: if it exists, expose prelighting on this mesh by disabling all base textures.
  1484. if (WW3D::Expose_Prelit()) {
  1485. switch (mesh->Peek_Model()->Get_Flag (MeshGeometryClass::PRELIT_MASK)) {
  1486. unsigned i;
  1487. case MeshGeometryClass::PRELIT_VERTEX:
  1488. // Disable texturing on all stages and passes.
  1489. for (i = 0; i < MeshMatDescClass::MAX_TEX_STAGES; i++)
  1490. {
  1491. DX8Wrapper::Set_Texture (i, NULL);
  1492. }
  1493. break;
  1494. case MeshGeometryClass::PRELIT_LIGHTMAP_MULTI_PASS:
  1495. // Disable texturing on all but the last pass.
  1496. if (pass == mesh->Peek_Model()->Get_Pass_Count() - 1) {
  1497. for (i = 0; i < MeshMatDescClass::MAX_TEX_STAGES; i++)
  1498. {
  1499. DX8Wrapper::Set_Texture (i, Peek_Texture (i));
  1500. }
  1501. } else {
  1502. for (i = 0; i < MAX_TEXTURE_STAGES; i++) {
  1503. DX8Wrapper::Set_Texture (i, NULL);
  1504. }
  1505. }
  1506. break;
  1507. case MeshGeometryClass::PRELIT_LIGHTMAP_MULTI_TEXTURE:
  1508. // Disable texturing on all but the zeroth stage of each pass.
  1509. DX8Wrapper::Set_Texture (0, Peek_Texture (0));
  1510. for (i = 1; i < MeshMatDescClass::MAX_TEX_STAGES; i++)
  1511. {
  1512. DX8Wrapper::Set_Texture (i, NULL);
  1513. }
  1514. break;
  1515. default:
  1516. for (i = 0; i < MeshMatDescClass::MAX_TEX_STAGES; i++)
  1517. {
  1518. DX8Wrapper::Set_Texture (i, Peek_Texture (i));
  1519. }
  1520. break;
  1521. }
  1522. }
  1523. #endif
  1524. /*
  1525. ** If the user is not installing LightEnvironmentClasses, we leave the lighting render
  1526. ** states untouched. This way they can set a couple global lights that affect the entire scene.
  1527. */
  1528. LightEnvironmentClass * lenv = mesh->Get_Lighting_Environment();
  1529. if (lenv != NULL) {
  1530. SNAPSHOT_SAY(("LightEnvironment, lights: %d\n",lenv->Get_Light_Count()));
  1531. DX8Wrapper::Set_Light_Environment(lenv);
  1532. }
  1533. else {
  1534. SNAPSHOT_SAY(("No light environment\n"));
  1535. }
  1536. /*
  1537. ** Support for ALIGNED and ORIENTED camera modes
  1538. */
  1539. const Matrix3D* world_transform = &mesh->Get_Transform();
  1540. bool identity=mesh->Is_Transform_Identity();
  1541. Matrix3D tmp_world;
  1542. if (mesh->Peek_Model()->Get_Flag(MeshModelClass::ALIGNED)) {
  1543. SNAPSHOT_SAY(("Camera mode ALIGNED\n"));
  1544. Vector3 mesh_position;
  1545. Vector3 camera_z_vector;
  1546. TheDX8MeshRenderer.Peek_Camera()->Get_Transform().Get_Z_Vector(&camera_z_vector);
  1547. mesh->Get_Transform().Get_Translation(&mesh_position);
  1548. tmp_world.Obj_Look_At(mesh_position,mesh_position + camera_z_vector,0.0f);
  1549. world_transform = &tmp_world;
  1550. } else if (mesh->Peek_Model()->Get_Flag(MeshModelClass::ORIENTED)) {
  1551. SNAPSHOT_SAY(("Camera mode ORIENTED\n"));
  1552. Vector3 mesh_position;
  1553. Vector3 camera_position;
  1554. TheDX8MeshRenderer.Peek_Camera()->Get_Transform().Get_Translation(&camera_position);
  1555. mesh->Get_Transform().Get_Translation(&mesh_position);
  1556. tmp_world.Obj_Look_At(mesh_position,camera_position,0.0f);
  1557. world_transform = &tmp_world;
  1558. } else if (mesh->Peek_Model()->Get_Flag(MeshModelClass::SKIN)) {
  1559. SNAPSHOT_SAY(("Set world identity (for skin)\n"));
  1560. tmp_world.Make_Identity();
  1561. world_transform = &tmp_world;
  1562. identity=true;
  1563. }
  1564. if (identity) {
  1565. SNAPSHOT_SAY(("Set_World_Identity\n"));
  1566. DX8Wrapper::Set_World_Identity();
  1567. }
  1568. else {
  1569. SNAPSHOT_SAY(("Set_World_Transform\n"));
  1570. DX8Wrapper::Set_Transform(D3DTS_WORLD,*world_transform);
  1571. }
  1572. //--------------------------------------------------------------------
  1573. if (mesh->Get_ObjectScale() != 1.0f)
  1574. DX8Wrapper::Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, TRUE);
  1575. //--------------------------------------------------------------------
  1576. /*
  1577. ** Render mesh using either sorting or immediate pipeline
  1578. */
  1579. //(gth) this if statement's contents are not tabbed to avoid perforce merge problems...
  1580. if (!DX8RendererDebugger::Is_Enabled() || !mesh->Is_Disabled_By_Debugger()) {
  1581. if ((!!mesh->Peek_Model()->Get_Flag(MeshGeometryClass::SORT)) && WW3D::Is_Sorting_Enabled()) {
  1582. renderer->Render_Sorted(mesh->Get_Base_Vertex_Offset(),mesh->Get_Bounding_Sphere());
  1583. } else {
  1584. //non-transparent mesh that will be rendered immediately. Okay to adjust the shader/material
  1585. //if necessary
  1586. if (mesh->Get_Alpha_Override() != 1.0 || (mesh->Get_User_Data() && *(int *)mesh->Get_User_Data() == RenderObjClass::USER_DATA_MATERIAL_OVERRIDE))
  1587. { //mesh has material override of some kind
  1588. //adjust the opacity of this model
  1589. float oldOpacity=vmaterial->Get_Opacity();
  1590. Vector3 oldDiffuse;
  1591. Vector2 oldUVOffset;
  1592. unsigned int oldUVOffsetSyncTime;
  1593. vmaterial->Get_Diffuse(&oldDiffuse);
  1594. LinearOffsetTextureMapperClass *oldMapper=(LinearOffsetTextureMapperClass *)vmaterial->Peek_Mapper();
  1595. if ( mesh->Get_User_Data() && *(int *)mesh->Get_User_Data() == RenderObjClass::USER_DATA_MATERIAL_OVERRIDE && oldMapper && oldMapper->Mapper_ID() == TextureMapperClass::MAPPER_ID_LINEAR_OFFSET)
  1596. { RenderObjClass::Material_Override *matOverride=(RenderObjClass::Material_Override *)mesh->Get_User_Data();
  1597. oldUVOffsetSyncTime = oldMapper->Get_LastUsedSyncTime();
  1598. oldMapper->Set_LastUsedSyncTime(WW3D::Get_Sync_Time()); //make sure zero time passes for the mapper.
  1599. oldMapper->Get_Current_UV_Offset(oldUVOffset);
  1600. oldMapper->Set_Current_UV_Offset(matOverride->customUVOffset);
  1601. }
  1602. else
  1603. oldMapper=NULL;
  1604. if (mesh->Get_Alpha_Override() != 1.0)
  1605. {
  1606. if (mesh->Is_Additive())
  1607. { //additvie blended mesh can't switch to alpha or we will get a black outline.
  1608. //so adjust diffuse color instead.
  1609. vmaterial->Set_Diffuse(mesh->Get_Alpha_Override(),mesh->Get_Alpha_Override(),mesh->Get_Alpha_Override());
  1610. theAlphaShader = theShader; //keep using additive blending.
  1611. }
  1612. vmaterial->Set_Opacity(mesh->Get_Alpha_Override());
  1613. DX8Wrapper::Set_Shader(theAlphaShader);
  1614. DX8Wrapper::Apply_Render_State_Changes();
  1615. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,(int)((float)0x60*mesh->Get_Alpha_Override()));
  1616. renderer->Render(mesh->Get_Base_Vertex_Offset());
  1617. DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x60);
  1618. vmaterial->Set_Opacity(oldOpacity); //restore previous value
  1619. vmaterial->Set_Diffuse(oldDiffuse.X,oldDiffuse.Y,oldDiffuse.Z);
  1620. DX8Wrapper::Set_Shader(theShader); //restore previous value
  1621. }
  1622. else
  1623. renderer->Render(mesh->Get_Base_Vertex_Offset());
  1624. if (oldMapper) //did we override the uv offset?
  1625. { oldMapper->Set_LastUsedSyncTime(oldUVOffsetSyncTime);
  1626. oldMapper->Set_Current_UV_Offset(oldUVOffset);
  1627. }
  1628. DX8Wrapper::Set_Material(NULL); //force a reset of vertex material since we secretly changed opacity
  1629. DX8Wrapper::Set_Material(vmaterial); //restore previous material.
  1630. }
  1631. else
  1632. renderer->Render(mesh->Get_Base_Vertex_Offset());
  1633. }
  1634. //--------------------------------------------------------------------
  1635. if (mesh->Get_ObjectScale() != 1.0f)
  1636. DX8Wrapper::Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE);
  1637. //--------------------------------------------------------------------
  1638. } // (gth) non-tabbed to aviod per-force merge problems...
  1639. /*
  1640. ** Move to the next render task. Note that the delete should be fast because prt's are pooled
  1641. */
  1642. PolyRenderTaskClass * next_prt = prt->Get_Next_Visible();
  1643. // remove from list, then delete
  1644. if (last_prt == NULL) {
  1645. render_task_head = next_prt;
  1646. } else {
  1647. last_prt->Set_Next_Visible(next_prt);
  1648. }
  1649. delete prt;
  1650. prt = next_prt;
  1651. }
  1652. if (!renderTasksRemaining)
  1653. { WWASSERT(!render_task_head);
  1654. Clear_Render_List();
  1655. }
  1656. }
  1657. DX8MeshRendererClass::DX8MeshRendererClass()
  1658. :
  1659. camera(NULL),
  1660. enable_lighting(true),
  1661. texture_category_container_list_skin(NULL),
  1662. visible_decal_meshes(NULL)
  1663. {
  1664. }
  1665. DX8MeshRendererClass::~DX8MeshRendererClass()
  1666. {
  1667. Invalidate(true);
  1668. Clear_Pending_Delete_Lists();
  1669. if (texture_category_container_list_skin != NULL) {
  1670. delete texture_category_container_list_skin;
  1671. }
  1672. }
  1673. void DX8MeshRendererClass::Init(void)
  1674. {
  1675. // DMS - Only allocate one if we havent already (leak fix)
  1676. if(!texture_category_container_list_skin)
  1677. texture_category_container_list_skin = W3DNEW FVFCategoryList;
  1678. }
  1679. void DX8MeshRendererClass::Shutdown(void)
  1680. {
  1681. Invalidate(true);
  1682. Clear_Pending_Delete_Lists();
  1683. _TempVertexBuffer.Clear(); //free memory
  1684. _TempNormalBuffer.Clear();
  1685. }
  1686. // ----------------------------------------------------------------------------
  1687. void DX8MeshRendererClass::Clear_Pending_Delete_Lists()
  1688. {
  1689. while (DX8TextureCategoryClass* category=texture_category_delete_list.Remove_Head()) {
  1690. delete category;
  1691. }
  1692. while (DX8FVFCategoryContainer* container=fvf_category_container_delete_list.Remove_Head()) {
  1693. delete container;
  1694. }
  1695. }
  1696. // ----------------------------------------------------------------------------
  1697. static void Add_Rigid_Mesh_To_Container(FVFCategoryList* container_list,unsigned fvf,MeshModelClass* mmc)
  1698. {
  1699. WWASSERT(container_list);
  1700. DX8FVFCategoryContainer * container = NULL;
  1701. bool sorting=((!!mmc->Get_Flag(MeshModelClass::SORT)) && WW3D::Is_Sorting_Enabled() && (mmc->Get_Sort_Level() == SORT_LEVEL_NONE));
  1702. FVFCategoryListIterator it(container_list);
  1703. while (!it.Is_Done()) {
  1704. container = it.Peek_Obj();
  1705. if (sorting==container->Is_Sorting() && container->Check_If_Mesh_Fits(mmc)) {
  1706. container->Add_Mesh(mmc);
  1707. return;
  1708. }
  1709. it.Next();
  1710. }
  1711. container=W3DNEW DX8RigidFVFCategoryContainer(fvf,sorting);
  1712. container_list->Add_Tail(container);
  1713. container->Add_Mesh(mmc);
  1714. }
  1715. // ----------------------------------------------------------------------------
  1716. void DX8MeshRendererClass::Unregister_Mesh_Type(MeshModelClass* mmc)
  1717. {
  1718. while (DX8PolygonRendererClass* n=mmc->PolygonRendererList.Remove_Head()) {
  1719. delete n;
  1720. }
  1721. _RegisteredMeshList.Remove(mmc);
  1722. // Also remove the gap filler!
  1723. if (mmc->GapFiller) {
  1724. GapFillerClass* gf=mmc->GapFiller;
  1725. mmc->GapFiller=NULL;
  1726. delete gf;
  1727. }
  1728. }
  1729. void DX8MeshRendererClass::Register_Mesh_Type(MeshModelClass* mmc)
  1730. {
  1731. WWMEMLOG(MEM_GEOMETRY);
  1732. #ifdef ENABLE_CATEGORY_LOG
  1733. WWDEBUG_SAY(("Registering mesh: %s (%d polys, %d verts + %d gap polygons)\n",mmc->Get_Name(),mmc->Get_Polygon_Count(),mmc->Get_Vertex_Count(),mmc->Get_Gap_Filler_Polygon_Count()));
  1734. #endif
  1735. bool skin=(mmc->Get_Flag(MeshModelClass::SKIN) && mmc->VertexBoneLink);
  1736. bool sorting=((!!mmc->Get_Flag(MeshModelClass::SORT)) && WW3D::Is_Sorting_Enabled() && (mmc->Get_Sort_Level() == SORT_LEVEL_NONE));
  1737. if (skin) {
  1738. /*
  1739. ** This mesh is a skin. Add it to a DX8SkinFVFCategoryContainer.
  1740. */
  1741. WWASSERT(texture_category_container_list_skin);
  1742. FVFCategoryListIterator it(texture_category_container_list_skin);
  1743. while (!it.Is_Done()) {
  1744. DX8FVFCategoryContainer * container = it.Peek_Obj();
  1745. if (sorting==container->Is_Sorting() && container->Check_If_Mesh_Fits(mmc)) {
  1746. container->Add_Mesh(mmc);
  1747. return;
  1748. }
  1749. it.Next();
  1750. }
  1751. DX8FVFCategoryContainer * new_container=W3DNEW DX8SkinFVFCategoryContainer(sorting);
  1752. texture_category_container_list_skin->Add_Tail(new_container);
  1753. new_container->Add_Mesh(mmc);
  1754. } else {
  1755. /*
  1756. ** We should never try to add the same mesh model to the system twice.
  1757. */
  1758. WWASSERT_PRINT(_RegisteredMeshList.Contains(mmc) == false,("Mesh name: %s",mmc->Get_Name()));
  1759. /*
  1760. ** If the previous step didn't add the mesh, then we have to actually process this mesh
  1761. */
  1762. if (!_RegisteredMeshList.Contains(mmc)) {
  1763. unsigned fvf=DX8FVFCategoryContainer::Define_FVF(mmc,enable_lighting);
  1764. /*
  1765. ** Search for an existing FVF Category Container that matches this mesh
  1766. */
  1767. for (int i=0;i<texture_category_container_lists_rigid.Count();++i) {
  1768. FVFCategoryList * list=texture_category_container_lists_rigid[i];
  1769. WWASSERT(list);
  1770. DX8FVFCategoryContainer * container=list->Peek_Head();
  1771. if (container && container->Get_FVF()!=fvf) continue;
  1772. Add_Rigid_Mesh_To_Container(list,fvf,mmc);
  1773. break;
  1774. }
  1775. if (i==texture_category_container_lists_rigid.Count()) {
  1776. /*
  1777. ** We couldn't find an existing FVF category container so we have to add one. Future
  1778. ** meshes that use this FVF will also be able to use this container.
  1779. */
  1780. FVFCategoryList * new_fvf_category = W3DNEW FVFCategoryList();
  1781. texture_category_container_lists_rigid.Add(new_fvf_category);
  1782. Add_Rigid_Mesh_To_Container(new_fvf_category,fvf,mmc);
  1783. }
  1784. /*
  1785. ** Done processing the mesh, add its polygon renderers to the global registered mesh list
  1786. */
  1787. if (mmc->PolygonRendererList.Is_Empty() == false) {
  1788. _RegisteredMeshList.Add_Tail(mmc);
  1789. }
  1790. else {
  1791. WWDEBUG_SAY(("Error: Register_Mesh_Type failed! file: %s line: %d\r\n",__FILE__,__LINE__));
  1792. }
  1793. }
  1794. }
  1795. return;
  1796. }
  1797. static unsigned statistics_requested=0;
  1798. void DX8MeshRendererClass::Request_Log_Statistics()
  1799. {
  1800. statistics_requested=WW3D::Get_Frame_Count();
  1801. }
  1802. // ---------------------------------------------------------------------------
  1803. //
  1804. // Render all meshes that are added to visible lists
  1805. //
  1806. // ---------------------------------------------------------------------------
  1807. static void Render_FVF_Category_Container_List(FVFCategoryList& list)
  1808. {
  1809. FVFCategoryListIterator it(&list);
  1810. while (!it.Is_Done()) {
  1811. it.Peek_Obj()->Render();
  1812. it.Next();
  1813. }
  1814. }
  1815. static void Render_FVF_Category_Container_List_Delayed_Passes(FVFCategoryList& list)
  1816. {
  1817. FVFCategoryListIterator it(&list);
  1818. while (!it.Is_Done()) {
  1819. it.Peek_Obj()->Render_Delayed_Procedural_Material_Passes();
  1820. it.Next();
  1821. }
  1822. }
  1823. void DX8MeshRendererClass::Flush(void)
  1824. {
  1825. int i;
  1826. WWPROFILE("DX8MeshRenderer::Flush");
  1827. if (!camera) return;
  1828. Log_Statistics_String(true);
  1829. /*
  1830. ** Render the FVF categories. Note that it is critical that skins be
  1831. ** rendered *after* the rigid meshes. This is caused by the fact that an object may
  1832. ** have its base passes disabled and a translucent procedural material pass rendered
  1833. ** instead. In this case, technically we have to delay rendering of the material pass but
  1834. ** for skins we just render these passes as we go because we can assume that the
  1835. ** bulk of the meshes have already been drawn (there would be extra overhead involved
  1836. ** in solving this for skins)
  1837. */
  1838. for (i=0;i<texture_category_container_lists_rigid.Count();++i) {
  1839. Render_FVF_Category_Container_List(*texture_category_container_lists_rigid[i]);
  1840. }
  1841. Render_FVF_Category_Container_List(*texture_category_container_list_skin);
  1842. Render_Decal_Meshes();
  1843. /*
  1844. ** Render the translucent procedural material passes that were applied to meshes that
  1845. ** had their base passes disabled.
  1846. */
  1847. for (i=0;i<texture_category_container_lists_rigid.Count();++i) {
  1848. Render_FVF_Category_Container_List_Delayed_Passes(*texture_category_container_lists_rigid[i]);
  1849. }
  1850. DX8Wrapper::Set_Vertex_Buffer(NULL);
  1851. DX8Wrapper::Set_Index_Buffer(NULL,0);
  1852. }
  1853. void DX8MeshRendererClass::Add_To_Render_List(DecalMeshClass * decalmesh)
  1854. {
  1855. WWASSERT(decalmesh != NULL);
  1856. decalmesh->Set_Next_Visible(visible_decal_meshes);
  1857. visible_decal_meshes = decalmesh;
  1858. }
  1859. void DX8MeshRendererClass::Render_Decal_Meshes(void)
  1860. {
  1861. DecalMeshClass * decal_mesh = visible_decal_meshes;
  1862. if (!decal_mesh) return;
  1863. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,8);
  1864. while (decal_mesh != NULL) {
  1865. decal_mesh->Render();
  1866. decal_mesh = decal_mesh->Peek_Next_Visible();
  1867. }
  1868. visible_decal_meshes = NULL;
  1869. DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,0);
  1870. }
  1871. // ----------------------------------------------------------------------------
  1872. static void Log_Container_List(FVFCategoryList& container_list,bool only_visible)
  1873. {
  1874. FVFCategoryListIterator it(&container_list);
  1875. while (!it.Is_Done()) {
  1876. it.Peek_Obj()->Log(only_visible);
  1877. it.Next();
  1878. }
  1879. }
  1880. void DX8MeshRendererClass::Log_Statistics_String(bool only_visible)
  1881. {
  1882. if (statistics_requested!=WW3D::Get_Frame_Count()) return;
  1883. for (int i=0;i<texture_category_container_lists_rigid.Count();++i) {
  1884. Log_Container_List(*texture_category_container_lists_rigid[i],only_visible);
  1885. }
  1886. Log_Container_List(*texture_category_container_list_skin,only_visible);
  1887. }
  1888. static void Invalidate_FVF_Category_Container_List(FVFCategoryList& list)
  1889. {
  1890. while (DX8FVFCategoryContainer* fvf_category=list.Remove_Head()) {
  1891. delete fvf_category;
  1892. }
  1893. }
  1894. void DX8MeshRendererClass::Invalidate( bool shutdown)
  1895. {
  1896. WWMEMLOG(MEM_RENDERER);
  1897. _RegisteredMeshList.Reset_List();
  1898. for (int i=0;i<texture_category_container_lists_rigid.Count();++i) {
  1899. Invalidate_FVF_Category_Container_List(*texture_category_container_lists_rigid[i]);
  1900. delete texture_category_container_lists_rigid[i];
  1901. }
  1902. if (texture_category_container_list_skin) {
  1903. Invalidate_FVF_Category_Container_List(*texture_category_container_list_skin);
  1904. delete texture_category_container_list_skin;
  1905. texture_category_container_list_skin=NULL;
  1906. }
  1907. if (!shutdown)
  1908. texture_category_container_list_skin = W3DNEW FVFCategoryList;
  1909. texture_category_container_lists_rigid.Delete_All();
  1910. }