1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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
;
50 // ***************************************************************************
52 void CMeshMultiLod::build(CMeshMultiLodBuild
&mbuild
)
57 // Build the base mesh
58 CMeshBase::buildMeshBase (mbuild
.BaseMesh
);
61 _StaticLod
=mbuild
.StaticLod
;
64 _MeshVector
.resize (mbuild
.LodMeshes
.size());
67 for (uint slot
=0; slot
<mbuild
.LodMeshes
.size(); slot
++)
70 _MeshVector
[slot
].DistMax
=mbuild
.LodMeshes
[slot
].DistMax
;
73 _MeshVector
[slot
].BlendLength
=mbuild
.LodMeshes
[slot
].BlendLength
;
76 _MeshVector
[slot
].Flags
=0;
79 if (mbuild
.LodMeshes
[slot
].Flags
& CMeshMultiLodBuild::CBuildSlot::BlendIn
)
80 _MeshVector
[slot
].Flags
|=CMeshSlot::BlendIn
;
83 if (mbuild
.LodMeshes
[slot
].Flags
& CMeshMultiLodBuild::CBuildSlot::BlendOut
)
84 _MeshVector
[slot
].Flags
|=CMeshSlot::BlendOut
;
87 if (mbuild
.LodMeshes
[slot
].Flags
& CMeshMultiLodBuild::CBuildSlot::CoarseMesh
)
90 _MeshVector
[slot
].Flags
|=CMeshSlot::CoarseMesh
;
94 if (mbuild
.LodMeshes
[slot
].Flags
& CMeshMultiLodBuild::CBuildSlot::IsOpaque
)
95 _MeshVector
[slot
].Flags
|=CMeshSlot::IsOpaque
;
98 if (mbuild
.LodMeshes
[slot
].Flags
& CMeshMultiLodBuild::CBuildSlot::IsTransparent
)
99 _MeshVector
[slot
].Flags
|=CMeshSlot::IsTransparent
;
102 nlassert (mbuild
.LodMeshes
[slot
].MeshGeom
);
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
;
116 _MeshVector
[slot
].MeshGeom
= mbuild
.LodMeshes
[slot
].MeshGeom
;
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
++)
128 if (_MeshVector
[j
].DistMax
>_MeshVector
[j
+1].DistMax
)
131 CMeshSlot tmp
=_MeshVector
[j
];
132 _MeshVector
[j
]=_MeshVector
[j
+1];
133 _MeshVector
[j
+1]=tmp
;
138 // Calc start and end polygon count
139 for (uint k
=0; k
<mbuild
.LodMeshes
.size(); k
++)
141 // Get start distance
146 startDist
=_MeshVector
[k
-1].DistMax
;
148 // Get start poly count
149 float startPolyCount
;
150 startPolyCount
=_MeshVector
[k
].MeshGeom
->getNumTriangles (startDist
);
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;
163 _MeshVector
[k
].EndPolygonCount
=_MeshVector
[k
+1].MeshGeom
->getNumTriangles (endDist
);
166 if (endDist
==startDist
)
169 _MeshVector
[k
].A
=(_MeshVector
[k
].EndPolygonCount
-startPolyCount
)/(endDist
-startDist
);
172 _MeshVector
[k
].B
=_MeshVector
[k
].EndPolygonCount
-_MeshVector
[k
].A
*endDist
;
175 // End: compile some stuff
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
);
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();
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
++)
217 CMeshSlot
&slot
=_MeshVector
[i
];
223 return slot
.MeshGeom
->clip (pyramid
, worldMatrix
);
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();
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
263 renderCoarseMesh (instance
->Lod0
, drv
, instance
, manager
);
267 // build rdrFlags the normal way (as CMesh::render() for example)
268 uint32 mask
= (0-(uint32
)passOpaque
);
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
);
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
);
308 f
.serial (_StaticLod
);
311 f
.serialCont (_MeshVector
);
314 // if reading, compile some stuff
319 // ***************************************************************************
321 float CMeshMultiLod::getNumTrianglesWithCoarsestDist(float distance
, float coarsestMeshDist
) const
323 // Look in the table for good distances..
324 uint meshCount
=(uint
)_MeshVector
.size();
330 if (coarsestMeshDist
!= -1)
332 if (coarsestMeshDist
!= 0)
334 // rescale distance to new coarse mesh distance..
335 distance
*= _MeshVector
[meshCount
- 1].DistMax
/ coarsestMeshDist
;
341 while ( _MeshVector
[i
].DistMax
< distance
)
350 const CMeshSlot
&slot
=_MeshVector
[i
];
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;
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);
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;*/
382 // ***************************************************************************
384 void CMeshMultiLod::getAABBox(NLMISC::CAABBox
&bbox
) const
387 uint count
=(uint
)_MeshVector
.size();
388 for (uint slot
=0; slot
<count
; slot
++)
391 if (_MeshVector
[slot
].MeshGeom
)
393 // Get the bounding box
394 bbox
=_MeshVector
[slot
].MeshGeom
->getBoundingBox().getAABBox();
402 // ***************************************************************************
404 void CMeshMultiLod::clear ()
406 _MeshVector
.clear ();
409 // ***************************************************************************
411 void CMeshMultiLod::CMeshSlot::serial(NLMISC::IStream
&f
)
414 (void)f
.serialVersion (0);
416 f
.serialPolyPtr (MeshGeom
);
420 f
.serial (EndPolygonCount
);
421 f
.serial (BlendLength
);
429 // ***************************************************************************
431 CMeshMultiLod::CMeshSlot::CMeshSlot ()
437 // ***************************************************************************
439 CMeshMultiLod::CMeshSlot::~CMeshSlot ()
445 // ***************************************************************************
447 void CMeshMultiLod::renderMeshGeom (uint slot
, IDriver
*drv
, CMeshMultiLodInstance
*trans
, float numPoylgons
, uint32 rdrFlags
, float alpha
, CCoarseMeshManager
*manager
)
450 CMeshSlot
&slotRef
=_MeshVector
[slot
];
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
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
488 blender
.restoreRenderCoarseMesh(material
, drv
, gaDisableZWrite
);
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.
508 CScene
*scene
= trans
->getOwnerScene();
513 if( (scene
->getFilterRenderFlags() & UScene::FilterCoarseMesh
)==0 )
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
;
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() );
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
) )
559 trans
->_LastLodMatrixDate
= trans
->ITransformable::getMatrixDate();
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() )
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
)
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()
599 if(_MeshVector
.empty())
600 IShape::_DistMax
= -1;
602 IShape::_DistMax
= _MeshVector
.back().DistMax
;
605 // ***************************************************************************
606 const IMeshGeom
& CMeshMultiLod::getMeshGeom (uint slot
) const
609 nlassert (slot
<getNumSlotMesh ());
611 return *_MeshVector
[slot
].MeshGeom
;
615 // ***************************************************************************
616 void CMeshMultiLod::changeMRMDistanceSetup(float distanceFinest
, float distanceMiddle
, float distanceCoarsest
)
619 if(getNumSlotMesh ()==0)
623 if(_MeshVector
[0].MeshGeom
==NULL
)
626 // verify it is a CMeshMRMGeom. else no-op.
627 CMeshMRMGeom
*mgeom
= dynamic_cast<CMeshMRMGeom
*>(_MeshVector
[0].MeshGeom
);
632 mgeom
->changeMRMDistanceSetup(distanceFinest
, distanceMiddle
, distanceCoarsest
);
636 // ***************************************************************************
637 IMeshGeom
*CMeshMultiLod::supportMeshBlockRendering (CTransformShape
*trans
, float &polygonCount
) const
639 IMeshGeom
*ret
= NULL
;
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 )
652 ret
= _MeshVector
[slot
].MeshGeom
;
656 // Ok if meshGeom is ok.
657 if( ret
&& ret
->supportMeshBlockRendering() )
659 polygonCount
= instance
->PolygonCountLod0
;
667 // ***************************************************************************
668 void CMeshMultiLod::profileMeshGeom (uint slot
, CRenderTrav
*rdrTrav
, CMeshMultiLodInstance
*trans
, float numPoylgons
, uint32 rdrFlags
)
671 CMeshSlot
&slotRef
=_MeshVector
[slot
];
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
);
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
);
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
)
721 // build rdrFlags the normal way (as CMesh::render() for example)
722 uint32 mask
= (0-(uint32
)passOpaque
);
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
);
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();
753 // For all MeshSlots that have a CoarseMesh, count max Coarse NumVertices;
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
)
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 )
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];
801 for(uint i
=0;i
<meshGeom
->getNbRdrPass(0);i
++)
803 const CIndexBuffer
&pb
= meshGeom
->getRdrPassPrimitiveBlock(0, i
);
804 CIndexBufferRead 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
));
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
++;
829 if (sizeof(TCoarseMeshIndexType
) == sizeof(uint32
))
831 memcpy(dstPtr
, (uint32
*) ibaRead
.getPtr(), numTris
*3*sizeof(uint32
));
836 const uint32
*src
= (const uint32
*) ibaRead
.getPtr();
837 for(uint k
= 0; k
< numTris
; ++k
)
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
868 compileCoarseMeshes();
870 // **** try to build a Visual Collision Mesh
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
884 const CMeshGeom
*meshGeom
= dynamic_cast<const CMeshGeom
*>(&getMeshGeom(0));
887 vector
<CVector
> vertices
;
888 vector
<uint32
> indices
;
889 if(meshGeom
->retrieveVertices(vertices
) && meshGeom
->retrieveTriangles(indices
))
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())))
897 delete _VisualCollisionMesh
;
898 _VisualCollisionMesh
= NULL
;
907 // ***************************************************************************
908 void CMeshMultiLod::buildSystemGeometry()
911 _SystemGeometry
.clear();
913 // Use the first lod, for system geometry copy
916 // the first is a meshGeom?
917 const CMeshGeom
*meshGeom
= dynamic_cast<const CMeshGeom
*>(&getMeshGeom(0));
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?
930 const CMeshMRMGeom
*meshMRMGeom
= dynamic_cast<const CMeshMRMGeom
*>(&getMeshGeom(0));
933 // Choose the best Lod available for system geometry
934 if(meshMRMGeom
->getNbLodLoaded()==0)
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();
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);*/