Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / mesh.cpp
blob325f26f8c65731453aca17307b25ce2227879346
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/mesh.h"
20 #include "nel/3d/mesh_instance.h"
21 #include "nel/3d/scene.h"
22 #include "nel/3d/skeleton_model.h"
23 #include "nel/3d/mesh_morpher.h"
24 #include "nel/misc/bsphere.h"
25 #include "nel/3d/stripifier.h"
26 #include "nel/misc/fast_floor.h"
27 #include "nel/misc/hierarchical_timer.h"
28 #include "nel/3d/mesh_blender.h"
29 #include "nel/3d/matrix_3x4.h"
30 #include "nel/3d/render_trav.h"
31 #include "nel/3d/visual_collision_mesh.h"
32 #include "nel/3d/meshvp_wind_tree.h"
33 #include "nel/3d/vertex_stream_manager.h"
35 using namespace std;
36 using namespace NLMISC;
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 namespace NL3D
48 // ***************************************************************************
49 // ***************************************************************************
50 // MeshGeom Tools.
51 // ***************************************************************************
52 // ***************************************************************************
55 // ***************************************************************************
56 static NLMISC::CAABBoxExt makeBBox(const std::vector<CVector> &Vertices)
58 NLMISC::CAABBox ret;
59 nlassert(!Vertices.empty());
60 ret.setCenter(Vertices[0]);
61 for(sint i=0;i<(sint)Vertices.size();i++)
63 ret.extend(Vertices[i]);
66 return ret;
70 // ***************************************************************************
71 sint CMeshGeom::CCornerTmp::Flags=0;
74 // ***************************************************************************
75 bool CMeshGeom::CCornerTmp::operator<(const CCornerTmp &c) const
77 sint i;
79 // Vert first.
80 if(Vertex!=c.Vertex)
81 return Vertex<c.Vertex;
83 // Order: normal, uvs, color0, color1, skinning.
84 if((CCornerTmp::Flags & CVertexBuffer::NormalFlag) && Normal!=c.Normal)
85 return Normal<c.Normal;
86 for(i=0; i<CVertexBuffer::MaxStage; i++)
88 if((CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i)) && Uvws[i]!=c.Uvws[i])
89 return Uvws[i]<c.Uvws[i];
91 if((CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag) && Color!=c.Color)
92 return Color<c.Color;
93 if((CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag) && Specular!=c.Specular)
94 return Specular<c.Specular;
96 if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
98 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
100 if(Palette.MatrixId[i] != c.Palette.MatrixId[i])
101 return Palette.MatrixId[i] < c.Palette.MatrixId[i];
102 if(Weights[i] != c.Weights[i])
103 return Weights[i] < c.Weights[i];
108 // All are equal!!
109 return false;
113 // ***************************************************************************
114 // ***************************************************************************
115 // CMeshGeom.
116 // ***************************************************************************
117 // ***************************************************************************
120 // ***************************************************************************
121 CMeshGeom::CMeshGeom()
123 /* ***********************************************
124 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
125 * It can be loaded/called through CAsyncFileManager for instance
126 * ***********************************************/
128 _Skinned= false;
129 _OriginalSkinRestored= true;
130 _MeshMorpher = new CMeshMorpher;
131 _BoneIdComputed = false;
132 _BoneIdExtended= false;
133 _PreciseClipping= false;
137 // ***************************************************************************
138 CMeshGeom::~CMeshGeom()
140 /* ***********************************************
141 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
142 * It can be loaded/called through CAsyncFileManager for instance
143 * ***********************************************/
145 delete _MeshMorpher;
149 // ***************************************************************************
150 void CMeshGeom::optimizeTriangleOrder()
152 CStripifier stripifier;
154 // for all rdrpass of all matrix blocks.
155 for(uint mb= 0;mb<_MatrixBlocks.size();mb++)
157 for(uint rp=0; rp<_MatrixBlocks[mb].RdrPass.size(); rp++ )
159 // stripify list of triangles of this pass.
160 CRdrPass &pass= _MatrixBlocks[mb].RdrPass[rp];
161 stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
168 // ***************************************************************************
169 void CMeshGeom::build (CMesh::CMeshBuild &m, uint numMaxMaterial)
171 sint i;
173 // Empty geometry?
174 if(m.Vertices.empty() || m.Faces.empty())
176 _VBuffer.setNumVertices(0);
177 _VBuffer.setName("CMeshGeom");
178 _VBuffer.reserve(0);
179 _MatrixBlocks.clear();
180 _BBox.setCenter(CVector::Null);
181 _BBox.setSize(CVector::Null);
182 return;
184 nlassert(numMaxMaterial>0);
186 // Copy the UV routing table
187 for (i=0; i<CVertexBuffer::MaxStage; i++)
188 _VBuffer.setUVRouting (i, m.UVRouting[i]);
190 /// 0. First, make bbox.
191 //======================
192 _BBox= makeBBox(m.Vertices);
195 /// 1. If skinning, group by matrix Block the vertices.
196 //================================================
198 // First, copy Face array.
199 vector<CFaceTmp> tmpFaces;
200 tmpFaces.resize(m.Faces.size());
201 for(i=0;i<(sint)tmpFaces.size();i++)
202 tmpFaces[i]= m.Faces[i];
204 _Skinned= ((m.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
205 // Skinning is OK only if SkinWeights are of same size as vertices.
206 _Skinned= _Skinned && (m.Vertices.size()==m.SkinWeights.size());
208 // If skinning is KO, remove the Skin option.
209 uint vbFlags= m.VertexFlags;
210 if(!_Skinned)
211 vbFlags&= ~CVertexBuffer::PaletteSkinFlag;
212 // Force presence of vertex.
213 vbFlags|= CVertexBuffer::PositionFlag;
216 // If the mesh is not skinned, we have just 1 _MatrixBlocks.
217 if(!_Skinned)
219 _MatrixBlocks.resize(1);
220 // For each faces, assign it to the matrix block 0.
221 for(i=0;i<(sint)tmpFaces.size();i++)
222 tmpFaces[i].MatrixBlockId= 0;
224 // Else We must group/compute the matrixs blocks.
225 else
227 // reset matrix blocks.
228 _MatrixBlocks.clear();
229 // build matrix blocks, and link faces to good matrix blocks.
230 buildSkin(m, tmpFaces);
233 /// 2. Then, for all faces, resolve continuities, building VBuffer.
234 //================================================
235 // Setup VB.
236 _VBuffer.setNumVertices(0);
237 _VBuffer.reserve(0);
239 bool useFormatExt = false;
240 /** If all texture coordinates are of dimension 2, we can setup the flags as before.
241 * If this isn't the case, we must setup a custom format
243 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
245 if (
246 (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
247 && m.NumCoords[k] != 2)
249 useFormatExt = true;
250 break;
254 if (!useFormatExt)
256 // setup standard format
257 _VBuffer.setVertexFormat(vbFlags);
259 else // setup extended format
261 _VBuffer.clearValueEx();
262 if (vbFlags & CVertexBuffer::PositionFlag) _VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
263 if (vbFlags & CVertexBuffer::NormalFlag) _VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
264 if (vbFlags & CVertexBuffer::PrimaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
265 if (vbFlags & CVertexBuffer::SecondaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
266 if (vbFlags & CVertexBuffer::WeightFlag) _VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
267 if (vbFlags & CVertexBuffer::PaletteSkinFlag) _VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
268 if (vbFlags & CVertexBuffer::FogFlag) _VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
270 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
272 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
274 switch(m.NumCoords[k])
276 case 2:
277 _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
278 break;
279 case 3:
280 _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
281 break;
282 default:
283 nlassert(0);
284 break;
288 _VBuffer.initEx();
291 // Set local flags for corner comparison.
292 CCornerTmp::Flags= vbFlags;
293 // Setup locals.
294 TCornerSet corners;
295 const CFaceTmp *pFace= &(*tmpFaces.begin());
296 uint32 nFaceMB = 0;
297 sint N= (sint)tmpFaces.size();
298 sint currentVBIndex=0;
300 m.VertLink.clear ();
302 // process each face, building up the VB.
303 for(;N>0;N--, pFace++)
305 sint v0= pFace->Corner[0].Vertex;
306 sint v1= pFace->Corner[1].Vertex;
307 sint v2= pFace->Corner[2].Vertex;
308 findVBId(corners, &pFace->Corner[0], currentVBIndex, m.Vertices[v0], m);
309 findVBId(corners, &pFace->Corner[1], currentVBIndex, m.Vertices[v1], m);
310 findVBId(corners, &pFace->Corner[2], currentVBIndex, m.Vertices[v2], m);
311 CMesh::CVertLink vl1(nFaceMB, 0, pFace->Corner[0].VBId);
312 CMesh::CVertLink vl2(nFaceMB, 1, pFace->Corner[1].VBId);
313 CMesh::CVertLink vl3(nFaceMB, 2, pFace->Corner[2].VBId);
314 m.VertLink.push_back(vl1);
315 m.VertLink.push_back(vl2);
316 m.VertLink.push_back(vl3);
317 ++nFaceMB;
321 /// 3. build the RdrPass material.
322 //================================
323 uint mb;
325 // For each _MatrixBlocks, point on those materials.
326 for(mb= 0;mb<_MatrixBlocks.size();mb++)
328 // Build RdrPass ids.
329 _MatrixBlocks[mb].RdrPass.resize (numMaxMaterial);
331 for(i=0;i<(sint)_MatrixBlocks[mb].RdrPass.size(); i++)
333 _MatrixBlocks[mb].RdrPass[i].MaterialId= i;
334 // for build, force 32 bit indices
335 _MatrixBlocks[mb].RdrPass[i].PBlock.setFormat(CIndexBuffer::Indices32);
340 /// 4. Then, for all faces, build the RdrPass PBlock.
341 //===================================================
342 pFace= &(*tmpFaces.begin());
343 N= (sint)tmpFaces.size();
344 for(;N>0;N--, pFace++)
346 sint mbId= pFace->MatrixBlockId;
347 nlassert(mbId>=0 && mbId<(sint)_MatrixBlocks.size());
348 // Insert the face in good MatrixBlock/RdrPass.
349 CIndexBuffer &ib = _MatrixBlocks[mbId].RdrPass[pFace->MaterialId].PBlock;
350 uint index = ib.getNumIndexes();
351 ib.setNumIndexes (index+3);
352 CIndexBufferReadWrite iba;
353 ib.lock (iba);
354 iba.setTri(index, pFace->Corner[0].VBId, pFace->Corner[1].VBId, pFace->Corner[2].VBId);
358 /// 5. Remove empty RdrPasses.
359 //============================
360 for(mb= 0;mb<_MatrixBlocks.size();mb++)
362 // NB: slow process (erase from a vector). Doens't matter since made at build.
363 vector<CRdrPass>::iterator itPass;
364 for( itPass=_MatrixBlocks[mb].RdrPass.begin(); itPass!=_MatrixBlocks[mb].RdrPass.end(); )
366 // If this pass is empty, remove it.
367 if( itPass->PBlock.getNumIndexes()==0 )
368 itPass= _MatrixBlocks[mb].RdrPass.erase(itPass);
369 else
370 itPass++;
374 /// 6. Misc.
375 //============================
376 // BShapes
377 this->_MeshMorpher->BlendShapes = m.BlendShapes;
379 // sort triangles for better cache use.
380 optimizeTriangleOrder();
382 // SmartPtr Copy VertexProgram effect.
383 this->_MeshVertexProgram= m.MeshVertexProgram;
385 /// 7. Compact bones id and build bones name array.
386 //=================================================
388 // If skinned
389 if(_Skinned)
391 // Reserve some space
392 _BonesName.reserve (m.BonesNames.size ());
394 // Current local bone
395 uint currentBone = 0;
397 // For each matrix block
398 uint matrixBlock;
399 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
401 // Ref on the matrix block
402 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
404 // Remap the skeleton index in model index
405 std::map<uint, uint> remap;
407 // For each matrix
408 uint matrix;
409 for (matrix=0; matrix<mb.NumMatrix; matrix++)
411 // Get bone id in the skeleton
412 std::map<uint, uint>::iterator ite = remap.find (mb.MatrixId[matrix]);
414 // Not found
415 if (ite == remap.end())
417 // Insert it
418 remap.insert (std::map<uint, uint>::value_type (mb.MatrixId[matrix], currentBone));
420 // Check the matrix id
421 nlassert (mb.MatrixId[matrix] < m.BonesNames.size());
423 // Set the bone name
424 _BonesName.push_back (m.BonesNames[mb.MatrixId[matrix]]);
426 // Set the id in local
427 mb.MatrixId[matrix] = currentBone++;
429 else
431 // Set the id in local
432 mb.MatrixId[matrix] = ite->second;
437 // Bone id in local
438 _BoneIdComputed = false;
439 _BoneIdExtended = false;
442 // Set the vertex buffer preferred memory
443 bool avoidVBHard= _Skinned || ( _MeshMorpher && !_MeshMorpher->BlendShapes.empty() );
444 _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
446 // End!!
447 // Some runtime not serialized compilation
448 compileRunTime();
451 // ***************************************************************************
452 void CMeshGeom::setBlendShapes(std::vector<CBlendShape>&bs)
454 _MeshMorpher->BlendShapes = bs;
455 // must update some RunTime parameters
456 compileRunTime();
460 // ***************************************************************************
461 void CMeshGeom::applyMaterialRemap(const std::vector<sint> &remap)
463 for(uint mb=0;mb<getNbMatrixBlock();mb++)
465 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
467 // remap
468 uint32 &matId= _MatrixBlocks[mb].RdrPass[rp].MaterialId;
469 nlassert(remap[matId]>=0);
470 matId= remap[matId];
476 // ***************************************************************************
477 void CMeshGeom::initInstance(CMeshBaseInstance *mbi)
479 // init the instance with _MeshVertexProgram infos
480 if(_MeshVertexProgram)
481 _MeshVertexProgram->initInstance(mbi);
484 // ***************************************************************************
485 bool CMeshGeom::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
487 // Speed Clip: clip just the sphere.
488 CBSphere localSphere(_BBox.getCenter(), _BBox.getRadius());
489 CBSphere worldSphere;
491 // transform the sphere in WorldMatrix (with nearly good scale info).
492 localSphere.applyTransform(worldMatrix, worldSphere);
494 // if out of only plane, entirely out.
495 for(sint i=0;i<(sint)pyramid.size();i++)
497 // We are sure that pyramid has normalized plane normals.
498 // if SpherMax OUT return false.
499 float d= pyramid[i]*worldSphere.Center;
500 if(d>worldSphere.Radius)
501 return false;
504 // test if must do a precise clip, according to mesh size.
505 if( _PreciseClipping )
507 CPlane localPlane;
509 // if out of only plane, entirely out.
510 for(sint i=0;i<(sint)pyramid.size();i++)
512 // Transform the pyramid in Object space.
513 localPlane= pyramid[i]*worldMatrix;
514 // localPlane must be normalized, because worldMatrix mya have a scale.
515 localPlane.normalize();
516 // if the box is not partially inside the plane, quit
517 if( !_BBox.clipBack(localPlane) )
518 return false;
522 return true;
525 // ***************************************************************************
526 void CMeshGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
528 nlassert(drv);
529 // get the mesh instance.
530 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
531 // get a ptr on scene
532 CScene *ownerScene= mi->getOwnerScene();
533 // get a ptr on renderTrav
534 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
536 // Soft vb if not supported by the driver
537 if (drv->slowUnlockVertexBufferHard())
538 _VBuffer.setPreferredMemory (CVertexBuffer::RAMPreferred, false);
540 // get the skeleton model to which I am binded (else NULL).
541 CSkeletonModel *skeleton;
542 skeleton= mi->getSkeletonModel();
543 // The mesh must not be skinned for render()
544 nlassert(!(_Skinned && mi->isSkinned() && skeleton));
545 bool bMorphApplied = !_MeshMorpher->BlendShapes.empty();
546 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
549 // Profiling
550 //===========
551 H_AUTO( NL3D_MeshGeom_RenderNormal );
554 // Morphing
555 // ========
556 if (bMorphApplied)
558 // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
559 // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
560 // are written in the preceding call to restoreOriginalSkinPart.
561 if (_Skinned)
563 _MeshMorpher->initSkinned(&_VBufferOri,
564 &_VBuffer,
565 useTangentSpace,
566 &_OriginalSkinVertices,
567 &_OriginalSkinNormals,
568 useTangentSpace ? &_OriginalTGSpace : NULL,
569 false );
570 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
572 else // Not even skinned so we have to do all the stuff
574 _MeshMorpher->init(&_VBufferOri,
575 &_VBuffer,
576 useTangentSpace);
577 _MeshMorpher->update (mi->getBlendShapeFactors());
582 // Skinning
583 // ========
585 // else setup instance matrix
586 drv->setupModelMatrix(trans->getWorldMatrix());
589 // since instance skin is invalid but mesh is skinned , we must copy vertices/normals from original vertices.
590 if (_Skinned)
592 // do it for this Lod only, and if cache say it is necessary.
593 if (!_OriginalSkinRestored)
594 restoreOriginalSkinVertices();
598 // Setup meshVertexProgram
599 //===========
601 // use MeshVertexProgram effect?
602 bool useMeshVP= _MeshVertexProgram != NULL;
603 if( useMeshVP )
605 CMatrix invertedObjectMatrix;
606 invertedObjectMatrix = trans->getWorldMatrix().inverted();
607 // really ok if success to begin VP
608 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
609 if (!useMeshVP && !mi->_VPWindTreeFixed)
611 if (dynamic_cast<CMeshVPWindTree *>(&(*_MeshVertexProgram)))
613 // fix for mesh tree v.p : all material should be lighted
614 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
616 CMatrixBlock &mBlock= _MatrixBlocks[mb];
617 for(uint i=0;i<mBlock.RdrPass.size();i++)
619 CMaterial &mat=mi->Materials[mBlock.RdrPass[i].MaterialId];
620 mat.setLighting(true, mat.getEmissive(), mat.getAmbient(), mat.getDiffuse(), mat.getSpecular());
624 mi->_VPWindTreeFixed = true;
630 // Render the mesh.
631 //===========
632 // active VB.
633 drv->activeVertexBuffer(_VBuffer);
636 // Global alpha used ?
637 uint32 globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
638 uint8 globalAlphaInt=(uint8)NLMISC::OptFastFloor(globalAlpha*255);
641 // For all _MatrixBlocks
642 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
644 CMatrixBlock &mBlock= _MatrixBlocks[mb];
645 if(mBlock.RdrPass.empty())
646 continue;
648 // Global alpha ?
649 if (globalAlphaUsed)
651 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
653 // Render all pass.
654 for (uint i=0;i<mBlock.RdrPass.size();i++)
656 CRdrPass &rdrPass= mBlock.RdrPass[i];
657 // Render with the Materials of the MeshInstance.
658 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
659 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
661 // CMaterial Ref
662 CMaterial &material=mi->Materials[rdrPass.MaterialId];
664 // Use a MeshBlender to modify material and driver.
665 CMeshBlender blender;
666 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
668 // Setup VP material
669 if (useMeshVP)
671 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
674 // Render
675 drv->activeIndexBuffer(rdrPass.PBlock);
676 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
678 // Resetup material/driver
679 blender.restoreRender(material, drv, gaDisableZWrite);
683 else
685 // Render all pass.
686 for(uint i=0;i<mBlock.RdrPass.size();i++)
688 CRdrPass &rdrPass= mBlock.RdrPass[i];
689 // Render with the Materials of the MeshInstance.
690 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
691 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
693 // CMaterial Ref
694 CMaterial &material=mi->Materials[rdrPass.MaterialId];
696 // Setup VP material
697 if (useMeshVP)
699 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
702 // render primitives
703 drv->activeIndexBuffer(rdrPass.PBlock);
704 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
710 // End VertexProgram effect
711 if(useMeshVP)
713 // Apply it.
714 _MeshVertexProgram->end(drv);
719 // ***************************************************************************
720 void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM)
722 // get the mesh instance.
723 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
724 // get a ptr on scene
725 CScene *ownerScene= mi->getOwnerScene();
726 // get a ptr on renderTrav
727 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
728 // get a ptr on the driver
729 IDriver *drv= renderTrav->getDriver();
730 nlassert(drv);
732 // get the skeleton model to which I am binded (else NULL).
733 CSkeletonModel *skeleton;
734 skeleton= mi->getSkeletonModel();
735 // must be skinned for renderSkin()
736 nlassert(_Skinned && mi->isSkinned() && skeleton);
737 bool bMorphApplied = !_MeshMorpher->BlendShapes.empty();
738 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
741 // Profiling
742 //===========
743 H_AUTO( NL3D_MeshGeom_RenderSkinned );
746 // Morphing
747 // ========
748 if (bMorphApplied)
750 // Since Skinned we must update original skin vertices and normals because skinning use it
751 _MeshMorpher->initSkinned(&_VBufferOri,
752 &_VBuffer,
753 useTangentSpace,
754 &_OriginalSkinVertices,
755 &_OriginalSkinNormals,
756 useTangentSpace ? &_OriginalTGSpace : NULL,
757 true );
758 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
762 // Skinning
763 // ========
765 // NB: the skeleton matrix has already been setuped by CSkeletonModel
766 // NB: the normalize flag has already been setuped by CSkeletonModel
768 bool supportVertexStream = ((_VBuffer.getVertexFormat() & ~(CVertexBuffer::PaletteSkinFlag | CVertexBuffer::WeightFlag))
769 == (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag))
770 && (_VBuffer.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2)
771 && (_OriginalSkinNormals.size()) && (!_OriginalTGSpace.size());
772 CVertexStreamManager *meshSkinManager = renderTrav->getMeshSkinManager();
774 if (supportVertexStream)
776 uint maxVertices = meshSkinManager->getMaxVertices();
777 uint vertexSize = meshSkinManager->getVertexSize();
779 if (maxVertices >= _OriginalSkinVertices.size() && vertexSize == 32)
781 // apply the skinning
782 uint8 *dstVb = meshSkinManager->lock();
783 applySkin(dstVb, skeleton);
784 meshSkinManager->unlock(_OriginalSkinVertices.size());
786 else
788 supportVertexStream = false;
789 nlwarning("Unable to animate skinned model, too many vertices, or stream format unsupported");
792 else
794 nlwarning("Unable to animate skinned model, unsupported vertex format");
798 // Setup meshVertexProgram
799 //===========
801 // use MeshVertexProgram effect?
802 bool useMeshVP= _MeshVertexProgram != NULL;
803 if( useMeshVP )
805 CMatrix invertedObjectMatrix;
806 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
807 // really ok if success to begin VP
808 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
812 // Render the mesh.
813 //===========
814 // active VB.
815 if (supportVertexStream)
817 meshSkinManager->activate();
819 else
821 drv->activeVertexBuffer(_VBuffer);
825 // For all _MatrixBlocks
826 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
828 CMatrixBlock &mBlock= _MatrixBlocks[mb];
829 if(mBlock.RdrPass.empty())
830 continue;
832 // Render all pass.
833 for(uint i=0;i<mBlock.RdrPass.size();i++)
835 CRdrPass &rdrPass= mBlock.RdrPass[i];
837 // CMaterial Ref
838 CMaterial &material=mi->Materials[rdrPass.MaterialId];
840 // Setup VP material
841 if (useMeshVP)
843 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
846 // render primitives
847 drv->activeIndexBuffer(rdrPass.PBlock);
848 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
852 if (supportVertexStream)
854 meshSkinManager->swapVBHard();
857 // End VertexProgram effect
858 if(useMeshVP)
860 // Apply it.
861 _MeshVertexProgram->end(drv);
867 // ***************************************************************************
868 void CMeshGeom::renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat)
870 H_AUTO( NL3D_MeshGeom_RenderSimpleWithMaterial );
872 nlassert(drv);
874 // setup matrix
875 drv->setupModelMatrix(worldMatrix);
877 // Active simple VB.
878 drv->activeVertexBuffer(_VBuffer);
880 // For all _MatrixBlocks
881 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
883 CMatrixBlock &mBlock= _MatrixBlocks[mb];
884 if(mBlock.RdrPass.empty())
885 continue;
887 // Render all pass.
888 for(uint i=0;i<mBlock.RdrPass.size();i++)
890 CRdrPass &rdrPass= mBlock.RdrPass[i];
892 // render primitives
893 drv->activeIndexBuffer(rdrPass.PBlock);
894 drv->renderTriangles(mat, 0, rdrPass.PBlock.getNumIndexes()/3);
901 // ***************************************************************************
902 void CMeshGeom::serial(NLMISC::IStream &f)
904 /* ***********************************************
905 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
906 * It can be loaded/called through CAsyncFileManager for instance
907 * ***********************************************/
910 Version 5:
911 - Preferred memory.
912 Version 4:
913 - BonesName.
914 Version 3:
915 - MeshVertexProgram.
916 Version 2:
917 - precompute of triangle order. (nothing more to load).
918 Version 1:
919 - added blend shapes
920 Version 0:
921 - separate serialisation CMesh / CMeshGeom.
923 sint ver = f.serialVersion (4);
926 // must have good original Skinned Vertex before writing.
927 if( !f.isReading() && _Skinned && !_OriginalSkinRestored )
929 restoreOriginalSkinVertices();
933 // Version 4+: Array of bone name
934 if (ver >= 4)
936 f.serialCont (_BonesName);
939 if (f.isReading())
941 // Version3-: Bones index are in skeleton model id list
942 _BoneIdComputed = (ver < 4);
943 // In all case, must recompute usage of parents.
944 _BoneIdExtended= false;
946 else
948 // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed!
949 nlassert (_BoneIdComputed==false);
952 // Version3+: MeshVertexProgram.
953 if (ver >= 3)
955 IMeshVertexProgram *mvp= NULL;
956 if(f.isReading())
958 f.serialPolyPtr(mvp);
959 _MeshVertexProgram= mvp;
961 else
963 mvp= _MeshVertexProgram;
964 f.serialPolyPtr(mvp);
967 else if(f.isReading())
969 // release vp
970 _MeshVertexProgram= NULL;
973 // TestYoyo
974 //_MeshVertexProgram= NULL;
976 // Version1+: _MeshMorpher.
977 if (ver >= 1)
978 f.serial (*_MeshMorpher);
980 // serial geometry.
981 f.serial (_VBuffer);
983 f.serialCont (_MatrixBlocks);
984 f.serial (_BBox);
985 f.serial (_Skinned);
988 // If _VertexBuffer changed, flag the VertexBufferHard.
989 if(f.isReading())
991 // if >= version 2, reorder of triangles is precomputed, else compute it now.
992 if(ver < 2 )
994 optimizeTriangleOrder();
998 // Skinning: If Version < 4, _BonesName are not present, must compute _BonesId from localId
999 // Else it is computed at first computeBonesId().
1000 if(ver < 4)
1001 buildBoneUsageVer3();
1003 // TestYoyo
1004 //_MeshVertexProgram= NULL;
1006 uint numTris= 0;
1007 for(uint i=0;i<_MatrixBlocks.size();i++)
1009 for(uint j=0;j<_MatrixBlocks[i].RdrPass.size();j++)
1010 numTris+= _MatrixBlocks[i].RdrPass[j].PBlock.getNumTri();
1012 nlinfo("YOYO: %d Vertices. %d Triangles.", _VBuffer.getNumVertices(), numTris);
1015 // Some runtime not serialized compilation
1016 if(f.isReading())
1017 compileRunTime();
1021 // ***************************************************************************
1022 void CMeshGeom::compileRunTime()
1024 /* ***********************************************
1025 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
1026 * It can be loaded/called through CAsyncFileManager for instance
1027 * ***********************************************/
1029 // if skinned, prepare skinning
1030 if(_Skinned)
1032 // bkup vertices
1033 bkupOriginalSkinVertices();
1034 // build the shadow skin
1035 buildShadowSkin();
1038 // Do precise clipping for big object??
1039 _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
1041 // Support MeshBlockRendering only if not skinned/meshMorphed.
1042 bool supportMeshBlockRendering= !_Skinned && _MeshMorpher->BlendShapes.empty();
1044 // true only if one matrix block, and at least one rdrPass.
1045 supportMeshBlockRendering= supportMeshBlockRendering && _MatrixBlocks.size()==1 && !_MatrixBlocks[0].RdrPass.empty();
1046 if (supportMeshBlockRendering && _MeshVertexProgram)
1048 supportMeshBlockRendering = supportMeshBlockRendering && _MeshVertexProgram->supportMeshBlockRendering();
1051 // TestYoyo
1052 //supportMeshBlockRendering= false;
1054 // support MeshVertexProgram, but no material sorting...
1055 bool supportMBRPerMaterial= supportMeshBlockRendering && _MeshVertexProgram==NULL;
1058 // setup flags
1059 _SupportMBRFlags= 0;
1060 if(supportMeshBlockRendering)
1061 _SupportMBRFlags|= MBROk;
1062 if(supportMBRPerMaterial)
1063 _SupportMBRFlags|= MBRSortPerMaterial;
1065 bool avoidVBHard= _Skinned || ( _MeshMorpher && !_MeshMorpher->BlendShapes.empty() );
1066 _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
1069 // ***************************************************************************
1070 bool CMeshGeom::retrieveVertices(std::vector<NLMISC::CVector> &vertices) const
1072 /* ***********************************************
1073 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
1074 * It can be loaded/called through CAsyncFileManager for instance
1075 * ***********************************************/
1077 uint i;
1079 // if resident, fails!!! cannot read!
1080 const CVertexBuffer &vb= getVertexBuffer();
1081 if(vb.isResident())
1082 return false;
1084 vertices.clear();
1085 vertices.resize(vb.getNumVertices());
1087 CVertexBufferRead vba;
1088 vb.lock (vba);
1089 const uint8 *pVert= (const uint8*)vba.getVertexCoordPointer(0);
1090 uint vSize= vb.getVertexSize();
1091 for(i=0;i<vertices.size();i++)
1093 vertices[i]= *(const CVector*)pVert;
1094 pVert+= vSize;
1098 return true;
1101 // ***************************************************************************
1102 bool CMeshGeom::retrieveTriangles(std::vector<uint32> &indices) const
1104 /* ***********************************************
1105 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
1106 * It can be loaded/called through CAsyncFileManager for instance
1107 * ***********************************************/
1109 uint i;
1111 indices.clear();
1113 // count numTris
1114 uint numTris= 0;
1115 for(i=0;i<getNbMatrixBlock();i++)
1117 for(uint rp=0;rp<getNbRdrPass(i);rp++)
1119 // if resident, fails!!! cannot read!
1120 const CIndexBuffer &pb= getRdrPassPrimitiveBlock(i, rp);
1121 if(pb.isResident())
1122 return false;
1123 numTris+= getRdrPassPrimitiveBlock(i, rp).getNumIndexes()/3;
1126 indices.resize(numTris*3);
1128 // build indices
1129 uint triIdx= 0;
1130 for(i=0;i<getNbMatrixBlock();i++)
1132 for(uint rp=0;rp<getNbRdrPass(i);rp++)
1134 const CIndexBuffer &pb= getRdrPassPrimitiveBlock(i, rp);
1135 CIndexBufferRead iba;
1136 pb.lock (iba);
1137 // copy
1138 if (pb.getFormat() == CIndexBuffer::Indices32)
1140 memcpy(&indices[triIdx*3], iba.getPtr(), pb.getNumIndexes()*sizeof(uint32));
1142 else
1144 // std::copy will convert from 16 bits index to 32 bit index
1145 #ifdef NL_COMP_VC14
1146 std::copy((uint16 *)iba.getPtr(), ((uint16 *)iba.getPtr()) + pb.getNumIndexes(), stdext::make_checked_array_iterator(&indices[triIdx * 3], indices.size() - triIdx * 3));
1147 #else
1148 std::copy((uint16 *)iba.getPtr(), ((uint16 *)iba.getPtr()) + pb.getNumIndexes(), &indices[triIdx * 3]);
1149 #endif
1151 // next
1152 triIdx+= pb.getNumIndexes()/3;
1156 return true;
1160 // ***************************************************************************
1161 // ***************************************************************************
1162 // Skinning.
1163 // ***************************************************************************
1164 // ***************************************************************************
1167 // ***************************************************************************
1168 void CMeshGeom::buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp> &tmpFaces)
1170 sint i,j,k;
1171 TBoneMap remainingBones;
1172 list<uint> remainingFaces;
1175 // 0. normalize SkinWeights: for all weights at 0, copy the matrixId from 0th matrix => no random/bad use of matrix.
1176 //================================
1177 for(i=0;i<(sint)m.SkinWeights.size();i++)
1179 CMesh::CSkinWeight &sw= m.SkinWeights[i];
1181 // 0th weight must not be 0.
1182 nlassert(sw.Weights[0]!=0);
1184 // Begin at 1, tests all other weights.
1185 for(j=1;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
1187 // We don't use this entry??
1188 if(sw.Weights[j]==0)
1190 // Setup MatrixId so that this vertex do no use more matrix than it really wants.
1191 sw.MatrixId[j]= sw.MatrixId[0];
1197 // 1. build the list of used/remaining bones, in ascending order. (so we use the depth-first topolgy of hierarchy).
1198 //================================
1199 for(i=0;i<(sint)tmpFaces.size();i++)
1201 CFaceTmp &face= tmpFaces[i];
1203 for(j=0;j<3;j++)
1205 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
1206 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
1208 // insert (if not already here) the used bone in the set.
1209 // and insert his refcount. (NB: ctor() init it to 0 :) ).
1210 remainingBones[sw.MatrixId[k]].RefCount++;
1216 // 2. Create the list of un-inserted faces.
1217 //================================
1218 for(i=0;i<(sint)tmpFaces.size();i++)
1220 remainingFaces.push_back(i);
1225 // 3. Create as many Blocks as necessary.
1226 //================================
1227 // Which bones a face use (up to 12).
1228 vector<uint> boneUse;
1229 boneUse.reserve(NL3D_MESH_SKINNING_MAX_MATRIX*3);
1231 // While still exist faces.
1232 while(!remainingFaces.empty())
1234 // create a new matrix block.
1235 _MatrixBlocks.push_back(CMatrixBlock());
1236 CMatrixBlock &matrixBlock= _MatrixBlocks[_MatrixBlocks.size()-1];
1237 matrixBlock.NumMatrix=0;
1239 // a. reset remainingBones as not inserted in the current matrixBlock.
1240 //============================
1241 ItBoneMap itBone;
1242 for(itBone= remainingBones.begin();itBone!=remainingBones.end();itBone++)
1244 itBone->second.Inserted= false;
1248 // b. while still exist bones, try to insert faces which use them in matrixBlock.
1249 //============================
1250 while(!remainingBones.empty())
1252 // get the first bone from the map. (remind: depth-first order).
1253 uint currentBoneId= remainingBones.begin()->first;
1255 // If no more faces in the remainingFace list use this bone, remove it, and continue.
1256 if(remainingBones.begin()->second.RefCount==0)
1258 remainingBones.erase(remainingBones.begin());
1259 continue;
1262 // this is a marker, to know if a face insertion will occurs.
1263 bool faceAdded= false;
1265 // traverse all faces, trying to insert them in current MatrixBlock processed.
1266 list<uint>::iterator itFace;
1267 for(itFace= remainingFaces.begin(); itFace!=remainingFaces.end();)
1269 bool useCurrentBoneId;
1270 uint newBoneAdded;
1272 // i/ Get info on current face.
1273 //-----------------------------
1275 // build which bones this face use.
1276 tmpFaces[*itFace].buildBoneUse(boneUse, m.SkinWeights);
1278 // test if this face use the currentBoneId.
1279 useCurrentBoneId= false;
1280 for(i=0;i<(sint)boneUse.size();i++)
1282 // if this face use the currentBoneId
1283 if(boneUse[i]==currentBoneId)
1285 useCurrentBoneId= true;
1286 break;
1289 // compute how many bones that are not in the current matrixblock this face use.
1290 newBoneAdded=0;
1291 for(i=0;i<(sint)boneUse.size();i++)
1293 // if this bone is not inserted in the current matrix block, inform it.
1294 if(!remainingBones[boneUse[i]].Inserted)
1295 newBoneAdded++;
1299 // ii/ insert/reject face.
1300 //------------------------
1302 // If this face do not add any more bone, we can insert it into the current matrixblock.
1303 // If it use the currentBoneId, and do not explode max count, we allow insert it too in the current matrixblock.
1304 if( newBoneAdded==0 ||
1305 (useCurrentBoneId && newBoneAdded+matrixBlock.NumMatrix < IDriver::MaxModelMatrix) )
1307 // Insert this face in the current matrix block
1309 CFaceTmp &face= tmpFaces[*itFace];
1311 // for all vertices of this face.
1312 for(j=0;j<3;j++)
1314 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
1316 // for each corner weight (4)
1317 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
1319 // get the global boneId this corner weight use.
1320 uint boneId= sw.MatrixId[k];
1321 // get the CBoneTmp this corner weight use.
1322 CBoneTmp &bone= remainingBones[boneId];
1324 // decRef the bone .
1325 bone.RefCount--;
1327 // Is this bone already inserted in the MatrixBlock ?
1328 if( !bone.Inserted )
1330 // No, insert it.
1331 bone.Inserted= true;
1332 // link it to the MatrixId in the current matrixBlock.
1333 bone.MatrixIdInMB= matrixBlock.NumMatrix;
1335 // modify the matrixBlock
1336 matrixBlock.MatrixId[matrixBlock.NumMatrix]= boneId;
1337 // increment the number of matrix in the matrixBlock.
1338 matrixBlock.NumMatrix++;
1341 // Copy Weight info for this Corner.
1342 // Set what matrix in the current matrix block this corner use.
1343 face.Corner[j].Palette.MatrixId[k]= bone.MatrixIdInMB;
1344 // Set weight.
1345 face.Corner[j].Weights[k]= sw.Weights[k];
1349 // to Which matrixblock this face is inserted.
1350 face.MatrixBlockId= (sint)_MatrixBlocks.size()-1;
1352 // remove the face from remain face list.
1353 itFace= remainingFaces.erase(itFace);
1355 // inform the algorithm that a face has been added.
1356 faceAdded= true;
1358 else
1360 // do not append this face to the current matrix block, skip to the next
1361 itFace++;
1365 // If no faces have been added during this pass, we are blocked, and either the MatrixBlock may be full,
1366 // or there is no more face. So quit this block and process a new one.
1367 if(!faceAdded)
1368 break;
1372 // NB: at the end of this loop, remainingBones may not be empty(), but all remainingBones should have RefCount==0.
1376 // 4. Re-order matrix use in MatrixBlocks, for minimum matrix change between MatrixBlocks.
1377 //================================
1378 vector<CMatrixBlockRemap> blockRemaps;
1379 blockRemaps.resize(_MatrixBlocks.size());
1382 // For all MatrixBlocks > first, try to "mirror" bones from previous.
1383 for(i=1;i<(sint)_MatrixBlocks.size();i++)
1385 CMatrixBlock &mBlock= _MatrixBlocks[i];
1386 CMatrixBlock &mPrevBlock= _MatrixBlocks[i-1];
1387 CMatrixBlockRemap &remap= blockRemaps[i];
1389 // First bkup the bone ids in remap table.
1390 for(j=0;j<(sint)mBlock.NumMatrix;j++)
1392 remap.Remap[j]= mBlock.MatrixId[j];
1395 // For all ids of this blocks, try to mirror them.
1396 for(j=0;j<(sint)mBlock.NumMatrix;j++)
1398 // get the location of this bone in the prev bone.
1399 sint idLoc= mPrevBlock.getMatrixIdLocation(mBlock.MatrixId[j]);
1400 // If not found, or if bigger than current array, fails (cant be mirrored).
1401 // Or if already mirrored.
1402 if(idLoc==-1 || idLoc>=(sint)mBlock.NumMatrix || idLoc==j)
1404 // next id.
1405 j++;
1407 else
1409 // puts me on my mirrored location. and swap with the current one at this mirrored location.
1410 swap(mBlock.MatrixId[j], mBlock.MatrixId[idLoc]);
1411 // mBlock.MatrixId[j] is now a candidate for mirror.
1415 // Then build the Remap table, to re-order faces matrixId which use this matrix block.
1416 for(j=0;j<(sint)mBlock.NumMatrix;j++)
1418 // get the boneid which was at this position j before.
1419 uint boneId= remap.Remap[j];
1420 // search his new position, and store the result in the remap table.
1421 remap.Remap[j]= mBlock.getMatrixIdLocation(boneId);
1424 // NB: this matrixBlock is re-ordered. next matrixBlock use this state.
1428 // For all faces/corners/weights, remap MatrixIds.
1429 for(i=0;i<(sint)tmpFaces.size();i++)
1431 CFaceTmp &face= tmpFaces[i];
1432 // do it but for matrixblock0.
1433 if(face.MatrixBlockId!=0)
1435 CMatrixBlockRemap &remap= blockRemaps[face.MatrixBlockId];
1436 // For all corners.
1437 for(j=0;j<3;j++)
1439 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
1441 uint oldId= face.Corner[j].Palette.MatrixId[k];
1442 face.Corner[j].Palette.MatrixId[k]= (uint8)remap.Remap[oldId];
1451 // ***************************************************************************
1452 void CMeshGeom::CFaceTmp::buildBoneUse(vector<uint> &boneUse, vector<CMesh::CSkinWeight> &skinWeights)
1454 boneUse.clear();
1456 // For the 3 corners of the face.
1457 for(sint i=0;i<3;i++)
1459 // get the CSkinWeight of this vertex.
1460 CMesh::CSkinWeight &sw= skinWeights[Corner[i].Vertex];
1462 // For all skin weights of this vertex,
1463 for(sint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
1465 uint boneId= sw.MatrixId[j];
1466 // insert (if not in the array) this bone.
1467 if( find(boneUse.begin(), boneUse.end(), boneId)==boneUse.end() )
1468 boneUse.push_back(boneId);
1477 // ***************************************************************************
1478 sint CMeshGeom::CMatrixBlock::getMatrixIdLocation(uint32 boneId) const
1480 for(uint i=0;i<NumMatrix;i++)
1482 if(MatrixId[i]==boneId)
1483 return i;
1486 // not found.
1487 return -1;
1491 // ***************************************************************************
1492 float CMeshGeom::getNumTriangles (float distance)
1494 // Sum of triangles
1495 uint32 triCount=0;
1497 // For each matrix block
1498 uint mbCount=(uint)_MatrixBlocks.size();
1499 for (uint mb=0; mb<mbCount; mb++)
1501 CMatrixBlock &block=_MatrixBlocks[mb];
1503 // Count of primitive block
1504 uint pCount=(uint)block.RdrPass.size();
1505 for (uint pb=0; pb<pCount; pb++)
1507 // Ref on the primitive block
1508 CRdrPass &pass=block.RdrPass[pb];
1510 // Sum tri
1511 triCount+=pass.PBlock.getNumIndexes ()/3;
1514 return (float)triCount;
1518 // ***************************************************************************
1519 void CMeshGeom::computeBonesId (CSkeletonModel *skeleton)
1521 // Already computed ?
1522 if (!_BoneIdComputed)
1524 // Get a pointer on the skeleton
1525 nlassert (skeleton);
1526 if (skeleton)
1528 // **** For each bones, compute remap
1529 std::vector<uint> remap;
1530 skeleton->remapSkinBones(_BonesName, _BonesId, remap);
1533 // **** Remap matrix blocks
1534 for (uint matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
1536 // Ref on the matrix block
1537 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
1539 // For each matrix
1540 uint matrix;
1541 for (matrix=0; matrix<mb.NumMatrix; matrix++)
1543 // Get bone id in the skeleton
1544 nlassert (mb.MatrixId[matrix]<remap.size());
1545 mb.MatrixId[matrix] = remap[mb.MatrixId[matrix]];
1549 // **** Remap ShadowSkin, and compute Bone Sphere
1550 // Prepare Sphere compute
1551 static std::vector<CAABBox> boneBBoxes;
1552 static std::vector<bool> boneBBEmpty;
1553 boneBBoxes.clear();
1554 boneBBEmpty.clear();
1555 boneBBoxes.resize(_BonesId.size());
1556 boneBBEmpty.resize(_BonesId.size(), true);
1558 // For simplicity, use the shadow skin info only, to compute bone sphere
1559 for(uint vert=0;vert<_ShadowSkin.Vertices.size();vert++)
1561 CShadowVertex &v= _ShadowSkin.Vertices[vert];
1562 // Check id
1563 uint srcId= v.MatrixId;
1564 nlassert ( srcId < remap.size());
1565 // remap
1566 v.MatrixId= remap[srcId];
1568 // if the boneId is valid (ie found)
1569 if(_BonesId[srcId]>=0)
1571 // transform the vertex pos in BoneSpace
1572 CVector p= skeleton->Bones[_BonesId[srcId]].getBoneBase().InvBindPos * v.Vertex;
1573 // extend the bone bbox.
1574 if(boneBBEmpty[srcId])
1576 boneBBoxes[srcId].setCenter(p);
1577 boneBBEmpty[srcId]= false;
1579 else
1581 boneBBoxes[srcId].extend(p);
1586 // Compile spheres
1587 _BonesSphere.resize(_BonesId.size());
1588 for(uint bone=0;bone<_BonesSphere.size();bone++)
1590 // If the bone is empty, mark with -1 in the radius.
1591 if(boneBBEmpty[bone])
1593 _BonesSphere[bone].Radius= -1;
1595 else
1597 _BonesSphere[bone].Center= boneBBoxes[bone].getCenter();
1598 _BonesSphere[bone].Radius= boneBBoxes[bone].getRadius();
1603 // Computed
1604 _BoneIdComputed = true;
1608 // Already extended ?
1609 if (!_BoneIdExtended)
1611 nlassert (skeleton);
1612 if (skeleton)
1614 // the total bone Usage of the mesh.
1615 vector<bool> boneUsage;
1616 boneUsage.resize(skeleton->Bones.size(), false);
1618 // for all Bones marked as valid.
1619 uint i;
1620 for(i=0; i<_BonesId.size(); i++)
1622 // if not a valid boneId, skip it.
1623 if(_BonesId[i]<0)
1624 continue;
1626 // mark him and his father in boneUsage.
1627 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
1630 // fill _BonesIdExt with bones of _BonesId and their parents.
1631 _BonesIdExt.clear();
1632 for(i=0; i<boneUsage.size();i++)
1634 // if the bone is used by the mesh, add it to BoneIdExt.
1635 if(boneUsage[i])
1636 _BonesIdExt.push_back(i);
1641 // Extended
1642 _BoneIdExtended= true;
1648 // ***************************************************************************
1649 void CMeshGeom::buildBoneUsageVer3 ()
1651 if(_Skinned)
1653 // parse all matrixBlocks, couting MaxBoneId used.
1654 uint32 maxBoneId= 0;
1655 // For each matrix block
1656 uint matrixBlock;
1657 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
1659 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
1660 // For each matrix
1661 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
1663 maxBoneId= max(mb.MatrixId[matrix], maxBoneId);
1667 // alloc an array of maxBoneId+1, reset to 0.
1668 std::vector<uint8> boneUsage;
1669 boneUsage.resize(maxBoneId+1, 0);
1671 // reparse all matrixBlocks, counting usage for each bone.
1672 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
1674 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
1675 // For each matrix
1676 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
1678 // mark this bone as used.
1679 boneUsage[mb.MatrixId[matrix]]= 1;
1683 // For each bone used
1684 _BonesId.clear();
1685 for(uint i=0; i<boneUsage.size();i++)
1687 // if the bone is used by the mesh, add it to BoneId.
1688 if(boneUsage[i])
1689 _BonesId.push_back(i);
1692 // Must also compute _BonesSphere
1693 // Cannot do it easily, deprecated data format => suppose radius 0 sphere
1694 CBSphere sphere(CVector::Null, 0.f);
1695 _BonesSphere.clear();
1696 _BonesSphere.resize(_BonesId.size(), sphere);
1702 // ***************************************************************************
1703 void CMeshGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
1705 // For all Bones used by this mesh.
1706 for(uint i=0; i<_BonesIdExt.size();i++)
1708 uint boneId= _BonesIdExt[i];
1709 // Some explicit Error.
1710 if(boneId>=sm->Bones.size())
1711 nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
1712 // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
1713 if(increment)
1714 sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
1715 else
1716 sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
1721 // ***************************************************************************
1722 void CMeshGeom::bkupOriginalSkinVertices()
1724 nlassert(_Skinned);
1726 // reset
1727 contReset(_OriginalSkinVertices);
1728 contReset(_OriginalSkinNormals);
1729 contReset(_OriginalTGSpace);
1731 // get num of vertices
1732 uint numVertices= _VBuffer.getNumVertices();
1734 CVertexBufferRead vba;
1735 _VBuffer.lock (vba);
1737 // Copy VBuffer content into Original vertices normals.
1738 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
1740 // copy vertices from VBuffer. (NB: useless geomorphed vertices are still copied, but doesn't matter).
1741 _OriginalSkinVertices.resize(numVertices);
1742 for(uint i=0; i<numVertices;i++)
1744 _OriginalSkinVertices[i]= *vba.getVertexCoordPointer(i);
1747 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
1749 // copy normals from VBuffer. (NB: useless geomorphed normals are still copied, but doesn't matter).
1750 _OriginalSkinNormals.resize(numVertices);
1751 for(uint i=0; i<numVertices;i++)
1753 _OriginalSkinNormals[i]= *vba.getNormalCoordPointer(i);
1757 // is there tangent space added ?
1758 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
1760 // yes, backup it
1761 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
1762 uint tgSpaceStage = _VBuffer.getNumTexCoordUsed() - 1;
1763 _OriginalTGSpace.resize(numVertices);
1764 for(uint i=0; i<numVertices;i++)
1766 _OriginalTGSpace[i]= *(CVector*)vba.getTexCoordPointer(i, tgSpaceStage);
1772 // ***************************************************************************
1773 void CMeshGeom::restoreOriginalSkinVertices()
1775 nlassert(_Skinned);
1777 // get num of vertices
1778 uint numVertices= _VBuffer.getNumVertices();
1780 CVertexBufferReadWrite vba;
1781 _VBuffer.lock (vba);
1783 // Copy VBuffer content into Original vertices normals.
1784 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
1786 // copy vertices from VBuffer. (NB: useless geomorphed vertices are still copied, but doesn't matter).
1787 for(uint i=0; i<numVertices;i++)
1789 *vba.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
1792 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
1794 // copy normals from VBuffer. (NB: useless geomorphed normals are still copied, but doesn't matter).
1795 for(uint i=0; i<numVertices;i++)
1797 *vba.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
1800 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
1802 uint numTexCoords = _VBuffer.getNumTexCoordUsed();
1803 nlassert(numTexCoords >= 2);
1804 nlassert(_OriginalTGSpace.size() == numVertices);
1805 // copy tangent space vectors
1806 for(uint i = 0; i < numVertices; ++i)
1808 *(CVector*)vba.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
1812 // cleared
1813 _OriginalSkinRestored= true;
1817 // ***************************************************************************
1818 // Flags for software vertex skinning.
1819 #define NL3D_SOFTSKIN_VNEEDCOMPUTE 3
1820 #define NL3D_SOFTSKIN_VMUSTCOMPUTE 1
1821 #define NL3D_SOFTSKIN_VCOMPUTED 0
1822 // 3 means "vertex may need compute".
1823 // 1 means "Primitive say vertex must be computed".
1824 // 0 means "vertex is computed".
1827 // ***************************************************************************
1828 void CMeshGeom::applySkin(void *dstVb, CSkeletonModel *skeleton)
1830 // init.
1831 //===================
1832 if(_OriginalSkinVertices.empty())
1833 return;
1835 // Use correct skinning
1836 nlassert(!_OriginalSkinNormals.empty());
1837 nlassert(_OriginalTGSpace.empty());
1839 // Get VB src/dst info/ptrs.
1840 uint numVertices= (uint)_OriginalSkinVertices.size();
1841 static const uint dstStride = 32; // _VBuffer.getVertexSize();
1842 uint srcStride = _VBuffer.getVertexSize();
1844 // Mark all vertices flag to not computed.
1845 static vector<uint8> skinFlags;
1846 skinFlags.resize(numVertices);
1847 // reset all flags
1848 memset(&skinFlags[0], NL3D_SOFTSKIN_VNEEDCOMPUTE, numVertices );
1850 CVertexBufferRead vba;
1851 _VBuffer.lock (vba);
1853 uint8 *dstVbPos = (uint8 *)dstVb;
1854 uint8 *dstVbNormal = dstVbPos + 12;
1855 uint8 *dstVbUV = dstVbPos + 24;
1857 // For all MatrixBlocks
1858 //===================
1859 for(uint mb= 0; mb<_MatrixBlocks.size();mb++)
1861 // compute matrixes for this block.
1862 static CMatrix3x4 matrixes[IDriver::MaxModelMatrix];
1863 computeSkinMatrixes(skeleton, matrixes, mb==0?NULL:&_MatrixBlocks[mb-1], _MatrixBlocks[mb]);
1865 // check what vertex to skin for this PB.
1866 flagSkinVerticesForMatrixBlock(&skinFlags[0], _MatrixBlocks[mb]);
1868 // Get VB src/dst ptrs.
1869 uint8 *pFlag= &skinFlags[0];
1870 CVector *srcVector= &_OriginalSkinVertices[0];
1871 uint8 *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
1872 uint8 *srcWgt= (uint8*)vba.getWeightPointer(0);
1873 uint8 *dstVector = dstVbPos;
1874 // Normal.
1875 CVector *srcNormal= &_OriginalSkinNormals[0];
1876 uint8 *dstNormal = dstVbNormal;
1878 // For all vertices that need to be computed.
1879 uint size= numVertices;
1880 for(;size>0;size--)
1882 // If we must compute this vertex.
1883 if(*pFlag==NL3D_SOFTSKIN_VMUSTCOMPUTE)
1885 // Flag this vertex as computed.
1886 *pFlag=NL3D_SOFTSKIN_VCOMPUTED;
1888 CPaletteSkin *psPal= (CPaletteSkin*)srcPal;
1890 // checks indices.
1891 nlassert(psPal->MatrixId[0]<IDriver::MaxModelMatrix);
1892 nlassert(psPal->MatrixId[1]<IDriver::MaxModelMatrix);
1893 nlassert(psPal->MatrixId[2]<IDriver::MaxModelMatrix);
1894 nlassert(psPal->MatrixId[3]<IDriver::MaxModelMatrix);
1896 // compute vertex part.
1897 computeSoftwarePointSkinning(matrixes, srcVector, psPal, (float*)srcWgt, (CVector*)dstVector);
1899 // compute normal part.
1900 computeSoftwareVectorSkinning(matrixes, srcNormal, psPal, (float*)srcWgt, (CVector*)dstNormal);
1903 // inc flags.
1904 pFlag++;
1905 // inc src (all whatever skin type used...)
1906 srcVector++;
1907 srcNormal++;
1908 // inc paletteSkin and dst (all whatever skin type used...)
1909 srcPal+= srcStride;
1910 srcWgt+= srcStride;
1911 dstVector+= dstStride;
1912 dstNormal+= dstStride;
1916 // Remaining vertices
1918 uint8 *pFlag = &skinFlags[0];
1919 CVector *srcVector = &_OriginalSkinVertices[0];
1920 uint8 *dstVector = dstVbPos;
1921 CVector *srcNormal = &_OriginalSkinNormals[0];
1922 uint8 *dstNormal = dstVbNormal;
1923 uint8 *srcUV = (uint8 *)vba.getTexCoordPointer(0, 0);
1924 uint8 *dstUV = dstVbUV;
1925 uint srcStride = _VBuffer.getVertexSize();
1927 for (uint i = 0; i < numVertices; ++i)
1929 if (*pFlag != NL3D_SOFTSKIN_VCOMPUTED)
1931 *(CVector *)dstVector = *srcVector;
1932 *(CVector *)dstNormal = *srcNormal;
1934 *(CVector2f *)dstUV = *(CVector2f *)srcUV;
1936 // inc flags.
1937 pFlag++;
1938 // inc src (all whatever skin type used...)
1939 srcVector++;
1940 srcNormal++;
1941 srcUV += srcStride;
1942 // inc paletteSkin and dst (all whatever skin type used...)
1943 dstVector += dstStride;
1944 dstNormal += dstStride;
1945 dstUV += dstStride;
1951 // ***************************************************************************
1952 void CMeshGeom::flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb)
1954 for(uint i=0; i<mb.RdrPass.size(); i++)
1956 CIndexBuffer &PB= mb.RdrPass[i].PBlock;
1958 uint nIndex;
1960 // This may be better to flags in 2 pass (first traverse primitives, then test vertices).
1961 // Better sol for BTB..., because number of tests are divided by 6 (for triangles).
1963 // for all prims, indicate which vertex we must compute.
1964 // nothing if not already computed (ie 0), because 0&1==0.
1965 // Lines.
1966 // Tris.
1967 CIndexBufferRead iba;
1968 PB.lock (iba);
1969 nIndex= PB.getNumIndexes();
1970 if (iba.getFormat() == CIndexBuffer::Indices32)
1972 uint32 *pIndex= (uint32*)iba.getPtr();
1973 for(;nIndex>0;nIndex--, pIndex++)
1974 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
1976 else
1978 uint16 *pIndex= (uint16*)iba.getPtr();
1979 for(;nIndex>0;nIndex--, pIndex++)
1980 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
1986 // ***************************************************************************
1987 void CMeshGeom::computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
1989 CMatrix3x4 *pMat;
1991 // 0th matrix influence.
1992 pMat= matrixes + srcPal->MatrixId[0];
1993 pMat->mulSetPoint(*srcVec, srcWgt[0], *pDst);
1994 // 1th matrix influence.
1995 pMat= matrixes + srcPal->MatrixId[1];
1996 pMat->mulAddPoint(*srcVec, srcWgt[1], *pDst);
1997 // 2th matrix influence.
1998 pMat= matrixes + srcPal->MatrixId[2];
1999 pMat->mulAddPoint(*srcVec, srcWgt[2], *pDst);
2000 // 3th matrix influence.
2001 pMat= matrixes + srcPal->MatrixId[3];
2002 pMat->mulAddPoint(*srcVec, srcWgt[3], *pDst);
2006 // ***************************************************************************
2007 void CMeshGeom::computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
2009 CMatrix3x4 *pMat;
2011 // 0th matrix influence.
2012 pMat= matrixes + srcPal->MatrixId[0];
2013 pMat->mulSetVector(*srcVec, srcWgt[0], *pDst);
2014 // 1th matrix influence.
2015 pMat= matrixes + srcPal->MatrixId[1];
2016 pMat->mulAddVector(*srcVec, srcWgt[1], *pDst);
2017 // 2th matrix influence.
2018 pMat= matrixes + srcPal->MatrixId[2];
2019 pMat->mulAddVector(*srcVec, srcWgt[2], *pDst);
2020 // 3th matrix influence.
2021 pMat= matrixes + srcPal->MatrixId[3];
2022 pMat->mulAddVector(*srcVec, srcWgt[3], *pDst);
2026 // ***************************************************************************
2027 void CMeshGeom::computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock *prevBlock, CMatrixBlock &mBlock)
2029 // For all matrix of this mBlock.
2030 for(uint idMat=0;idMat<mBlock.NumMatrix;idMat++)
2032 uint curBoneId= mBlock.MatrixId[idMat];
2034 // If same matrix binded as previous block, no need to bind!!
2035 if(prevBlock && idMat<prevBlock->NumMatrix && prevBlock->MatrixId[idMat]== curBoneId)
2036 continue;
2038 // Else, we must setup the matrix
2039 matrixes[idMat].set(skeleton->getActiveBoneSkinMatrix(curBoneId));
2044 // ***************************************************************************
2045 void CMeshGeom::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags)
2047 // get the mesh instance.
2048 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
2050 // For all _MatrixBlocks
2051 uint triCount= 0;
2052 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
2054 CMatrixBlock &mBlock= _MatrixBlocks[mb];
2056 // Profile all pass.
2057 for (uint i=0;i<mBlock.RdrPass.size();i++)
2059 CRdrPass &rdrPass= mBlock.RdrPass[i];
2060 // Profile with the Materials of the MeshInstance.
2061 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
2062 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
2064 triCount+= rdrPass.PBlock.getNumIndexes()/3;
2069 // Profile
2070 if(triCount)
2072 // tri per VBFormat
2073 rdrTrav->Scene->incrementProfileTriVBFormat(rdrTrav->Scene->BenchRes.MeshProfileTriVBFormat,
2074 _VBuffer.getVertexFormat(), triCount);
2076 // VBHard
2077 if(_VBuffer.getPreferredMemory()!=CVertexBuffer::RAMPreferred)
2078 rdrTrav->Scene->BenchRes.NumMeshVBufferHard++;
2079 else
2080 rdrTrav->Scene->BenchRes.NumMeshVBufferStd++;
2082 // rendered in BlockRendering, only if not transparent pass (known it if RenderTransparentMaterial is set)
2083 if(supportMeshBlockRendering() && (rdrFlags & IMeshGeom::RenderTransparentMaterial)==0 )
2085 if(isMeshInVBHeap())
2087 rdrTrav->Scene->BenchRes.NumMeshRdrBlockWithVBHeap++;
2088 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlockWithVBHeap+= triCount;
2090 else
2092 rdrTrav->Scene->BenchRes.NumMeshRdrBlock++;
2093 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlock+= triCount;
2096 else
2098 rdrTrav->Scene->BenchRes.NumMeshRdrNormal++;
2099 rdrTrav->Scene->BenchRes.NumMeshTriRdrNormal+= triCount;
2104 // ***************************************************************************
2105 bool CMeshGeom::intersectSkin(CTransformShape *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
2107 // for Mesh, Use the Shadow Skinning (simple version).
2109 // get skeleton
2110 if(!mi || _OriginalSkinVertices.empty())
2111 return false;
2112 CSkeletonModel *skeleton= mi->getSkeletonModel();
2113 if(!skeleton)
2114 return false;
2116 // Compute skinning with all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
2117 static std::vector<uint32> matInfs;
2118 matInfs.resize(_BonesId.size());
2119 for(uint i=0;i<matInfs.size();i++)
2121 // treat any "missing bone" as the root one.
2122 matInfs[i]= max(_BonesId[i], (sint32)0);
2124 return _ShadowSkin.getRayIntersection(toRaySpace, *skeleton, matInfs, dist2D, distZ, computeDist2D);
2127 // ***************************************************************************
2128 void CMeshGeom::buildShadowSkin()
2130 /* ***********************************************
2131 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2132 * It can be loaded/called through CAsyncFileManager for instance
2133 * ***********************************************/
2135 // reset
2136 contReset(_ShadowSkin.Vertices);
2137 contReset(_ShadowSkin.Triangles);
2139 nlassert(_Skinned && (_VBuffer.getVertexFormat() & CVertexBuffer::PaletteSkinFlag)
2140 && (_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag) );
2143 // *** Copy VBuffer content
2145 // get num of vertices
2146 uint numVertices= _VBuffer.getNumVertices();
2148 // lock VB
2149 CVertexBufferRead vba;
2150 _VBuffer.lock (vba);
2151 uint8 *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
2152 uint8 *srcVert= (uint8*)vba.getVertexCoordPointer(0);
2153 uint32 srcVertSize= _VBuffer.getVertexSize();
2155 // copy vertices from VBuffer
2156 _ShadowSkin.Vertices.resize(numVertices);
2157 for(uint i=0; i<numVertices;i++)
2159 // Copy Vertex
2160 _ShadowSkin.Vertices[i].Vertex= *((CVector*)srcVert);
2161 // Suppose the 0 matrix inf is the highest (we are at least sure it is not 0)
2162 // And SkinWeight Export show the 0th is the highest one...
2163 _ShadowSkin.Vertices[i].MatrixId= ((CPaletteSkin*)srcPal)->MatrixId[0];
2165 // Next
2166 srcVert+= srcVertSize;
2167 srcPal+= srcVertSize;
2171 // But _ShadowSkin.Vertices[i].MatrixId is incorrect, since < IDriver::MaxModelMatrix
2174 // *** Count number of triangles, and get start index of each matrix block in the final Tri list
2175 uint numIndices= 0;
2176 uint mb;
2177 // can't be static cause of ThreadSafe
2178 vector<pair<uint32,uint32> > mbIndexRange;
2179 mbIndexRange.resize(_MatrixBlocks.size());
2180 for(mb=0;mb<_MatrixBlocks.size();mb++)
2182 // this matrix block start here
2183 mbIndexRange[mb].first= numIndices;
2185 // count tris rendered for this matrix block
2186 const CMatrixBlock &mBlock= _MatrixBlocks[mb];
2187 for(uint rp=0;rp<mBlock.RdrPass.size();rp++)
2189 const CRdrPass &rPass= mBlock.RdrPass[rp];
2190 numIndices+= rPass.PBlock.getNumIndexes();
2193 // this matrix block end here
2194 mbIndexRange[mb].second= numIndices;
2198 // *** Fill Triangles
2199 nlverify(retrieveTriangles(_ShadowSkin.Triangles));
2200 nlassert(numIndices==_ShadowSkin.Triangles.size());
2203 // *** Reindex correctly MatrixId, (ie unpack matrix blocks)
2204 // can't be static cause of ThreadSafe
2205 vector<bool> vertReIndexed;
2206 vertReIndexed.resize(_ShadowSkin.Vertices.size(), false);
2207 // for all matrix blocks
2208 for(mb=0;mb<mbIndexRange.size();mb++)
2210 const CMatrixBlock &mBlock= _MatrixBlocks[mb];
2212 uint iStart= mbIndexRange[mb].first;
2213 uint iEnd= mbIndexRange[mb].second;
2214 nlassert(iStart <= iEnd && iEnd<=_ShadowSkin.Triangles.size());
2216 // For all indices in this range
2217 uint32 *pIndex= &_ShadowSkin.Triangles[iStart];
2218 uint nbIndex= iEnd - iStart;
2219 for(;nbIndex>0;--nbIndex, pIndex++)
2221 uint index= *pIndex;
2222 // if not already reindexed
2223 if(!vertReIndexed[index])
2225 vertReIndexed[index]= true;
2226 // reindex
2227 uint matId= _ShadowSkin.Vertices[index].MatrixId;
2228 nlassert(matId<mBlock.NumMatrix);
2229 _ShadowSkin.Vertices[index].MatrixId= mBlock.MatrixId[matId];
2236 // ***************************************************************************
2237 // ***************************************************************************
2238 // Mesh Block Render Interface
2239 // ***************************************************************************
2240 // ***************************************************************************
2243 // ***************************************************************************
2244 bool CMeshGeom::supportMeshBlockRendering () const
2246 return _SupportMBRFlags!=0;
2249 // ***************************************************************************
2250 bool CMeshGeom::sortPerMaterial() const
2252 return (_SupportMBRFlags & MBRSortPerMaterial)!=0;
2254 // ***************************************************************************
2255 uint CMeshGeom::getNumRdrPassesForMesh() const
2257 return (uint)_MatrixBlocks[0].RdrPass.size();
2259 // ***************************************************************************
2260 uint CMeshGeom::getNumRdrPassesForInstance(CMeshBaseInstance *inst) const
2262 return (uint)_MatrixBlocks[0].RdrPass.size();
2264 // ***************************************************************************
2265 void CMeshGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
2267 if(rdrCtx.RenderThroughVBHeap)
2269 // Don't setup VB in this case, since use the VBHeap setuped one.
2270 // NB: no VertexProgram test since VBHeap not possible with it...
2271 nlassert( (_SupportMBRFlags & MBRCurrentUseVP)==0 );
2273 else
2275 // use MeshVertexProgram effect?
2276 if( _MeshVertexProgram != NULL && _MeshVertexProgram->isMBRVpOk(rdrCtx.Driver) )
2278 // Ok will use it.
2279 _SupportMBRFlags|= MBRCurrentUseVP;
2280 // Before VB activation
2281 _MeshVertexProgram->beginMBRMesh(rdrCtx.Driver, rdrCtx.Scene );
2284 // active VB. SoftwareSkinning: reset flags for skinning.
2285 rdrCtx.Driver->activeVertexBuffer(_VBuffer);
2288 // ***************************************************************************
2289 void CMeshGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst)
2291 // setup instance matrix
2292 rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
2294 // setupLighting.
2295 inst->changeLightSetup(rdrCtx.RenderTrav);
2297 // MeshVertexProgram ?
2298 if( _SupportMBRFlags & MBRCurrentUseVP )
2300 CMatrix invertedObjectMatrix;
2301 invertedObjectMatrix = inst->getWorldMatrix().inverted();
2302 _MeshVertexProgram->beginMBRInstance(rdrCtx.Driver, rdrCtx.Scene, inst, invertedObjectMatrix);
2305 // ***************************************************************************
2306 void CMeshGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
2308 CMatrixBlock &mBlock= _MatrixBlocks[0];
2310 CRdrPass &rdrPass= mBlock.RdrPass[rdrPassId];
2311 // Render with the Materials of the MeshInstance, only if not blended.
2312 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) ) )
2314 CMaterial &material= mi->Materials[rdrPass.MaterialId];
2316 // MeshVertexProgram ?
2317 if( _SupportMBRFlags & MBRCurrentUseVP )
2319 rdrCtx.RenderTrav->changeVPLightSetupMaterial(material, false);
2322 if(rdrCtx.RenderThroughVBHeap)
2324 // render shifted primitives
2325 rdrCtx.Driver->activeIndexBuffer(rdrPass.VBHeapPBlock);
2326 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.VBHeapPBlock.getNumIndexes()/3);
2328 else
2330 // render primitives
2331 rdrCtx.Driver->activeIndexBuffer(rdrPass.PBlock);
2332 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
2336 // ***************************************************************************
2337 void CMeshGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
2339 // MeshVertexProgram ?
2340 if( _SupportMBRFlags & MBRCurrentUseVP )
2342 // End Mesh
2343 _MeshVertexProgram->endMBRMesh( rdrCtx.Driver );
2345 // and remove Current Flag.
2346 _SupportMBRFlags&= ~MBRCurrentUseVP;
2350 // ***************************************************************************
2351 bool CMeshGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
2353 // CMeshGeom support VBHeap rendering, assuming supportMeshBlockRendering is true.
2354 if( _SupportMBRFlags )
2355 /* Yoyo: If VertexProgram, DON'T SUPPORT!! because VB need to be activated AFTER meshVP activation
2356 NB: still possible with complex code to do it (sort per VP type (with or not)...), but tests in Ryzom
2357 shows that VBHeap is not really important (not so much different shapes...)
2359 if( _MeshVertexProgram==NULL )
2361 vertexFormat= _VBuffer.getVertexFormat();
2362 numVertices= _VBuffer.getNumVertices();
2363 return true;
2366 return false;
2369 // ***************************************************************************
2370 void CMeshGeom::computeMeshVBHeap(void *dst, uint indexStart)
2372 // Fill dst with Buffer content.
2373 CVertexBufferRead vba;
2374 _VBuffer.lock (vba);
2375 memcpy(dst, vba.getVertexCoordPointer(), _VBuffer.getNumVertices()*_VBuffer.getVertexSize() );
2377 // NB: only 1 MB is possible ...
2378 nlassert(_MatrixBlocks.size()==1);
2379 CMatrixBlock &mBlock= _MatrixBlocks[0];
2380 // For all rdrPass.
2381 for(uint i=0;i<mBlock.RdrPass.size();i++)
2383 // shift the PB
2384 CIndexBuffer &srcPb= mBlock.RdrPass[i].PBlock;
2385 CIndexBuffer &dstPb= mBlock.RdrPass[i].VBHeapPBlock;
2386 uint j;
2388 // Tris.
2389 dstPb.setNumIndexes(srcPb.getNumIndexes());
2390 CIndexBufferRead ibaRead;
2391 srcPb.lock (ibaRead);
2392 CIndexBufferReadWrite ibaWrite;
2393 dstPb.lock (ibaWrite);
2394 // nico : apparently not used, so don't manage 16 bits index here
2395 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
2396 nlassert(ibaWrite.getFormat() == CIndexBuffer::Indices32);
2397 const uint32 *srcTriPtr= (const uint32 *) ibaRead.getPtr();
2398 uint32 *dstTriPtr= (uint32 *) ibaWrite.getPtr();
2399 for(j=0; j<dstPb.getNumIndexes();j++)
2401 dstTriPtr[j]= srcTriPtr[j]+indexStart;
2407 // ***************************************************************************
2408 // ***************************************************************************
2409 // CMeshBuild components.
2410 // ***************************************************************************
2411 // ***************************************************************************
2415 // ***************************************************************************
2416 CMesh::CCorner::CCorner()
2418 sint i;
2419 Vertex= 0;
2420 Normal= CVector::Null;
2421 for(i=0;i<CVertexBuffer::MaxStage;i++)
2423 Uvws[i]= CUVW(0, 0, 0);
2425 Color.set(255,255,255,255);
2426 Specular.set(0,0,0,0);
2430 // ***************************************************************************
2431 void CMesh::CCorner::serial(NLMISC::IStream &f)
2433 nlassert(0); // not used
2434 f.serial(Vertex);
2435 f.serial(Normal);
2436 for(int i=0;i<CVertexBuffer::MaxStage;++i) f.serial(Uvws[i]);
2437 f.serial(Color);
2438 f.serial(Specular);
2441 // ***************************************************************************
2442 void CMesh::CFace::serial(NLMISC::IStream &f)
2444 for(int i=0;i<3;++i)
2445 f.serial(Corner[i]);
2446 f.serial(MaterialId);
2447 f.serial(SmoothGroup);
2450 // ***************************************************************************
2451 void CMesh::CSkinWeight::serial(NLMISC::IStream &f)
2453 for(int i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;++i)
2455 f.serial(MatrixId[i]);
2456 f.serial(Weights[i]);
2460 // ***************************************************************************
2461 /* Serialization is not used.
2462 void CMesh::CMeshBuild::serial(NLMISC::IStream &f)
2464 sint ver= f.serialVersion(0);
2466 // Serial mesh base (material info).
2467 CMeshBaseBuild::serial(f);
2469 // Serial Geometry.
2470 f.serial( VertexFlags );
2471 f.serialCont( Vertices );
2472 f.serialCont( SkinWeights );
2473 f.serialCont( Faces );
2478 // ************************************
2479 CMesh::CMeshBuild::CMeshBuild()
2481 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
2483 NumCoords[k] = 2;
2484 UVRouting[k] = k;
2489 // ***************************************************************************
2490 // ***************************************************************************
2491 // CMesh.
2492 // ***************************************************************************
2493 // ***************************************************************************
2497 // ***************************************************************************
2498 CMesh::CMesh()
2500 /* ***********************************************
2501 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2502 * It can be loaded/called through CAsyncFileManager for instance
2503 * ***********************************************/
2505 // create the MeshGeom
2506 _MeshGeom= new CMeshGeom;
2508 // ***************************************************************************
2509 CMesh::~CMesh()
2511 /* ***********************************************
2512 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2513 * It can be loaded/called through CAsyncFileManager for instance
2514 * ***********************************************/
2516 // delete the MeshGeom
2517 delete _MeshGeom;
2521 // ***************************************************************************
2522 CMesh::CMesh(const CMesh &mesh) : CMeshBase()
2524 // create the MeshGeom
2525 _MeshGeom= new CMeshGeom(*mesh._MeshGeom);
2529 // ***************************************************************************
2530 CMesh &CMesh::operator=(const CMesh &mesh)
2532 // Copy CMeshBase part
2533 (CMeshBase&)*this= (CMeshBase&)mesh;
2535 // copy content of meshGeom.
2536 *_MeshGeom= *mesh._MeshGeom;
2539 return *this;
2544 // ***************************************************************************
2545 void CMesh::build (CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &m)
2547 /// copy MeshBase info: materials ....
2548 CMeshBase::buildMeshBase (mbase);
2550 // build the geometry.
2551 _MeshGeom->build (m, (uint)mbase.Materials.size());
2553 // compile some stuff
2554 compileRunTime();
2558 // ***************************************************************************
2559 void CMesh::optimizeMaterialUsage(std::vector<sint> &remap)
2561 // For each material, count usage.
2562 vector<bool> materialUsed;
2563 materialUsed.resize(CMeshBase::_Materials.size(), false);
2564 for(uint mb=0;mb<getNbMatrixBlock();mb++)
2566 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
2568 uint matId= getRdrPassMaterial(mb, rp);
2569 // flag as used.
2570 materialUsed[matId]= true;
2574 // Apply it to meshBase
2575 CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
2577 // Apply lut to meshGeom.
2578 _MeshGeom->applyMaterialRemap(remap);
2582 // ***************************************************************************
2583 void CMesh::setBlendShapes(std::vector<CBlendShape>&bs)
2585 _MeshGeom->setBlendShapes (bs);
2588 // ***************************************************************************
2589 void CMesh::build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom)
2591 /// copy MeshBase info: materials ....
2592 CMeshBase::buildMeshBase(mbuild);
2594 // build the geometry.
2595 *_MeshGeom= meshGeom;
2597 // compile some stuff
2598 compileRunTime();
2602 // ***************************************************************************
2603 CTransformShape *CMesh::createInstance(CScene &scene)
2605 // Create a CMeshInstance, an instance of a mesh.
2606 //===============================================
2607 CMeshInstance *mi= (CMeshInstance*)scene.createModel(NL3D::MeshInstanceId);
2608 mi->Shape= this;
2610 // instanciate the material part of the Mesh, ie the CMeshBase.
2611 CMeshBase::instanciateMeshBase(mi, &scene);
2614 // do some instance init for MeshGeom
2615 _MeshGeom->initInstance(mi);
2617 // init render Filter
2618 mi->initRenderFilterType();
2620 return mi;
2624 // ***************************************************************************
2625 bool CMesh::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
2627 return _MeshGeom->clip(pyramid, worldMatrix);
2631 // ***************************************************************************
2632 void CMesh::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
2634 // 0 or 0xFFFFFFFF
2635 uint32 mask= (0-(uint32)passOpaque);
2636 uint32 rdrFlags;
2637 // select rdrFlags, without ifs.
2638 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
2639 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
2640 // render the mesh
2641 _MeshGeom->render(drv, trans, 0, rdrFlags, 1);
2645 // ***************************************************************************
2646 void CMesh::serial(NLMISC::IStream &f)
2648 /* ***********************************************
2649 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2650 * It can be loaded/called through CAsyncFileManager for instance
2651 * ***********************************************/
2654 Version 6:
2655 - cut in serialisation, because of:
2656 - bad ITexture serialisation (with no version....) => must cut. (see CMeshBase serial).
2657 - because of this and to simplify, make a cut too in CMesh serialisation.
2658 NB : all old version code is dropped.
2660 sint ver= f.serialVersion(6);
2663 if(ver<6)
2664 throw NLMISC::EStream(f, "Mesh in Stream is too old (Mesh version < 6)");
2667 // serial Materials infos contained in CMeshBase.
2668 CMeshBase::serialMeshBase(f);
2671 // serial geometry.
2672 _MeshGeom->serial(f);
2674 // if reading, compile some stuff
2675 if(f.isReading())
2676 compileRunTime();
2680 // ***************************************************************************
2681 const NLMISC::CAABBoxExt& CMesh::getBoundingBox() const
2683 return _MeshGeom->getBoundingBox();
2685 // ***************************************************************************
2686 const CVertexBuffer &CMesh::getVertexBuffer() const
2688 return _MeshGeom->getVertexBuffer() ;
2690 // ***************************************************************************
2691 uint CMesh::getNbMatrixBlock() const
2693 return _MeshGeom->getNbMatrixBlock();
2695 // ***************************************************************************
2696 uint CMesh::getNbRdrPass(uint matrixBlockIndex) const
2698 return _MeshGeom->getNbRdrPass(matrixBlockIndex) ;
2700 // ***************************************************************************
2701 const CIndexBuffer &CMesh::getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
2703 return _MeshGeom->getRdrPassPrimitiveBlock(matrixBlockIndex, renderingPassIndex) ;
2705 // ***************************************************************************
2706 uint32 CMesh::getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
2708 return _MeshGeom->getRdrPassMaterial(matrixBlockIndex, renderingPassIndex) ;
2710 // ***************************************************************************
2711 float CMesh::getNumTriangles (float distance)
2713 // A CMesh do not degrad himself, so return 0, to not be taken into account.
2714 return 0;
2716 // ***************************************************************************
2717 const CMeshGeom& CMesh::getMeshGeom () const
2719 return *_MeshGeom;
2721 // ***************************************************************************
2722 void CMesh::computeBonesId (CSkeletonModel *skeleton)
2724 nlassert (_MeshGeom);
2725 _MeshGeom->computeBonesId (skeleton);
2729 // ***************************************************************************
2730 void CMesh::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
2732 nlassert (_MeshGeom);
2733 _MeshGeom->updateSkeletonUsage(sm, increment);
2736 // ***************************************************************************
2737 IMeshGeom *CMesh::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
2739 // Ok if meshGeom is ok.
2740 if(_MeshGeom->supportMeshBlockRendering())
2742 polygonCount= 0;
2743 return _MeshGeom;
2745 else
2746 return NULL;
2750 // ***************************************************************************
2751 void CMesh::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
2753 // 0 or 0xFFFFFFFF
2754 uint32 mask= (0-(uint32)passOpaque);
2755 uint32 rdrFlags;
2756 // select rdrFlags, without ifs.
2757 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
2758 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
2759 // render the mesh
2760 _MeshGeom->profileSceneRender(rdrTrav, trans, 0, rdrFlags);
2763 // ***************************************************************************
2764 void CMesh::compileRunTime()
2766 /* ***********************************************
2767 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
2768 * It can be loaded/called through CAsyncFileManager for instance
2769 * ***********************************************/
2771 // **** try to build a Visual Collision Mesh
2772 // clear first
2773 if(_VisualCollisionMesh)
2775 delete _VisualCollisionMesh;
2776 _VisualCollisionMesh= NULL;
2778 // build only if wanted
2779 if( (_CollisionMeshGeneration==AutoCameraCol && !_LightInfos.empty()) ||
2780 _CollisionMeshGeneration==ForceCameraCol )
2783 vector<CVector> vertices;
2784 vector<uint32> indices;
2785 if(_MeshGeom->retrieveVertices(vertices) && _MeshGeom->retrieveTriangles(indices))
2787 // ok, can build!
2788 _VisualCollisionMesh= new CVisualCollisionMesh;
2789 // if fails to build cause of too many vertices/indices for instance
2790 if( !_VisualCollisionMesh->build(vertices, indices,const_cast<CVertexBuffer&>(_MeshGeom->getVertexBuffer())) )
2792 // delete
2793 delete _VisualCollisionMesh;
2794 _VisualCollisionMesh= NULL;
2800 // ***************************************************************************
2801 void CMesh::buildSystemGeometry()
2803 // clear any
2804 _SystemGeometry.clear();
2806 // don't build a system copy if skinned. In this case, ray intersection is done through CSkeletonModel
2807 // and intersectSkin() scheme
2808 if(_MeshGeom->isSkinned())
2809 return;
2811 // retrieve geometry (if VB/IB not resident)
2812 if( !_MeshGeom->retrieveVertices(_SystemGeometry.Vertices) ||
2813 !_MeshGeom->retrieveTriangles(_SystemGeometry.Triangles))
2815 _SystemGeometry.clear();
2818 // TestYoyo
2819 /*static uint32 totalMem= 0;
2820 totalMem+= _SystemGeometry.Vertices.size()*sizeof(CVector);
2821 totalMem+= _SystemGeometry.Triangles.size()*sizeof(uint32);
2822 nlinfo("CMesh: TotalMem: %d", totalMem);*/
2826 } // NL3D