Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / mesh_multi_lod.cpp
blob291c00225413fb2052627c6a57ddf3190e322bb2
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/mesh_multi_lod.h"
23 #include "nel/3d/mesh_multi_lod_instance.h"
24 #include "nel/3d/mesh_instance.h"
25 #include "nel/3d/mesh_mrm.h"
26 #include "nel/3d/scene.h"
27 #include "nel/3d/coarse_mesh_manager.h"
28 #include "nel/3d/skeleton_model.h"
29 #include "nel/misc/fast_floor.h"
30 #include "nel/3d/mesh_blender.h"
31 #include "nel/3d/visual_collision_mesh.h"
33 #include "nel/misc/debug.h"
34 #include "nel/misc/hierarchical_timer.h"
36 using namespace NLMISC;
37 using namespace std;
41 #ifdef DEBUG_NEW
42 #define new DEBUG_NEW
43 #endif
45 namespace NL3D
50 // ***************************************************************************
52 void CMeshMultiLod::build(CMeshMultiLodBuild &mbuild)
54 // Clear the mesh
55 clear ();
57 // Build the base mesh
58 CMeshBase::buildMeshBase (mbuild.BaseMesh);
60 // Static flag
61 _StaticLod=mbuild.StaticLod;
63 // Resize the array
64 _MeshVector.resize (mbuild.LodMeshes.size());
66 // For each slots
67 for (uint slot=0; slot<mbuild.LodMeshes.size(); slot++)
69 // Dist max
70 _MeshVector[slot].DistMax=mbuild.LodMeshes[slot].DistMax;
72 // BlendLength
73 _MeshVector[slot].BlendLength=mbuild.LodMeshes[slot].BlendLength;
75 // Flags
76 _MeshVector[slot].Flags=0;
78 // Blend in ?
79 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::BlendIn)
80 _MeshVector[slot].Flags|=CMeshSlot::BlendIn;
82 // Blend out ?
83 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::BlendOut)
84 _MeshVector[slot].Flags|=CMeshSlot::BlendOut;
86 // Coarse mesh ?
87 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::CoarseMesh)
89 // Flag
90 _MeshVector[slot].Flags|=CMeshSlot::CoarseMesh;
93 // Is opaque
94 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::IsOpaque)
95 _MeshVector[slot].Flags|=CMeshSlot::IsOpaque;
97 // Is transparent
98 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::IsTransparent)
99 _MeshVector[slot].Flags|=CMeshSlot::IsTransparent;
101 // MeshGeom
102 nlassert (mbuild.LodMeshes[slot].MeshGeom);
104 // Valid pointer ?
105 if (_MeshVector[slot].Flags&CMeshSlot::CoarseMesh)
107 // If it is a coarse mesh, it must be a CMeshGeom.
108 if (dynamic_cast<CMeshGeom*>(mbuild.LodMeshes[slot].MeshGeom)==NULL)
110 // If it is a coarse mesh, it must be a CMeshGeom.
111 _MeshVector[slot].MeshGeom = NULL;
112 delete mbuild.LodMeshes[slot].MeshGeom;
114 else
115 // Ok, no prb
116 _MeshVector[slot].MeshGeom = mbuild.LodMeshes[slot].MeshGeom;
118 else
119 // Ok, no prb
120 _MeshVector[slot].MeshGeom = mbuild.LodMeshes[slot].MeshGeom;
123 // Sort the slot by the distance...
124 for (int i=(uint)mbuild.LodMeshes.size()-1; i>0; i--)
125 for (int j=0; j<i; j++)
127 // Bad sort ?
128 if (_MeshVector[j].DistMax>_MeshVector[j+1].DistMax)
130 // Exchange slots
131 CMeshSlot tmp=_MeshVector[j];
132 _MeshVector[j]=_MeshVector[j+1];
133 _MeshVector[j+1]=tmp;
134 tmp.MeshGeom=NULL;
138 // Calc start and end polygon count
139 for (uint k=0; k<mbuild.LodMeshes.size(); k++)
141 // Get start distance
142 float startDist;
143 if (k==0)
144 startDist=0;
145 else
146 startDist=_MeshVector[k-1].DistMax;
148 // Get start poly count
149 float startPolyCount;
150 startPolyCount=_MeshVector[k].MeshGeom->getNumTriangles (startDist);
152 // Get end distance
153 float endDist=_MeshVector[k].DistMax;
155 // Get end poly count
156 if (k==mbuild.LodMeshes.size()-1)
158 _MeshVector[k].EndPolygonCount=_MeshVector[k].MeshGeom->getNumTriangles (endDist);
159 if (startPolyCount==_MeshVector[k].EndPolygonCount)
160 _MeshVector[k].EndPolygonCount=startPolyCount/2;
162 else
163 _MeshVector[k].EndPolygonCount=_MeshVector[k+1].MeshGeom->getNumTriangles (endDist);
165 // Calc A
166 if (endDist==startDist)
167 _MeshVector[k].A=0;
168 else
169 _MeshVector[k].A=(_MeshVector[k].EndPolygonCount-startPolyCount)/(endDist-startDist);
171 // Calc A
172 _MeshVector[k].B=_MeshVector[k].EndPolygonCount-_MeshVector[k].A*endDist;
175 // End: compile some stuff
176 compileRunTime();
179 // ***************************************************************************
181 CTransformShape *CMeshMultiLod::createInstance(CScene &scene)
183 // Create a CMeshInstance, an instance of a multi lod mesh.
184 CMeshMultiLodInstance *mi=(CMeshMultiLodInstance*)scene.createModel(NL3D::MeshMultiLodInstanceId);
185 mi->Shape= this;
186 mi->_LastLodMatrixDate=0;
188 // instanciate the material part of the Mesh, ie the CMeshBase.
189 CMeshBase::instanciateMeshBase(mi, &scene);
191 // Create the necessary space for Coarse Instanciation
192 instanciateCoarseMeshSpace(mi);
194 // For all lods, do some instance init for MeshGeom
195 for(uint i=0; i<_MeshVector.size(); i++)
197 if(_MeshVector[i].MeshGeom)
198 _MeshVector[i].MeshGeom->initInstance(mi);
201 // init the Filter type
202 mi->initRenderFilterType();
205 return mi;
208 // ***************************************************************************
210 bool CMeshMultiLod::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
212 // Look for the biggest mesh
213 uint meshCount=(uint)_MeshVector.size();
214 for (uint i=0; i<meshCount; i++)
216 // Ref on slot
217 CMeshSlot &slot=_MeshVector[i];
219 // Is mesh present ?
220 if (slot.MeshGeom)
222 // Clip this mesh
223 return slot.MeshGeom->clip (pyramid, worldMatrix);
226 return true;
229 // ***************************************************************************
231 void CMeshMultiLod::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
233 // Render good meshes
234 CMeshMultiLodInstance *instance=safe_cast<CMeshMultiLodInstance*>(trans);
236 // Static or dynamic coarse mesh ?
237 CCoarseMeshManager *manager;
238 // Get the coarse mesh manager
239 manager=instance->getOwnerScene()->getCoarseMeshManager();
241 // *** Render Lods
243 // Second lod ?
244 if ( (instance->Lod1!=0xffffffff) && (passOpaque==false) )
246 // build rdrFlags to rdr both transparent and opaque materials,
247 // use globalAlphaBlend, and disable ZWrite for Lod1
248 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
249 IMeshGeom::RenderGlobalAlpha | IMeshGeom::RenderGADisableZWrite;
250 // NB: very important to render Lod1 first, because Lod0 is still rendered with ZWrite enabled.
251 renderMeshGeom (instance->Lod1, drv, instance, instance->PolygonCountLod1, rdrFlags, 1.f-instance->BlendFactor, manager);
255 // Have an opaque pass ?
256 if ( (instance->Flags&CMeshMultiLodInstance::Lod0Blend) == 0)
258 // Is this slot a CoarseMesh?
259 if ( _MeshVector[instance->Lod0].Flags&CMeshSlot::CoarseMesh )
261 // render as a CoarseMesh the lod 0, only in opaque pass
262 if(passOpaque)
263 renderCoarseMesh (instance->Lod0, drv, instance, manager);
265 else
267 // build rdrFlags the normal way (as CMesh::render() for example)
268 uint32 mask= (0-(uint32)passOpaque);
269 uint32 rdrFlags;
270 // select rdrFlags, without ifs.
271 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
272 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
273 // Only render the normal way the first lod
274 renderMeshGeom (instance->Lod0, drv, instance, instance->PolygonCountLod0, rdrFlags, 1, manager);
277 else
279 // Should not be in opaque
280 nlassert (passOpaque==false);
282 // build rdrFlags to rdr both transparent and opaque materials,
283 // use globalAlphaBlend, BUT Don't disable ZWrite for Lod0
284 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
285 IMeshGeom::RenderGlobalAlpha;
287 // Render first lod in blend mode. Don't disable ZWrite for Lod0
288 renderMeshGeom (instance->Lod0, drv, instance, instance->PolygonCountLod0, rdrFlags, instance->BlendFactor, manager);
292 // ***************************************************************************
294 void CMeshMultiLod::serial(NLMISC::IStream &f)
296 /* ***********************************************
297 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
298 * It can be loaded/called through CAsyncFileManager for instance
299 * ***********************************************/
301 // Serial a version number
302 (void)f.serialVersion (0);
304 // serial Materials infos contained in CMeshBase.
305 CMeshBase::serialMeshBase(f);
307 // Static lod flag
308 f.serial (_StaticLod);
310 // Serial the values
311 f.serialCont (_MeshVector);
314 // if reading, compile some stuff
315 if (f.isReading())
316 compileRunTime();
319 // ***************************************************************************
321 float CMeshMultiLod::getNumTrianglesWithCoarsestDist(float distance, float coarsestMeshDist) const
323 // Look in the table for good distances..
324 uint meshCount=(uint)_MeshVector.size();
326 // At least on mesh
327 if (meshCount>0)
330 if (coarsestMeshDist != -1)
332 if (coarsestMeshDist != 0)
334 // rescale distance to new coarse mesh distance..
335 distance *= _MeshVector[meshCount - 1].DistMax / coarsestMeshDist;
339 uint i=0;
340 // Look for good i
341 while ( _MeshVector[i].DistMax < distance)
343 if (i==meshCount-1)
344 // Abort if last one
345 break;
346 i++;
349 // Ref on slot
350 const CMeshSlot &slot=_MeshVector[i];
352 // Is mesh present ?
353 if (slot.MeshGeom)
355 // Get the polygon count with the distance
356 float polyCount=slot.A * distance + slot.B;
358 /*// Get the perfect polygon count in this slot for the asked distance
359 float goodPolyCount=slot.MeshGeom->getNumTriangles (distance);
361 // Get the next slot perfect polygon count
362 float realEndPolyCount;
364 // Last slot ?
365 if ( (i<meshCount-1) && _MeshVector[i+1].MeshGeom )
366 // Take end number polygon count in the next slot
367 realEndPolyCount=_MeshVector[i+1].MeshGeom->getNumTriangles (slot.DistMax);
368 else
369 // Take end number polygon count in the this slot
370 realEndPolyCount=slot.EndPolygonCount;
372 // Return blended polygon count to have a continous decreasing function
373 return (goodPolyCount-slot.BeginPolygonCount) * (realEndPolyCount-slot.BeginPolygonCount) /
374 (slot.EndPolygonCount-slot.BeginPolygonCount) + slot.BeginPolygonCount;*/
375 return polyCount;
379 return 0;
382 // ***************************************************************************
384 void CMeshMultiLod::getAABBox(NLMISC::CAABBox &bbox) const
386 // Get count
387 uint count=(uint)_MeshVector.size();
388 for (uint slot=0; slot<count; slot++)
390 // Shape ?
391 if (_MeshVector[slot].MeshGeom)
393 // Get the bounding box
394 bbox=_MeshVector[slot].MeshGeom->getBoundingBox().getAABBox();
396 // ok
397 break;
402 // ***************************************************************************
404 void CMeshMultiLod::clear ()
406 _MeshVector.clear ();
409 // ***************************************************************************
411 void CMeshMultiLod::CMeshSlot::serial(NLMISC::IStream &f)
413 // Check version
414 (void)f.serialVersion (0);
416 f.serialPolyPtr (MeshGeom);
417 f.serial (A);
418 f.serial (B);
419 f.serial (DistMax);
420 f.serial (EndPolygonCount);
421 f.serial (BlendLength);
422 f.serial (Flags);
424 if (f.isReading())
429 // ***************************************************************************
431 CMeshMultiLod::CMeshSlot::CMeshSlot ()
433 MeshGeom=NULL;
434 CoarseNumTris= 0;
437 // ***************************************************************************
439 CMeshMultiLod::CMeshSlot::~CMeshSlot ()
441 if (MeshGeom)
442 delete MeshGeom;
445 // ***************************************************************************
447 void CMeshMultiLod::renderMeshGeom (uint slot, IDriver *drv, CMeshMultiLodInstance *trans, float numPoylgons, uint32 rdrFlags, float alpha, CCoarseMeshManager *manager)
449 // Ref
450 CMeshSlot &slotRef=_MeshVector[slot];
452 // MeshGeom exist?
453 if (slotRef.MeshGeom)
455 // NB Here, the meshGeom may still be a coarseMesh, but rendered through CMeshGeom
456 if(slotRef.Flags&CMeshSlot::CoarseMesh)
458 // Render only for opaque material
459 if(manager && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) )
461 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
463 // Render the CoarseMesh with the manager material
464 CMaterial &material= manager->getMaterial();
466 // modulate material for alphaBlend transition
467 // ----------
468 // get average sun color for this coarseMesh
469 CRGBA newCol= trans->getCoarseMeshLighting();
471 // Use a CMeshBlender to modify material and driver.
472 CMeshBlender blender;
473 blender.prepareRenderForGlobalAlphaCoarseMesh(material, drv, newCol, alpha, gaDisableZWrite);
476 // render simple the coarseMesh
477 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
479 // Force corse mesh vertex buffer in system memory
480 const_cast<CVertexBuffer&>(meshGeom->getVertexBuffer ()).setPreferredMemory (CVertexBuffer::RAMPreferred, false);
482 meshGeom->renderSimpleWithMaterial(drv, trans->getWorldMatrix(), material);
485 // resetup standard CoarseMeshMaterial material values
486 // ----------
487 // blender restore
488 blender.restoreRenderCoarseMesh(material, drv, gaDisableZWrite);
491 else
493 // Render the geom mesh
494 // Disable ZWrite only if in transition and for rendering Lod1
495 slotRef.MeshGeom->render (drv, trans, numPoylgons, rdrFlags, alpha);
499 // ***************************************************************************
501 void CMeshMultiLod::renderCoarseMesh (uint slot, IDriver *drv, CMeshMultiLodInstance *trans, CCoarseMeshManager *manager)
503 // if the manager is NULL, quit.
504 if(manager==NULL)
505 return;
507 // get the scene
508 CScene *scene= trans->getOwnerScene();
509 if(!scene)
510 return;
512 // If filtered...
513 if( (scene->getFilterRenderFlags() & UScene::FilterCoarseMesh)==0 )
514 return;
516 // Ref
517 CMeshSlot &slotRef=_MeshVector[slot];
519 // the slot must be a Coarse mesh
520 nlassert(slotRef.Flags&CMeshSlot::CoarseMesh);
522 // Get a pointer on the geom mesh
523 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
525 // ** If not the same as Before (or if NULL before...)
526 if ( trans->_LastCoarseMesh!=meshGeom )
528 uint numVerts= meshGeom->getVertexBuffer().getNumVertices();
529 uint numTris= slotRef.CoarseNumTris;
530 // If empty meshGeom, erase cache (each frame, ugly but error mgt here...)
531 if( numTris==0 || numVerts==0 )
532 trans->_LastCoarseMesh= NULL;
533 else
535 // Cache
536 trans->_LastCoarseMesh= meshGeom;
537 trans->_LastCoarseMeshNumVertices= numVerts;
539 // Check setuped size.
540 nlassert( trans->_CoarseMeshVB.size() >= numVerts*manager->getVertexSize() );
542 // Fill only UVs here. (Pos updated in Matrix pass. Color in Lighting Pass)
543 trans->setUVCoarseMesh( *meshGeom, manager->getVertexSize(), manager->getUVOff() );
545 // Dirt the matrix
546 trans->_LastLodMatrixDate=0;
547 // Dirt the lighting. NB: period maximum is 255. Hence the -256, to ensure lighting compute now
548 trans->_LastLodLightingDate= -0x100;
552 // ** If setuped, update and render
553 if( trans->_LastCoarseMesh )
555 // Matrix has changed ?
556 if ( trans->ITransformable::compareMatrixDate (trans->_LastLodMatrixDate) )
558 // Get date
559 trans->_LastLodMatrixDate = trans->ITransformable::getMatrixDate();
561 // Set matrix
562 trans->setPosCoarseMesh ( *meshGeom, trans->getMatrix(), manager->getVertexSize() );
565 // Lighting: test if must update lighting, according to date of HrcTrav (num of CScene::render() call).
566 sint64 currentDate= scene->getHrcTrav().CurrentDate;
567 if( trans->_LastLodLightingDate < currentDate - scene->getCoarseMeshLightingUpdate() )
569 // reset the date.
570 trans->_LastLodLightingDate= currentDate;
572 // get average sun color
573 CRGBA sunContrib= trans->getCoarseMeshLighting();
575 // Invert BR if driver is BGRA
576 if(drv->getVertexColorFormat()==CVertexBuffer::TBGRA)
577 sunContrib.swapBR();
579 // Set color
580 trans->setColorCoarseMesh ( sunContrib, manager->getVertexSize(), manager->getColorOff());
583 // Add dynamic to the manager
584 if( !manager->addMesh(trans->_LastCoarseMeshNumVertices, &trans->_CoarseMeshVB[0], slotRef.CoarseNumTris, &slotRef.CoarseTriangles[0] ) )
586 // If failure, flush the manager
587 manager->flushRender(drv);
588 // then try to re-add. No-op if fails this time..
589 manager->addMesh(trans->_LastCoarseMeshNumVertices, &trans->_CoarseMeshVB[0], slotRef.CoarseNumTris, &slotRef.CoarseTriangles[0] );
595 // ***************************************************************************
596 void CMeshMultiLod::compileDistMax()
598 // Last element
599 if(_MeshVector.empty())
600 IShape::_DistMax= -1;
601 else
602 IShape::_DistMax= _MeshVector.back().DistMax;
605 // ***************************************************************************
606 const IMeshGeom& CMeshMultiLod::getMeshGeom (uint slot) const
608 // Checks
609 nlassert (slot<getNumSlotMesh ());
611 return *_MeshVector[slot].MeshGeom;
615 // ***************************************************************************
616 void CMeshMultiLod::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
618 // no-op if empty.
619 if(getNumSlotMesh ()==0)
620 return;
622 // If not NULL
623 if(_MeshVector[0].MeshGeom==NULL)
624 return;
626 // verify it is a CMeshMRMGeom. else no-op.
627 CMeshMRMGeom *mgeom= dynamic_cast<CMeshMRMGeom*>(_MeshVector[0].MeshGeom);
628 if(mgeom==NULL)
629 return;
631 // ok, setup.
632 mgeom->changeMRMDistanceSetup(distanceFinest, distanceMiddle, distanceCoarsest);
636 // ***************************************************************************
637 IMeshGeom *CMeshMultiLod::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
639 IMeshGeom *ret= NULL;
641 // get the instance
642 CMeshMultiLodInstance *instance=safe_cast<CMeshMultiLodInstance*>(trans);
644 // Must not be in blend transition.
645 if ( (instance->Flags&CMeshMultiLodInstance::Lod0Blend) == 0)
647 uint slot= instance->Lod0;
648 // The slot must not be a CoarseMesh
649 if ( (_MeshVector[slot].Flags&CMeshSlot::CoarseMesh)==0 )
651 // MeshGeom exist?
652 ret= _MeshVector[slot].MeshGeom;
656 // Ok if meshGeom is ok.
657 if( ret && ret->supportMeshBlockRendering() )
659 polygonCount= instance->PolygonCountLod0;
660 return ret;
662 else
663 return NULL;
667 // ***************************************************************************
668 void CMeshMultiLod::profileMeshGeom (uint slot, CRenderTrav *rdrTrav, CMeshMultiLodInstance *trans, float numPoylgons, uint32 rdrFlags)
670 // Ref
671 CMeshSlot &slotRef=_MeshVector[slot];
673 // MeshGeom exist?
674 if (slotRef.MeshGeom)
676 // NB Here, the meshGeom may still be a coarseMesh, but rendered through CMeshGeom
677 if(slotRef.Flags&CMeshSlot::CoarseMesh)
679 // Render only for opaque material
680 if(rdrFlags & IMeshGeom::RenderOpaqueMaterial)
682 slotRef.MeshGeom->profileSceneRender(rdrTrav, trans, numPoylgons, rdrFlags);
685 else
687 slotRef.MeshGeom->profileSceneRender(rdrTrav, trans, numPoylgons, rdrFlags);
693 // ***************************************************************************
694 void CMeshMultiLod::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
696 // Render good meshes
697 CMeshMultiLodInstance *instance=safe_cast<CMeshMultiLodInstance*>(trans);
700 // Second lod ?
701 if ( (instance->Lod1!=0xffffffff) && (passOpaque==false) )
703 // build rdrFlags to rdr both transparent and opaque materials,
704 // use globalAlphaBlend, and disable ZWrite for Lod1
705 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
706 IMeshGeom::RenderGlobalAlpha | IMeshGeom::RenderGADisableZWrite;
707 // NB: very important to render Lod1 first, because Lod0 is still rendered with ZWrite enabled.
708 profileMeshGeom (instance->Lod1, rdrTrav, instance, instance->PolygonCountLod1, rdrFlags);
712 // Have an opaque pass ?
713 if ( (instance->Flags&CMeshMultiLodInstance::Lod0Blend) == 0)
715 // Is this slot a CoarseMesh?
716 if ( _MeshVector[instance->Lod0].Flags&CMeshSlot::CoarseMesh )
719 else
721 // build rdrFlags the normal way (as CMesh::render() for example)
722 uint32 mask= (0-(uint32)passOpaque);
723 uint32 rdrFlags;
724 // select rdrFlags, without ifs.
725 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
726 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
727 // Only render the normal way the first lod
728 profileMeshGeom (instance->Lod0, rdrTrav, instance, instance->PolygonCountLod0, rdrFlags);
731 else
733 // Should not be in opaque
734 nlassert (passOpaque==false);
736 // build rdrFlags to rdr both transparent and opaque materials,
737 // use globalAlphaBlend, BUT Don't disable ZWrite for Lod0
738 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
739 IMeshGeom::RenderGlobalAlpha;
741 // Render first lod in blend mode. Don't disable ZWrite for Lod0
742 profileMeshGeom (instance->Lod0, rdrTrav, instance, instance->PolygonCountLod0, rdrFlags);
746 // ***************************************************************************
747 void CMeshMultiLod::instanciateCoarseMeshSpace(CMeshMultiLodInstance *mi)
749 CCoarseMeshManager *manager= mi->getOwnerScene()->getCoarseMeshManager();
751 if(manager)
753 // For all MeshSlots that have a CoarseMesh, count max Coarse NumVertices;
754 uint numVertices= 0;
755 for(uint i=0;i<_MeshVector.size();i++)
757 CMeshSlot &slotRef= _MeshVector[i];
758 if( slotRef.Flags & CMeshSlot::CoarseMesh )
760 // Get a pointer on the geom mesh
761 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
762 numVertices= max(numVertices, (uint)meshGeom->getVertexBuffer().getNumVertices() );
766 // Then allocate vertex space for dest manager vertex size.
767 mi->_CoarseMeshVB.resize( numVertices*manager->getVertexSize() );
771 // ***************************************************************************
772 void CMeshMultiLod::compileCoarseMeshes()
774 // For All Slots that are CoarseMeshes.
775 for(uint i=0;i<_MeshVector.size();i++)
777 CMeshSlot &slotRef= _MeshVector[i];
778 if( slotRef.Flags & CMeshSlot::CoarseMesh )
780 // reset
781 slotRef.CoarseNumTris= 0;
783 // Get a pointer on the geom mesh
784 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
786 // For All RdrPass of the 1st matrix block
787 if( meshGeom->getNbMatrixBlock()>0 )
789 // 1st count
790 for(uint i=0;i<meshGeom->getNbRdrPass(0);i++)
792 slotRef.CoarseNumTris+= meshGeom->getRdrPassPrimitiveBlock(0, i).getNumIndexes()/3;
795 // 2nd allocate and fill
796 if( slotRef.CoarseNumTris )
798 slotRef.CoarseTriangles.resize(slotRef.CoarseNumTris * 3);
799 TCoarseMeshIndexType *dstPtr= &slotRef.CoarseTriangles[0];
800 uint totalTris = 0;
801 for(uint i=0;i<meshGeom->getNbRdrPass(0);i++)
803 const CIndexBuffer &pb= meshGeom->getRdrPassPrimitiveBlock(0, i);
804 CIndexBufferRead ibaRead;
805 pb.lock (ibaRead);
806 uint numTris= pb.getNumIndexes()/3;
807 totalTris += numTris;
808 if (pb.getFormat() == CIndexBuffer::Indices16)
810 if (sizeof(TCoarseMeshIndexType) == sizeof(uint16))
812 memcpy(dstPtr, (uint16 *) ibaRead.getPtr(), numTris*3*sizeof(uint16));
813 dstPtr+= numTris*3;
815 else
817 // 16 -> 32
818 uint16 *src = (uint16 *) ibaRead.getPtr();
819 for(uint k = 0; k < numTris; ++k)
821 *dstPtr++ = (TCoarseMeshIndexType) *src++;
822 *dstPtr++ = (TCoarseMeshIndexType) *src++;
823 *dstPtr++ = (TCoarseMeshIndexType) *src++;
827 else
829 if (sizeof(TCoarseMeshIndexType) == sizeof(uint32))
831 memcpy(dstPtr, (uint32 *) ibaRead.getPtr(), numTris*3*sizeof(uint32));
832 dstPtr+= numTris*3;
834 else
836 const uint32 *src = (const uint32 *) ibaRead.getPtr();
837 for(uint k = 0; k < numTris; ++k)
839 // 32 -> 16
840 nlassert(src[0] <= 0xffff);
841 nlassert(src[1] <= 0xffff);
842 nlassert(src[2] <= 0xffff);
843 *dstPtr++ = (TCoarseMeshIndexType) *src++;
844 *dstPtr++ = (TCoarseMeshIndexType) *src++;
845 *dstPtr++ = (TCoarseMeshIndexType) *src++;
850 nlassert(totalTris == slotRef.CoarseNumTris);
858 // ***************************************************************************
859 void CMeshMultiLod::compileRunTime()
861 /* ***********************************************
862 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
863 * It can be loaded/called through CAsyncFileManager for instance
864 * ***********************************************/
866 // **** MultiLod basics
867 compileDistMax();
868 compileCoarseMeshes();
870 // **** try to build a Visual Collision Mesh
871 // clear first
872 if(_VisualCollisionMesh)
874 delete _VisualCollisionMesh;
875 _VisualCollisionMesh= NULL;
877 // build only if wanted
878 if( (_CollisionMeshGeneration==AutoCameraCol && !_LightInfos.empty()) ||
879 _CollisionMeshGeneration==ForceCameraCol )
881 // try to retrieve the info from a CMeshGeom only
882 if(getNumSlotMesh())
884 const CMeshGeom *meshGeom= dynamic_cast<const CMeshGeom*>(&getMeshGeom(0));
885 if(meshGeom)
887 vector<CVector> vertices;
888 vector<uint32> indices;
889 if(meshGeom->retrieveVertices(vertices) && meshGeom->retrieveTriangles(indices))
891 // ok, can build!
892 _VisualCollisionMesh= new CVisualCollisionMesh;
893 // if fails to build cause of too many vertices/indices for instance
894 if(!_VisualCollisionMesh->build(vertices, indices,const_cast<CVertexBuffer&>(meshGeom->getVertexBuffer())))
896 // delete
897 delete _VisualCollisionMesh;
898 _VisualCollisionMesh= NULL;
907 // ***************************************************************************
908 void CMeshMultiLod::buildSystemGeometry()
910 // clear any
911 _SystemGeometry.clear();
913 // Use the first lod, for system geometry copy
914 if(getNumSlotMesh())
916 // the first is a meshGeom?
917 const CMeshGeom *meshGeom= dynamic_cast<const CMeshGeom*>(&getMeshGeom(0));
918 if(meshGeom)
920 // retrieve geometry (if VB/IB not resident)
921 if( !meshGeom->retrieveVertices(_SystemGeometry.Vertices) ||
922 !meshGeom->retrieveTriangles(_SystemGeometry.Triangles))
924 _SystemGeometry.clear();
927 // else it is a mrm geom?
928 else
930 const CMeshMRMGeom *meshMRMGeom= dynamic_cast<const CMeshMRMGeom*>(&getMeshGeom(0));
931 if(meshMRMGeom)
933 // Choose the best Lod available for system geometry
934 if(meshMRMGeom->getNbLodLoaded()==0)
935 return;
936 uint lodId= meshMRMGeom->getNbLodLoaded()-1;
938 // retrieve geometry (if VB/IB not resident)
939 if( !meshMRMGeom->buildGeometryForLod(lodId, _SystemGeometry.Vertices, _SystemGeometry.Triangles) )
941 _SystemGeometry.clear();
947 // TestYoyo
948 /*static uint32 totalMem= 0;
949 totalMem+= _SystemGeometry.Vertices.size()*sizeof(CVector);
950 totalMem+= _SystemGeometry.Triangles.size()*sizeof(uint32);
951 nlinfo("CMeshMultiLod: TotalMem: %d", totalMem);*/
954 } // NL3D