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