Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / mesh_mrm.cpp
blobf31720f353b067c599a2bee7f4732cdba11add81
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/misc/bsphere.h"
20 #include "nel/misc/system_info.h"
21 #include "nel/misc/hierarchical_timer.h"
22 #include "nel/misc/fast_mem.h"
23 #include "nel/3d/mesh_mrm.h"
24 #include "nel/3d/mrm_builder.h"
25 #include "nel/3d/mrm_parameters.h"
26 #include "nel/3d/mesh_mrm_instance.h"
27 #include "nel/3d/scene.h"
28 #include "nel/3d/skeleton_model.h"
29 #include "nel/3d/stripifier.h"
30 #include "nel/3d/mesh_blender.h"
31 #include "nel/3d/render_trav.h"
32 #include "nel/misc/fast_floor.h"
33 #include "nel/3d/raw_skin.h"
34 #include "nel/3d/shifted_triangle_cache.h"
35 #include "nel/3d/texture_file.h"
38 using namespace NLMISC;
39 using namespace std;
41 #ifdef DEBUG_NEW
42 #define new DEBUG_NEW
43 #endif
45 namespace NL3D
49 H_AUTO_DECL( NL3D_MeshMRMGeom_RenderShadow )
52 // ***************************************************************************
53 // ***************************************************************************
54 // CMeshMRMGeom::CLod
55 // ***************************************************************************
56 // ***************************************************************************
59 // ***************************************************************************
60 void CMeshMRMGeom::CLod::serial(NLMISC::IStream &f)
63 Version 2:
64 - precompute of triangle order. (nothing more to load).
65 Version 1:
66 - add VertexBlocks;
67 Version 0:
68 - base vdrsion.
71 sint ver= f.serialVersion(2);
72 uint i;
74 f.serial(NWedges);
75 f.serialCont(RdrPass);
76 f.serialCont(Geomorphs);
77 f.serialCont(MatrixInfluences);
79 // Serial array of InfluencedVertices. NB: code written so far for NL3D_MESH_SKINNING_MAX_MATRIX==4 only.
80 nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
81 for(i= 0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
83 f.serialCont(InfluencedVertices[i]);
86 if(ver>=1)
87 f.serialCont(SkinVertexBlocks);
88 else
89 buildSkinVertexBlocks();
91 // if >= version 2, reorder of triangles is precomputed, else compute it now.
92 if(ver<2)
93 optimizeTriangleOrder();
98 // ***************************************************************************
99 void CMeshMRMGeom::CLod::buildSkinVertexBlocks()
101 contReset(SkinVertexBlocks);
104 // The list of vertices. true if used by this lod.
105 vector<bool> vertexMap;
106 vertexMap.resize(NWedges, false);
109 // from InfluencedVertices, aknoledge what vertices are used.
110 uint i;
111 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
113 uint nInf= (uint)InfluencedVertices[i].size();
114 if( nInf==0 )
115 continue;
116 uint32 *infPtr= &(InfluencedVertices[i][0]);
118 // for all InfluencedVertices only.
119 for(;nInf>0;nInf--, infPtr++)
121 uint index= *infPtr;
122 vertexMap[index]= true;
126 // For all vertices, test if they are used, and build the according SkinVertexBlocks;
127 CVertexBlock *vBlock= NULL;
128 for(i=0; i<vertexMap.size();i++)
130 if(vertexMap[i])
132 // preceding block?
133 if(vBlock)
135 // yes, extend it.
136 vBlock->NVertices++;
138 else
140 // no, append a new one.
141 SkinVertexBlocks.push_back(CVertexBlock());
142 vBlock= &SkinVertexBlocks[SkinVertexBlocks.size()-1];
143 vBlock->VertexStart= i;
144 vBlock->NVertices= 1;
147 else
149 // Finish the preceding block (if any).
150 vBlock= NULL;
157 // ***************************************************************************
158 void CMeshMRMGeom::CLod::optimizeTriangleOrder()
160 CStripifier stripifier;
162 // for all rdrpass
163 for(uint rp=0; rp<RdrPass.size(); rp++ )
165 // stripify list of triangles of this pass.
166 CRdrPass &pass= RdrPass[rp];
167 stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
173 // ***************************************************************************
174 // ***************************************************************************
175 // CMeshMRMGeom.
176 // ***************************************************************************
177 // ***************************************************************************
182 // ***************************************************************************
183 static NLMISC::CAABBoxExt makeBBox(const std::vector<CVector> &Vertices)
185 NLMISC::CAABBox ret;
186 nlassert(!Vertices.empty());
187 ret.setCenter(Vertices[0]);
188 for(sint i=0;i<(sint)Vertices.size();i++)
190 ret.extend(Vertices[i]);
193 return ret;
197 // ***************************************************************************
198 CMeshMRMGeom::CMeshMRMGeom()
200 _Skinned= false;
201 _NbLodLoaded= 0;
202 _BoneIdComputed = false;
203 _BoneIdExtended = false;
204 _PreciseClipping= false;
205 _SupportSkinGrouping= false;
206 _MeshDataId= 0;
207 _SupportMeshBlockRendering= false;
208 _MBRCurrentLodId= 0;
209 _SupportShadowSkinGrouping= false;
213 // ***************************************************************************
214 CMeshMRMGeom::~CMeshMRMGeom()
219 // ***************************************************************************
220 void CMeshMRMGeom::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
222 // check input.
223 if(distanceFinest<0) return;
224 if(distanceMiddle<=distanceFinest) return;
225 if(distanceCoarsest<=distanceMiddle) return;
227 // Change.
228 _LevelDetail.DistanceFinest= distanceFinest;
229 _LevelDetail.DistanceMiddle= distanceMiddle;
230 _LevelDetail.DistanceCoarsest= distanceCoarsest;
232 // compile
233 _LevelDetail.compileDistanceSetup();
237 // ***************************************************************************
238 void CMeshMRMGeom::build(CMesh::CMeshBuild &m, std::vector<CMesh::CMeshBuild*> &bsList,
239 uint numMaxMaterial, const CMRMParameters &params)
241 // Empty geometry?
242 if(m.Vertices.empty() || m.Faces.empty())
244 _VBufferFinal.setNumVertices(0);
245 _VBufferFinal.reserve(0);
246 _Lods.clear();
247 _BBox.setCenter(CVector::Null);
248 _BBox.setSize(CVector::Null);
249 return;
251 nlassert(numMaxMaterial>0);
254 // SmartPtr Copy VertexProgram effect.
255 //================================================
256 this->_MeshVertexProgram= m.MeshVertexProgram;
259 /// 0. First, make bbox.
260 //======================
261 // NB: this is equivalent as building BBox from MRM VBuffer, because CMRMBuilder create new vertices
262 // which are just interpolation of original vertices.
263 _BBox= makeBBox(m.Vertices);
266 /// 1. Launch the MRM build process.
267 //================================================
268 CMRMBuilder mrmBuilder;
269 CMeshBuildMRM meshBuildMRM;
271 mrmBuilder.compileMRM(m, bsList, params, meshBuildMRM, numMaxMaterial);
273 // Then just copy result!
274 //================================================
275 _VBufferFinal= meshBuildMRM.VBuffer;
276 _Lods= meshBuildMRM.Lods;
277 _Skinned= meshBuildMRM.Skinned;
278 _SkinWeights= meshBuildMRM.SkinWeights;
280 // Compute degradation control.
281 //================================================
282 _LevelDetail.DistanceFinest= meshBuildMRM.DistanceFinest;
283 _LevelDetail.DistanceMiddle= meshBuildMRM.DistanceMiddle;
284 _LevelDetail.DistanceCoarsest= meshBuildMRM.DistanceCoarsest;
285 nlassert(_LevelDetail.DistanceFinest>=0);
286 nlassert(_LevelDetail.DistanceMiddle > _LevelDetail.DistanceFinest);
287 nlassert(_LevelDetail.DistanceCoarsest > _LevelDetail.DistanceMiddle);
288 // Compute OODistDelta and DistancePow
289 _LevelDetail.compileDistanceSetup();
292 // Build the _LodInfos.
293 //================================================
294 _LodInfos.resize(_Lods.size());
295 uint32 precNWedges= 0;
296 uint i;
297 for(i=0;i<_Lods.size();i++)
299 _LodInfos[i].StartAddWedge= precNWedges;
300 _LodInfos[i].EndAddWedges= _Lods[i].NWedges;
301 precNWedges= _Lods[i].NWedges;
302 // LodOffset is filled in serial() when stream is input.
304 // After build, all lods are present in memory.
305 _NbLodLoaded= (uint)_Lods.size();
308 // For load balancing.
309 //================================================
310 // compute Max Face Used
311 _LevelDetail.MaxFaceUsed= 0;
312 _LevelDetail.MinFaceUsed= 0;
313 // Count of primitive block
314 if (!_Lods.empty())
316 uint pb;
317 // Compute MinFaces.
318 CLod &firstLod= _Lods[0];
319 for (pb=0; pb<firstLod.RdrPass.size(); pb++)
321 CRdrPass &pass= firstLod.RdrPass[pb];
322 // Sum tri
323 _LevelDetail.MinFaceUsed+= pass.PBlock.getNumIndexes ()/3;
325 // Compute MaxFaces.
326 CLod &lastLod= _Lods[_Lods.size()-1];
327 for (pb=0; pb<lastLod.RdrPass.size(); pb++)
329 CRdrPass &pass= lastLod.RdrPass[pb];
330 // Sum tri
331 _LevelDetail.MaxFaceUsed+= pass.PBlock.getNumIndexes ()/3;
336 // For skinning.
337 //================================================
338 if( _Skinned )
340 bkupOriginalSkinVertices();
342 // Inform that the mesh data has changed
343 dirtMeshDataId();
346 // For AGP SKinning optim, and for Render optim
347 //================================================
348 for(i=0;i<_Lods.size();i++)
350 _Lods[i].buildSkinVertexBlocks();
351 // sort triangles for better cache use.
352 _Lods[i].optimizeTriangleOrder();
355 // Copy Blend Shapes
356 //================================================
357 _MeshMorpher.BlendShapes = meshBuildMRM.BlendShapes;
360 // Compact bone id and build a bone id names
361 //================================================
363 // Skinned ?
364 if (_Skinned)
366 // Remap
367 std::map<uint, uint> remap;
369 // Current bone
370 uint currentBone = 0;
372 // Reserve memory
373 _BonesName.reserve (m.BonesNames.size());
375 // For each vertices
376 uint vert;
377 for (vert=0; vert<_SkinWeights.size(); vert++)
379 // Found one ?
380 bool found=false;
382 // For each weight
383 uint weight;
384 for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
386 // Active ?
387 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
389 // Look for it
390 std::map<uint, uint>::iterator ite = remap.find (_SkinWeights[vert].MatrixId[weight]);
392 // Find ?
393 if (ite == remap.end())
395 // Insert it
396 remap.insert (std::map<uint, uint>::value_type (_SkinWeights[vert].MatrixId[weight], currentBone));
398 // Check the id
399 nlassert (_SkinWeights[vert].MatrixId[weight]<m.BonesNames.size());
401 // Set the bone name
402 _BonesName.push_back (m.BonesNames[_SkinWeights[vert].MatrixId[weight]]);
404 // Set the local bone id
405 _SkinWeights[vert].MatrixId[weight] = currentBone++;
407 else
409 // Set the local bone id
410 _SkinWeights[vert].MatrixId[weight] = ite->second;
413 // Found one
414 found = true;
418 // Found one ?
419 nlassert (found);
422 // Remap the vertex influence by lods
423 uint lod;
424 for (lod=0; lod<_Lods.size(); lod++)
426 // For each matrix used
427 uint matrix;
428 for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
430 // Remap
431 std::map<uint, uint>::iterator ite = remap.find (_Lods[lod].MatrixInfluences[matrix]);
433 // Find ?
434 nlassert (ite != remap.end());
436 // Remap
437 _Lods[lod].MatrixInfluences[matrix] = ite->second;
442 // Misc.
443 //===================
444 // Some runtime not serialized compilation
445 compileRunTime();
449 // ***************************************************************************
450 void CMeshMRMGeom::applyMaterialRemap(const std::vector<sint> &remap)
452 for(uint lod=0;lod<getNbLod();lod++)
454 for(uint rp=0;rp<getNbRdrPass(lod);rp++)
456 // remap
457 uint32 &matId= _Lods[lod].RdrPass[rp].MaterialId;
458 nlassert(remap[matId]>=0);
459 matId= remap[matId];
464 // ***************************************************************************
465 void CMeshMRMGeom::applyGeomorph(std::vector<CMRMWedgeGeom> &geoms, float alphaLod)
467 applyGeomorphWithVBHardPtr(geoms, alphaLod, NULL);
471 // ***************************************************************************
472 void CMeshMRMGeom::applyGeomorphWithVBHardPtr(std::vector<CMRMWedgeGeom> &geoms, float alphaLod, uint8 *vertexDestPtr)
474 // no geomorphs? quit.
475 if(geoms.empty())
476 return;
478 clamp(alphaLod, 0.f, 1.f);
479 float a= alphaLod;
480 float a1= 1 - alphaLod;
483 // info from VBuffer.
484 CVertexBufferReadWrite vba;
485 _VBufferFinal.lock (vba);
486 uint8 *vertexPtr= (uint8*)vba.getVertexCoordPointer();
487 uint flags= _VBufferFinal.getVertexFormat();
488 sint32 vertexSize= _VBufferFinal.getVertexSize();
489 // because of the unrolled code for 4 first UV, must assert this.
490 nlassert(CVertexBuffer::MaxStage>=4);
491 // must have XYZ.
492 nlassert(flags & CVertexBuffer::PositionFlag);
495 // If VBuffer Hard disabled
496 if(vertexDestPtr==NULL)
498 // write into vertexPtr.
499 vertexDestPtr= vertexPtr;
503 // if it is a common format
504 if( flags== (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag) &&
505 _VBufferFinal.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2 )
507 // use a faster method
508 applyGeomorphPosNormalUV0(geoms, vertexPtr, vertexDestPtr, vertexSize, a, a1);
510 else
512 // for color interp
513 uint i;
514 uint ua= (uint)(a*256);
515 clamp(ua, (uint)0, (uint)256);
516 uint ua1= 256 - ua;
518 // if an offset is 0, it means that the component is not in the VBuffer.
519 sint32 normalOff;
520 sint32 colorOff;
521 sint32 specularOff;
522 sint32 uvOff[CVertexBuffer::MaxStage];
523 bool has3Coords[CVertexBuffer::MaxStage];
526 // Compute offset of each component of the VB.
527 if(flags & CVertexBuffer::NormalFlag)
528 normalOff= _VBufferFinal.getNormalOff();
529 else
530 normalOff= 0;
531 if(flags & CVertexBuffer::PrimaryColorFlag)
532 colorOff= _VBufferFinal.getColorOff();
533 else
534 colorOff= 0;
535 if(flags & CVertexBuffer::SecondaryColorFlag)
536 specularOff= _VBufferFinal.getSpecularOff();
537 else
538 specularOff= 0;
540 for(i= 0; i<CVertexBuffer::MaxStage;i++)
542 if(flags & (CVertexBuffer::TexCoord0Flag<<i))
544 uvOff[i]= _VBufferFinal.getTexCoordOff(i);
545 has3Coords[i] = (_VBufferFinal.getValueType(i + CVertexBuffer::TexCoord0) == CVertexBuffer::Float3);
547 else
549 uvOff[i]= 0;
554 // For all geomorphs.
555 uint nGeoms= (uint)geoms.size();
556 CMRMWedgeGeom *ptrGeom= &(geoms[0]);
557 uint8 *destPtr= vertexDestPtr;
558 /* NB: optimisation: lot of "if" in this Loop, but because of BTB, they always cost nothing (prediction is good).
559 NB: this also is why we unroll the 4 1st Uv. The other (if any), are done in the other loop.
560 NB: optimisation for AGP write cominers: the order of write (vertex, normal, uvs...) is important for good
561 use of AGP write combiners.
562 We have 2 version : one that tests for 3 coordinates texture coords, and one that doesn't
565 if (!has3Coords[0] && !has3Coords[1] && !has3Coords[2] && !has3Coords[3])
567 // there are no texture coordinate of dimension 3
568 for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
570 uint8 *startPtr= vertexPtr + ptrGeom->Start*vertexSize;
571 uint8 *endPtr= vertexPtr + ptrGeom->End*vertexSize;
573 // Vertex.
575 CVector *start= (CVector*)startPtr;
576 CVector *end= (CVector*)endPtr;
577 CVector *dst= (CVector*)destPtr;
578 *dst= *start * a + *end * a1;
581 // Normal.
582 if(normalOff)
584 CVector *start= (CVector*)(startPtr + normalOff);
585 CVector *end= (CVector*)(endPtr + normalOff);
586 CVector *dst= (CVector*)(destPtr + normalOff);
587 *dst= *start * a + *end * a1;
591 // Uvs.
592 // uv[0].
593 if(uvOff[0])
595 // Uv.
596 CUV *start= (CUV*)(startPtr + uvOff[0]);
597 CUV *end= (CUV*)(endPtr + uvOff[0]);
598 CUV *dst= (CUV*)(destPtr + uvOff[0]);
599 *dst= *start * a + *end * a1;
601 // uv[1].
602 if(uvOff[1])
604 // Uv.
605 CUV *start= (CUV*)(startPtr + uvOff[1]);
606 CUV *end= (CUV*)(endPtr + uvOff[1]);
607 CUV *dst= (CUV*)(destPtr + uvOff[1]);
608 *dst= *start * a + *end * a1;
610 // uv[2].
611 if(uvOff[2])
613 CUV *start= (CUV*)(startPtr + uvOff[2]);
614 CUV *end= (CUV*)(endPtr + uvOff[2]);
615 CUV *dst= (CUV*)(destPtr + uvOff[2]);
616 *dst= *start * a + *end * a1;
618 // uv[3].
619 if(uvOff[3])
621 // Uv.
622 CUV *start= (CUV*)(startPtr + uvOff[3]);
623 CUV *end= (CUV*)(endPtr + uvOff[3]);
624 CUV *dst= (CUV*)(destPtr + uvOff[3]);
625 *dst= *start * a + *end * a1;
629 else // THERE ARE TEXTURE COORDINATES OF DIMENSION 3
631 for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
633 uint8 *startPtr= vertexPtr + ptrGeom->Start*vertexSize;
634 uint8 *endPtr= vertexPtr + ptrGeom->End*vertexSize;
636 // Vertex.
638 CVector *start= (CVector*)startPtr;
639 CVector *end= (CVector*)endPtr;
640 CVector *dst= (CVector*)destPtr;
641 *dst= *start * a + *end * a1;
644 // Normal.
645 if(normalOff)
647 CVector *start= (CVector*)(startPtr + normalOff);
648 CVector *end= (CVector*)(endPtr + normalOff);
649 CVector *dst= (CVector*)(destPtr + normalOff);
650 *dst= *start * a + *end * a1;
652 // Uvs.
653 // uv[0].
654 if(uvOff[0])
656 if (!has3Coords[0])
658 // Uv.
659 CUV *start= (CUV*)(startPtr + uvOff[0]);
660 CUV *end= (CUV*)(endPtr + uvOff[0]);
661 CUV *dst= (CUV*)(destPtr + uvOff[0]);
662 *dst= *start * a + *end * a1;
664 else
666 // Uv.
667 CUVW *start= (CUVW*)(startPtr + uvOff[0]);
668 CUVW *end= (CUVW*)(endPtr + uvOff[0]);
669 CUVW *dst= (CUVW*)(destPtr + uvOff[0]);
670 *dst= *start * a + *end * a1;
673 // uv[1].
674 if(uvOff[1])
676 if (!has3Coords[1])
678 // Uv.
679 CUV *start= (CUV*)(startPtr + uvOff[1]);
680 CUV *end= (CUV*)(endPtr + uvOff[1]);
681 CUV *dst= (CUV*)(destPtr + uvOff[1]);
682 *dst= *start * a + *end * a1;
684 else
686 // Uv.
687 CUVW *start= (CUVW*)(startPtr + uvOff[1]);
688 CUVW *end= (CUVW*)(endPtr + uvOff[1]);
689 CUVW *dst= (CUVW*)(destPtr + uvOff[1]);
690 *dst= *start * a + *end * a1;
693 // uv[2].
694 if(uvOff[2])
696 if (!has3Coords[2])
698 // Uv.
699 CUV *start= (CUV*)(startPtr + uvOff[2]);
700 CUV *end= (CUV*)(endPtr + uvOff[2]);
701 CUV *dst= (CUV*)(destPtr + uvOff[2]);
702 *dst= *start * a + *end * a1;
704 else
706 // Uv.
707 CUVW *start= (CUVW*)(startPtr + uvOff[2]);
708 CUVW *end= (CUVW*)(endPtr + uvOff[2]);
709 CUVW *dst= (CUVW*)(destPtr + uvOff[2]);
710 *dst= *start * a + *end * a1;
713 // uv[3].
714 if(uvOff[3])
716 if (!has3Coords[3])
718 // Uv.
719 CUV *start= (CUV*)(startPtr + uvOff[3]);
720 CUV *end= (CUV*)(endPtr + uvOff[3]);
721 CUV *dst= (CUV*)(destPtr + uvOff[3]);
722 *dst= *start * a + *end * a1;
724 else
726 // Uv.
727 CUVW *start= (CUVW*)(startPtr + uvOff[3]);
728 CUVW *end= (CUVW*)(endPtr + uvOff[3]);
729 CUVW *dst= (CUVW*)(destPtr + uvOff[3]);
730 *dst= *start * a + *end * a1;
733 // color.
734 if(colorOff)
736 CRGBA *start= (CRGBA*)(startPtr + colorOff);
737 CRGBA *end= (CRGBA*)(endPtr + colorOff);
738 CRGBA *dst= (CRGBA*)(destPtr + colorOff);
739 dst->blendFromui(*start, *end, ua1);
741 // specular.
742 if(specularOff)
744 CRGBA *start= (CRGBA*)(startPtr + specularOff);
745 CRGBA *end= (CRGBA*)(endPtr + specularOff);
746 CRGBA *dst= (CRGBA*)(destPtr + specularOff);
747 dst->blendFromui(*start, *end, ua1);
753 // Process extra UVs (maybe never, so don't bother optims :)).
754 // For all stages after 4.
755 for(i=4;i<CVertexBuffer::MaxStage;i++)
757 uint nGeoms= (uint)geoms.size();
758 CMRMWedgeGeom *ptrGeom= &(geoms[0]);
759 uint8 *destPtr= vertexDestPtr;
761 if(uvOff[i]==0)
762 continue;
764 // For all geomorphs.
765 for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
767 uint8 *startPtr= vertexPtr + ptrGeom->Start*vertexSize;
768 uint8 *endPtr= vertexPtr + ptrGeom->End*vertexSize;
770 // uv[i].
771 // Uv.
772 if (!has3Coords[i])
774 CUV *start= (CUV*)(startPtr + uvOff[i]);
775 CUV *end= (CUV*)(endPtr + uvOff[i]);
776 CUV *dst= (CUV*)(destPtr + uvOff[i]);
777 *dst= *start * a + *end * a1;
779 else
781 CUVW *start= (CUVW*)(startPtr + uvOff[i]);
782 CUVW *end= (CUVW*)(endPtr + uvOff[i]);
783 CUVW *dst= (CUVW*)(destPtr + uvOff[i]);
784 *dst= *start * a + *end * a1;
792 // ***************************************************************************
793 void CMeshMRMGeom::applyGeomorphPosNormalUV0(std::vector<CMRMWedgeGeom> &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, float a, float a1)
795 nlassert(vertexSize==32);
798 // For all geomorphs.
799 uint nGeoms= (uint)geoms.size();
800 CMRMWedgeGeom *ptrGeom= &(geoms[0]);
801 uint8 *destPtr= vertexDestPtr;
802 for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
804 // Consider the Pos/Normal/UV as an array of 8 float to interpolate.
805 float *start= (float*)(vertexPtr + (ptrGeom->Start<<5));
806 float *end= (float*)(vertexPtr + (ptrGeom->End<<5));
807 float *dst= (float*)(destPtr);
809 // unrolled
810 dst[0]= start[0] * a + end[0]* a1;
811 dst[1]= start[1] * a + end[1]* a1;
812 dst[2]= start[2] * a + end[2]* a1;
813 dst[3]= start[3] * a + end[3]* a1;
814 dst[4]= start[4] * a + end[4]* a1;
815 dst[5]= start[5] * a + end[5]* a1;
816 dst[6]= start[6] * a + end[6]* a1;
817 dst[7]= start[7] * a + end[7]* a1;
822 // ***************************************************************************
823 void CMeshMRMGeom::initInstance(CMeshBaseInstance *mbi)
825 // init the instance with _MeshVertexProgram infos
826 if(_MeshVertexProgram)
827 _MeshVertexProgram->initInstance(mbi);
831 // ***************************************************************************
832 bool CMeshMRMGeom::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
834 // Speed Clip: clip just the sphere.
835 CBSphere localSphere(_BBox.getCenter(), _BBox.getRadius());
836 CBSphere worldSphere;
838 // transform the sphere in WorldMatrix (with nearly good scale info).
839 localSphere.applyTransform(worldMatrix, worldSphere);
841 // if out of only plane, entirely out.
842 for(sint i=0;i<(sint)pyramid.size();i++)
844 // We are sure that pyramid has normalized plane normals.
845 // if SpherMax OUT return false.
846 float d= pyramid[i]*worldSphere.Center;
847 if(d>worldSphere.Radius)
848 return false;
851 // test if must do a precise clip, according to mesh size.
852 if( _PreciseClipping )
854 CPlane localPlane;
856 // if out of only plane, entirely out.
857 for(sint i=0;i<(sint)pyramid.size();i++)
859 // Transform the pyramid in Object space.
860 localPlane= pyramid[i]*worldMatrix;
861 // localPlane must be normalized, because worldMatrix mya have a scale.
862 localPlane.normalize();
863 // if the box is not partially inside the plane, quit
864 if( !_BBox.clipBack(localPlane) )
865 return false;
869 return true;
873 // ***************************************************************************
874 inline sint CMeshMRMGeom::chooseLod(float alphaMRM, float &alphaLod)
876 // Choose what Lod to draw.
877 alphaMRM*= _Lods.size()-1;
878 sint numLod= (sint)ceil(alphaMRM);
879 if(numLod==0)
881 numLod= 0;
882 alphaLod= 0;
884 else
886 // Lerp beetween lod i-1 and lod i.
887 alphaLod= alphaMRM-(numLod-1);
891 // If lod chosen is not loaded, take the best loaded.
892 if(numLod>=(sint)_NbLodLoaded)
894 numLod= _NbLodLoaded-1;
895 alphaLod= 1;
898 return numLod;
902 // ***************************************************************************
903 void CMeshMRMGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
905 nlassert(drv);
906 if(_Lods.empty())
907 return;
910 // get the meshMRM instance.
911 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
912 // get a ptr on scene
913 CScene *ownerScene= mi->getOwnerScene();
914 // get a ptr on renderTrav
915 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
918 // get the result of the Load Balancing.
919 float alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
921 // choose the lod.
922 float alphaLod;
923 sint numLod= chooseLod(alphaMRM, alphaLod);
926 // Render the choosen Lod.
927 CLod &lod= _Lods[numLod];
928 if(lod.RdrPass.empty())
929 return;
932 // Update the vertexBufferHard (if possible).
933 // \toto yoyo: TODO_OPTIMIZE: allocate only what is needed for the current Lod (Max of all instances, like
934 // the loading....) (see loadHeader()).
936 // get the skeleton model to which I am binded (else NULL).
937 CSkeletonModel *skeleton;
938 skeleton = mi->getSkeletonModel();
939 // The mesh must not be skinned for render()
940 nlassert(!(_Skinned && mi->isSkinned() && skeleton));
941 bool bMorphApplied = !_MeshMorpher.BlendShapes.empty();
942 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
945 // Profiling
946 //===========
947 H_AUTO( NL3D_MeshMRMGeom_RenderNormal );
950 // Morphing
951 // ========
952 if (bMorphApplied)
954 // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
955 // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
956 // are written in the preceding call to restoreOriginalSkinPart.
957 if (_Skinned)
959 _MeshMorpher.initSkinned(&_VBufferOriginal,
960 &_VBufferFinal,
961 useTangentSpace,
962 &_OriginalSkinVertices,
963 &_OriginalSkinNormals,
964 useTangentSpace ? &_OriginalTGSpace : NULL,
965 false );
966 _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
968 else // Not even skinned so we have to do all the stuff
970 _MeshMorpher.init(&_VBufferOriginal,
971 &_VBufferFinal,
972 useTangentSpace);
973 _MeshMorpher.update (mi->getBlendShapeFactors());
977 // Skinning.
978 //===========
979 // if mesh is skinned (but here skin not applied), we must copy vertices/normals from original vertices.
980 if (_Skinned)
982 // do it for this Lod only, and if cache say it is necessary.
983 if (!lod.OriginalSkinRestored)
984 restoreOriginalSkinPart(lod);
988 // set the instance worldmatrix.
989 drv->setupModelMatrix(trans->getWorldMatrix());
992 // Geomorph.
993 //===========
994 // Geomorph the choosen Lod (if not the coarser mesh).
995 if(numLod>0)
997 applyGeomorph(lod.Geomorphs, alphaLod);
1001 // force normalisation of normals..
1002 bool bkupNorm= drv->isForceNormalize();
1003 drv->forceNormalize(true);
1006 // Setup meshVertexProgram
1007 //===========
1009 // use MeshVertexProgram effect?
1010 bool useMeshVP= _MeshVertexProgram != NULL;
1011 if( useMeshVP )
1013 CMatrix invertedObjectMatrix;
1014 invertedObjectMatrix = trans->getWorldMatrix().inverted();
1015 // really ok if success to begin VP
1016 useMeshVP= _MeshVertexProgram->begin(drv, mi->getOwnerScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
1020 // Render the lod.
1021 //===========
1022 // active VB.
1023 drv->activeVertexBuffer(_VBufferFinal);
1026 // Global alpha used ?
1027 uint32 globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
1028 uint8 globalAlphaInt=(uint8)NLMISC::OptFastFloor(globalAlpha*255);
1030 // Render all pass.
1031 if (globalAlphaUsed)
1033 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
1035 // for all passes
1036 for(uint i=0;i<lod.RdrPass.size();i++)
1038 CRdrPass &rdrPass= lod.RdrPass[i];
1040 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
1041 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
1043 // CMaterial Ref
1044 CMaterial &material=mi->Materials[rdrPass.MaterialId];
1046 // Use a MeshBlender to modify material and driver.
1047 CMeshBlender blender;
1048 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
1050 // Setup VP material
1051 if (useMeshVP)
1053 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
1056 // Render
1057 drv->activeIndexBuffer(rdrPass.PBlock);
1058 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
1060 // Resetup material/driver
1061 blender.restoreRender(material, drv, gaDisableZWrite);
1065 else
1067 for(uint i=0;i<lod.RdrPass.size();i++)
1069 CRdrPass &rdrPass= lod.RdrPass[i];
1071 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
1072 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
1074 // CMaterial Ref
1075 CMaterial &material=mi->Materials[rdrPass.MaterialId];
1077 // Setup VP material
1078 if (useMeshVP)
1080 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
1083 // Render with the Materials of the MeshInstance.
1084 drv->activeIndexBuffer(rdrPass.PBlock);
1085 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
1091 // End VertexProgram effect
1092 if(useMeshVP)
1094 // end it.
1095 _MeshVertexProgram->end(drv);
1099 // bkup force normalisation.
1100 drv->forceNormalize(bkupNorm);
1105 // ***************************************************************************
1106 void CMeshMRMGeom::renderSkin(CTransformShape *trans, float alphaMRM)
1108 H_AUTO( NL3D_MeshMRMGeom_renderSkin );
1110 if(_Lods.empty())
1111 return;
1114 // get the meshMRM instance. only CMeshMRMInstance is possible when skinned (not MultiLod)
1115 CMeshMRMInstance *mi= safe_cast<CMeshMRMInstance*>(trans);
1116 // get a ptr on scene
1117 CScene *ownerScene= mi->getOwnerScene();
1118 // get a ptr on renderTrav
1119 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
1120 // get a ptr on the driver
1121 IDriver *drv= renderTrav->getDriver();
1122 nlassert(drv);
1125 // choose the lod.
1126 float alphaLod;
1127 sint numLod= chooseLod(alphaMRM, alphaLod);
1130 // Render the choosen Lod.
1131 CLod &lod= _Lods[numLod];
1132 if(lod.RdrPass.empty())
1133 return;
1137 YOYO: renderSkin() no more support vertexBufferHard()!!! for AGP Memory optimisation concern.
1138 AGP Skin rendering is made when supportSkinGrouping() is true
1139 Hence if a skin is to be rendered here, because it doesn't have a good vertex format, or it has
1140 MeshVertexProgram etc..., it will be rendered WITHOUT VBHard => slower.
1144 // get the skeleton model to which I am skinned
1145 CSkeletonModel *skeleton;
1146 skeleton = mi->getSkeletonModel();
1147 // must be skinned for renderSkin()
1148 nlassert(_Skinned && mi->isSkinned() && skeleton);
1149 bool bMorphApplied = !_MeshMorpher.BlendShapes.empty();
1150 bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
1151 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
1154 // Profiling
1155 //===========
1156 H_AUTO( NL3D_MeshMRMGeom_renderSkin_go );
1159 // Morphing
1160 // ========
1161 if (bMorphApplied)
1163 // Since Skinned we must update original skin vertices and normals because skinning use it
1164 _MeshMorpher.initSkinned(&_VBufferOriginal,
1165 &_VBufferFinal,
1166 useTangentSpace,
1167 &_OriginalSkinVertices,
1168 &_OriginalSkinNormals,
1169 useTangentSpace ? &_OriginalTGSpace : NULL,
1170 true );
1171 _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
1174 // Skinning.
1175 //===========
1177 // Never use RawSkin. Actually used in skinGrouping.
1178 updateRawSkinNormal(false, mi, numLod);
1180 // applySkin.
1181 //--------
1183 // If skin without normal (rare/useful?) always simple (slow) case.
1184 if(!useNormal)
1186 // skinning with just position
1187 applySkin (lod, skeleton);
1189 else
1191 // apply skin for this Lod only.
1192 if (!useTangentSpace)
1194 // skinning with normal, but no tangent space
1195 applySkinWithNormal (lod, skeleton);
1197 else
1199 // Tangent space stored in the last texture coordinate
1200 applySkinWithTangentSpace(lod, skeleton, _VBufferFinal.getNumTexCoordUsed() - 1);
1204 // endSkin.
1205 //--------
1206 // dirt this lod part. (NB: this is not optimal, but sufficient :) ).
1207 lod.OriginalSkinRestored= false;
1210 // NB: the skeleton matrix has already been setuped by CSkeletonModel
1211 // NB: the normalize flag has already been setuped by CSkeletonModel
1214 // Geomorph.
1215 //===========
1216 // Geomorph the choosen Lod (if not the coarser mesh).
1217 if(numLod>0)
1219 applyGeomorph(lod.Geomorphs, alphaLod);
1223 // Setup meshVertexProgram
1224 //===========
1226 // use MeshVertexProgram effect?
1227 bool useMeshVP= _MeshVertexProgram != NULL;
1228 if( useMeshVP )
1230 CMatrix invertedObjectMatrix;
1231 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
1232 // really ok if success to begin VP
1233 useMeshVP= _MeshVertexProgram->begin(drv, mi->getOwnerScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
1237 // Render the lod.
1238 //===========
1239 // active VB.
1240 drv->activeVertexBuffer(_VBufferFinal);
1243 // Render all pass.
1244 for(uint i=0;i<lod.RdrPass.size();i++)
1246 CRdrPass &rdrPass= lod.RdrPass[i];
1248 // CMaterial Ref
1249 CMaterial &material=mi->Materials[rdrPass.MaterialId];
1251 // Setup VP material
1252 if (useMeshVP)
1254 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
1257 // Render with the Materials of the MeshInstance.
1258 drv->activeIndexBuffer(rdrPass.PBlock);
1259 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
1262 // End VertexProgram effect
1263 if(useMeshVP)
1265 // end it.
1266 _MeshVertexProgram->end(drv);
1271 // ***************************************************************************
1272 bool CMeshMRMGeom::supportSkinGrouping() const
1274 return _SupportSkinGrouping;
1277 // ***************************************************************************
1278 sint CMeshMRMGeom::renderSkinGroupGeom(CMeshMRMInstance *mi, float alphaMRM, uint remainingVertices, uint8 *vbDest)
1280 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom )
1282 // NB: not need to test if _Lods.empty(), because already done through supportSkinGrouping()
1284 // get a ptr on scene
1285 CScene *ownerScene= mi->getOwnerScene();
1286 // get a ptr on renderTrav
1287 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
1288 // get a ptr on the driver
1289 IDriver *drv= renderTrav->getDriver();
1290 nlassert(drv);
1293 // choose the lod.
1294 float alphaLod;
1295 sint numLod= chooseLod(alphaMRM, alphaLod);
1296 _LastLodComputed= numLod;
1299 // Render the choosen Lod.
1300 CLod &lod= _Lods[numLod];
1301 if(lod.RdrPass.empty())
1302 // return no vertices added
1303 return 0;
1305 // If the Lod is too big to render in the VBufferHard
1306 if(lod.NWedges>remainingVertices)
1307 // return Failure
1308 return -1;
1310 // get the skeleton model to which I am skinned
1311 CSkeletonModel *skeleton;
1312 skeleton = mi->getSkeletonModel();
1313 // must be skinned for renderSkin()
1314 nlassert(_Skinned && mi->isSkinned() && skeleton);
1315 bool bMorphApplied = !_MeshMorpher.BlendShapes.empty();
1316 bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
1317 nlassert(useNormal);
1320 // Profiling
1321 //===========
1322 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom_go );
1325 // Morphing
1326 // ========
1328 // Use RawSkin?. compute before morphing, cause of updateRawSkin
1329 updateRawSkinNormal(true, mi, numLod);
1330 nlassert(mi->_RawSkinCache);
1332 // Apply morph
1333 if (bMorphApplied)
1335 // No need to manage lod.OriginalSkinRestored, since in case of SkinGroupGeom, the VBuffer final is not modified.
1337 // copy directly from the original VB, and apply BlendShapes. Dest is directly the RawSkin
1338 _MeshMorpher.updateRawSkin(&_VBufferFinal,
1339 mi->_RawSkinCache->VertexRemap,
1340 mi->getBlendShapeFactors());
1343 // Skinning.
1344 //===========
1346 // NB: the skeleton matrix has already been setuped by CSkeletonModel
1347 // NB: the normalize flag has already been setuped by CSkeletonModel
1349 // applySkin with RawSkin.
1350 //--------
1351 // always RawSkin now in SkinGrouping, even with MeshMorpher
1353 H_AUTO( NL3D_RawSkinning );
1355 // RawSkin do all the job in optimized way: Skinning, copy to VBHard and Geomorph.
1357 // skinning with normal, but no tangent space
1358 applyRawSkinWithNormal (lod, *(mi->_RawSkinCache), skeleton, vbDest, alphaLod);
1360 // Vertices are packed in RawSkin mode (ie no holes due to MRM!)
1361 return (sint)mi->_RawSkinCache->Geomorphs.size() +
1362 mi->_RawSkinCache->TotalSoftVertices +
1363 mi->_RawSkinCache->TotalHardVertices;
1367 // ***************************************************************************
1368 void CMeshMRMGeom::renderSkinGroupPrimitives(CMeshMRMInstance *mi, uint baseVertex, std::vector<CSkinSpecularRdrPass> &specularRdrPasses, uint skinIndex)
1370 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpPrimitives );
1372 // get a ptr on scene
1373 CScene *ownerScene= mi->getOwnerScene();
1374 // get a ptr on renderTrav
1375 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
1376 // get a ptr on the driver
1377 IDriver *drv= renderTrav->getDriver();
1378 nlassert(drv);
1380 // Get the lod choosen in renderSkinGroupGeom()
1381 CLod &lod= _Lods[_LastLodComputed];
1384 // must update primitive cache
1385 updateShiftedTriangleCache(mi, _LastLodComputed, baseVertex);
1386 nlassert(mi->_ShiftedTriangleCache);
1389 // Render Triangles with cache
1390 //===========
1391 for(uint i=0;i<lod.RdrPass.size();i++)
1393 CRdrPass &rdrPass= lod.RdrPass[i];
1395 // CMaterial Ref
1396 CMaterial &material=mi->Materials[rdrPass.MaterialId];
1398 // TestYoyo. Material Speed Test
1399 /*if( material.getDiffuse()!=CRGBA(250, 251, 252) )
1401 material.setDiffuse(CRGBA(250, 251, 252));
1402 // Set all texture the same.
1403 static CSmartPtr<ITexture> pTexFile= new CTextureFile("fy_hom_visage_c1_fy_e1.tga");
1404 material.setTexture(0, pTexFile );
1405 // Remove Specular.
1406 if(material.getShader()==CMaterial::Specular)
1408 CSmartPtr<ITexture> tex= material.getTexture(0);
1409 material.setShader(CMaterial::Normal);
1410 material.setTexture(0, tex );
1412 // Remove MakeUp
1413 material.setTexture(1, NULL);
1416 // If the material is a specular material, don't render it now!
1417 if(material.getShader()==CMaterial::Specular)
1419 // Add it to the rdrPass to sort!
1420 CSkinSpecularRdrPass specRdrPass;
1421 specRdrPass.SkinIndex= skinIndex;
1422 specRdrPass.RdrPassIndex= i;
1423 // Get the handle of the specular Map as the sort Key
1424 ITexture *specTex= material.getTexture(1);
1425 if(!specTex)
1426 specRdrPass.SpecId= 0;
1427 else
1428 specRdrPass.SpecId= drv->getTextureHandle( *specTex );
1429 // Append it to the list
1430 specularRdrPasses.push_back(specRdrPass);
1432 else
1434 // Get the shifted triangles.
1435 CShiftedTriangleCache::CRdrPass &shiftedRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
1437 // Render with the Materials of the MeshInstance.
1438 drv->activeIndexBuffer(mi->_ShiftedTriangleCache->RawIndices);
1439 drv->renderTriangles(material, shiftedRdrPass.Triangles, shiftedRdrPass.NumTriangles);
1445 // ***************************************************************************
1446 void CMeshMRMGeom::renderSkinGroupSpecularRdrPass(CMeshMRMInstance *mi, uint rdrPassId)
1448 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpSpecularRdrPass );
1450 // get a ptr on scene
1451 CScene *ownerScene= mi->getOwnerScene();
1452 // get a ptr on renderTrav
1453 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
1454 // get a ptr on the driver
1455 IDriver *drv= renderTrav->getDriver();
1456 nlassert(drv);
1458 // Get the lod choosen in renderSkinGroupGeom()
1459 CLod &lod= _Lods[_LastLodComputed];
1462 // _ShiftedTriangleCache must have been computed in renderSkinGroupPrimitives
1463 nlassert(mi->_ShiftedTriangleCache);
1466 // Render Triangles with cache
1467 //===========
1468 CRdrPass &rdrPass= lod.RdrPass[rdrPassId];
1470 // CMaterial Ref
1471 CMaterial &material=mi->Materials[rdrPass.MaterialId];
1473 // Get the shifted triangles.
1474 CShiftedTriangleCache::CRdrPass &shiftedRdrPass= mi->_ShiftedTriangleCache->RdrPass[rdrPassId];
1476 // Render with the Materials of the MeshInstance.
1477 drv->activeIndexBuffer(mi->_ShiftedTriangleCache->RawIndices);
1478 drv->renderTriangles(material, shiftedRdrPass.Triangles, shiftedRdrPass.NumTriangles);
1482 // ***************************************************************************
1483 void CMeshMRMGeom::updateShiftedTriangleCache(CMeshMRMInstance *mi, sint curLodId, uint baseVertex)
1485 // if the instance has a cache, but not sync to us, delete it.
1486 if( mi->_ShiftedTriangleCache && (
1487 mi->_ShiftedTriangleCache->MeshDataId != _MeshDataId ||
1488 mi->_ShiftedTriangleCache->LodId != curLodId ||
1489 mi->_ShiftedTriangleCache->BaseVertex != baseVertex) )
1491 mi->clearShiftedTriangleCache();
1494 // If the instance has not a valid cache, must create it.
1495 if( !mi->_ShiftedTriangleCache )
1497 mi->_ShiftedTriangleCache= new CShiftedTriangleCache;
1498 // Fill the cache Key.
1499 mi->_ShiftedTriangleCache->MeshDataId= _MeshDataId;
1500 mi->_ShiftedTriangleCache->LodId= curLodId;
1501 mi->_ShiftedTriangleCache->BaseVertex= baseVertex;
1503 // Build list of PBlock. From Lod, or from RawSkin cache.
1504 static vector<CIndexBuffer*> pbList;
1505 pbList.clear();
1506 if(mi->_RawSkinCache)
1508 pbList.resize(mi->_RawSkinCache->RdrPass.size());
1509 for(uint i=0;i<pbList.size();i++)
1511 pbList[i]= &mi->_RawSkinCache->RdrPass[i];
1514 else
1516 CLod &lod= _Lods[curLodId];
1517 pbList.resize(lod.RdrPass.size());
1518 for(uint i=0;i<pbList.size();i++)
1520 pbList[i]= &lod.RdrPass[i].PBlock;
1524 // Build RdrPass
1525 mi->_ShiftedTriangleCache->RdrPass.resize((uint32)pbList.size());
1527 // First pass, count number of triangles, and fill header info
1528 uint totalTri= 0;
1529 uint i;
1530 for(i=0;i<pbList.size();i++)
1532 mi->_ShiftedTriangleCache->RdrPass[i].NumTriangles= pbList[i]->getNumIndexes()/3;
1533 totalTri+= pbList[i]->getNumIndexes()/3;
1536 // Allocate triangles indices.
1537 mi->_ShiftedTriangleCache->RawIndices.setFormat(NL_MESH_MRM_INDEX_FORMAT);
1538 mi->_ShiftedTriangleCache->RawIndices.setNumIndexes(totalTri*3);
1540 // Lock the index buffer
1541 CIndexBufferReadWrite ibaWrite;
1542 mi->_ShiftedTriangleCache->RawIndices.lock (ibaWrite);
1543 if (ibaWrite.getFormat() == CIndexBuffer::Indices32)
1545 uint32 *dstPtr = (uint32 *) ibaWrite.getPtr();
1546 // Second pass, fill ptrs, and fill Arrays
1547 uint indexTri= 0;
1548 for(i=0;i<pbList.size();i++)
1550 CShiftedTriangleCache::CRdrPass &dstRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
1551 dstRdrPass.Triangles= indexTri*3;
1553 // Fill the array
1554 uint numTris= pbList[i]->getNumIndexes()/3;
1555 if(numTris)
1557 uint nIds= numTris*3;
1558 // index, and fill
1559 CIndexBufferRead ibaRead;
1560 pbList[i]->lock (ibaRead);
1561 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
1562 const uint32 *pSrcTri= (const uint32 *) ibaRead.getPtr();
1563 uint32 *pDstTri= dstPtr+dstRdrPass.Triangles;
1564 for(;nIds>0;nIds--,pSrcTri++,pDstTri++)
1565 *pDstTri= *pSrcTri + baseVertex;
1568 // Next
1569 indexTri+= dstRdrPass.NumTriangles;
1572 else
1574 nlassert(ibaWrite.getFormat() == CIndexBuffer::Indices16);
1575 uint16 *dstPtr = (uint16 *) ibaWrite.getPtr();
1576 // Second pass, fill ptrs, and fill Arrays
1577 uint indexTri= 0;
1578 for(i=0;i<pbList.size();i++)
1580 CShiftedTriangleCache::CRdrPass &dstRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
1581 dstRdrPass.Triangles= indexTri*3;
1583 // Fill the array
1584 uint numTris= pbList[i]->getNumIndexes()/3;
1585 if(numTris)
1587 uint nIds= numTris*3;
1588 // index, and fill
1589 CIndexBufferRead ibaRead;
1590 pbList[i]->lock (ibaRead);
1591 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
1592 const uint16 *pSrcTri= (const uint16 *) ibaRead.getPtr();
1593 uint16 *pDstTri= (uint16 *) dstPtr+dstRdrPass.Triangles;
1594 for(;nIds>0;nIds--,pSrcTri++,pDstTri++)
1595 *pDstTri= *pSrcTri + baseVertex;
1598 // Next
1599 indexTri+= dstRdrPass.NumTriangles;
1606 // ***************************************************************************
1607 void CMeshMRMGeom::serial(NLMISC::IStream &f)
1609 // because of complexity, serial is separated in save / load.
1611 if(f.isReading())
1612 load(f);
1613 else
1614 save(f);
1620 // ***************************************************************************
1621 sint CMeshMRMGeom::loadHeader(NLMISC::IStream &f)
1624 Version 5:
1625 - Shadow Skinning
1626 Version 4:
1627 - serial SkinWeights per MRM, not per Lod
1628 Version 3:
1629 - Bones names.
1630 Version 2:
1631 - Mesh Vertex Program.
1632 Version 1:
1633 - added blend shapes
1634 Version 0:
1635 - base version.
1637 sint ver= f.serialVersion(5);
1640 // if >= version 3, serial boens names
1641 if(ver>=3)
1643 f.serialCont (_BonesName);
1646 // Version3-: Bones index are in skeleton model id list
1647 _BoneIdComputed = (ver < 3);
1648 // Must always recompute usage of parents of bones used.
1649 _BoneIdExtended = false;
1651 // Mesh Vertex Program.
1652 if (ver >= 2)
1654 IMeshVertexProgram *mvp= NULL;
1655 f.serialPolyPtr(mvp);
1656 _MeshVertexProgram= mvp;
1658 else
1660 // release vp
1661 _MeshVertexProgram= NULL;
1664 // blend shapes
1665 if (ver >= 1)
1666 f.serial (_MeshMorpher);
1668 // serial Basic info.
1669 // ==================
1670 f.serial(_Skinned);
1671 f.serial(_BBox);
1672 f.serial(_LevelDetail.MaxFaceUsed);
1673 f.serial(_LevelDetail.MinFaceUsed);
1674 f.serial(_LevelDetail.DistanceFinest);
1675 f.serial(_LevelDetail.DistanceMiddle);
1676 f.serial(_LevelDetail.DistanceCoarsest);
1677 f.serial(_LevelDetail.OODistanceDelta);
1678 f.serial(_LevelDetail.DistancePow);
1679 // preload the Lods.
1680 f.serialCont(_LodInfos);
1682 // read/save number of wedges.
1683 /* NB: prepare memory space too for vertices.
1684 \todo yoyo: TODO_OPTIMIZE. for now there is no Lod memory profit with vertices / skinWeights.
1685 But resizing arrays is a problem because of reallocation...
1687 uint32 nWedges;
1688 f.serial(nWedges);
1689 // Prepare the VBuffer.
1690 _VBufferFinal.serialHeader(f);
1691 // If skinned, must allocate skinWeights.
1692 contReset(_SkinWeights);
1693 if(_Skinned)
1695 _SkinWeights.resize(nWedges);
1699 // If new version, serial SkinWeights in header, not in lods.
1700 if(ver >= 4)
1702 f.serialCont(_SkinWeights);
1706 // if >= version 5, serial Shadow Skin Information
1707 if(ver>=5)
1709 f.serialCont (_ShadowSkin.Vertices);
1710 f.serialCont (_ShadowSkin.Triangles);
1714 // Serial lod offsets.
1715 // ==================
1716 // This is the reference pos, to load / save relative offsets.
1717 sint32 startPos = f.getPos();
1718 // Those are the lodOffsets, relative to startPos.
1719 vector<sint32> lodOffsets;
1720 lodOffsets.resize(_LodInfos.size(), 0);
1722 // read all relative offsets, and build the absolute offset of LodInfos.
1723 for(uint i=0;i<_LodInfos.size(); i++)
1725 f.serial(lodOffsets[i]);
1726 _LodInfos[i].LodOffset= startPos + lodOffsets[i];
1730 // resest the Lod arrays. NB: each Lod is empty, and ready to receive Lod data.
1731 // ==================
1732 contReset(_Lods);
1733 _Lods.resize(_LodInfos.size());
1735 // Flag the fact that no lod is loaded for now.
1736 _NbLodLoaded= 0;
1738 // Inform that the mesh data has changed
1739 dirtMeshDataId();
1742 // Some runtime not serialized compilation
1743 compileRunTime();
1745 // return version of the header
1746 return ver;
1750 // ***************************************************************************
1751 void CMeshMRMGeom::load(NLMISC::IStream &f)
1753 // Load the header of the stream.
1754 // ==================
1755 sint verHeader= loadHeader(f);
1757 // Read All lod subsets.
1758 // ==================
1759 for(uint i=0;i<_LodInfos.size(); i++)
1761 // read the lod face data.
1762 f.serial(_Lods[i]);
1763 // read the lod vertex data.
1764 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
1765 // if reading, must bkup all original vertices from VB.
1766 // this is done in serialLodVertexData(). by subset
1769 // Now, all lods are loaded.
1770 _NbLodLoaded= (uint)_Lods.size();
1772 // If version doen't have boneNames, must build BoneId now.
1773 if(verHeader <= 2)
1775 buildBoneUsageVer2 ();
1780 // ***************************************************************************
1781 void CMeshMRMGeom::save(NLMISC::IStream &f)
1784 Version 5:
1785 - Shadow Skinning
1786 Version 4:
1787 - serial SkinWeights per MRM, not per Lod
1788 Version 3:
1789 - Bones names.
1790 Version 2:
1791 - Mesh Vertex Program.
1792 Version 1:
1793 - added blend shapes
1794 Version 0:
1795 - base version.
1797 sint ver= f.serialVersion(5);
1798 uint i;
1800 // if >= version 3, serial bones names
1801 f.serialCont (_BonesName);
1803 // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed!
1804 nlassert (_BoneIdComputed==false);
1806 // Mesh Vertex Program.
1807 if (ver >= 2)
1809 IMeshVertexProgram *mvp= NULL;
1810 mvp= _MeshVertexProgram;
1811 f.serialPolyPtr(mvp);
1814 // blend shapes
1815 if (ver >= 1)
1816 f.serial (_MeshMorpher);
1818 // must have good original Skinned Vertex before writing.
1819 if( _Skinned )
1821 restoreOriginalSkinVertices();
1825 // serial Basic info.
1826 // ==================
1827 f.serial(_Skinned);
1828 f.serial(_BBox);
1829 f.serial(_LevelDetail.MaxFaceUsed);
1830 f.serial(_LevelDetail.MinFaceUsed);
1831 f.serial(_LevelDetail.DistanceFinest);
1832 f.serial(_LevelDetail.DistanceMiddle);
1833 f.serial(_LevelDetail.DistanceCoarsest);
1834 f.serial(_LevelDetail.OODistanceDelta);
1835 f.serial(_LevelDetail.DistancePow);
1836 f.serialCont(_LodInfos);
1838 // save number of wedges.
1839 uint32 nWedges;
1840 nWedges= _VBufferFinal.getNumVertices();
1841 f.serial(nWedges);
1842 // Save the VBuffer header.
1843 _VBufferFinal.serialHeader(f);
1846 // If new version, serial SkinWeights in header, not in lods.
1847 if(ver >= 4)
1849 f.serialCont(_SkinWeights);
1852 // if >= version 5, serial Shadow Skin Information
1853 if(ver>=5)
1855 f.serialCont (_ShadowSkin.Vertices);
1856 f.serialCont (_ShadowSkin.Triangles);
1859 // Serial lod offsets.
1860 // ==================
1861 // This is the reference pos, to load / save relative offsets.
1862 sint32 startPos = f.getPos();
1863 // Those are the lodOffsets, relative to startPos.
1864 vector<sint32> lodOffsets;
1865 lodOffsets.resize(_LodInfos.size(), 0);
1867 // write all dummy offset. For now (since we don't know what to set), compute the offset of
1868 // the sint32 to come back in serial lod parts below.
1869 for(i=0;i<_LodInfos.size(); i++)
1871 lodOffsets[i]= f.getPos();
1872 f.serial(lodOffsets[i]);
1875 // Serial lod subsets.
1876 // ==================
1878 // Save all the lods.
1879 for(i=0;i<_LodInfos.size(); i++)
1881 // get current absolute position.
1882 sint32 absCurPos= f.getPos();
1884 // come back to "relative lodOffset" absolute position in the stream. (temp stored in lodOffset[i]).
1885 f.seek(lodOffsets[i], NLMISC::IStream::begin);
1887 // write the relative position of the lod to the stream.
1888 sint32 relCurPos= absCurPos - startPos;
1889 f.serial(relCurPos);
1891 // come back to absCurPos, to save the lod.
1892 f.seek(absCurPos, NLMISC::IStream::begin);
1894 // And so now, save the lod.
1895 // write the lod face data.
1896 f.serial(_Lods[i]);
1897 // write the lod vertex data.
1898 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
1906 // ***************************************************************************
1907 void CMeshMRMGeom::serialLodVertexData(NLMISC::IStream &f, uint startWedge, uint endWedge)
1910 Version 1:
1911 - serial SkinWeights per MRM, not per Lod
1913 sint ver= f.serialVersion(1);
1915 // VBuffer part.
1916 _VBufferFinal.serialSubset(f, startWedge, endWedge);
1918 // SkinWeights.
1919 if(_Skinned)
1921 // Serialize SkinWeight per lod only for old versions.
1922 if(ver<1)
1924 for(uint i= startWedge; i<endWedge; i++)
1926 f.serial(_SkinWeights[i]);
1929 // if reading, must copy original vertices from VB.
1930 if( f.isReading())
1932 bkupOriginalSkinVerticesSubset(startWedge, endWedge);
1939 // ***************************************************************************
1940 void CMeshMRMGeom::loadFirstLod(NLMISC::IStream &f)
1942 // Load the header of the stream.
1943 // ==================
1944 sint verHeader= loadHeader(f);
1947 // If empty MRM, quit.
1948 if(_LodInfos.empty())
1949 return;
1951 /* If the version is <4, then SkinWeights are serialised per Lod.
1952 But for computebonesId(), we must have all SkinWeights RIGHT NOW.
1953 Hence, if too old version (<4), serialize all the MRM....
1955 uint numLodToLoad;
1956 if(verHeader<4)
1957 numLodToLoad= (uint)_LodInfos.size();
1958 else
1959 numLodToLoad= 1;
1962 // Read lod subset(s).
1963 // ==================
1964 for(uint i=0;i<numLodToLoad; i++)
1966 // read the lod face data.
1967 f.serial(_Lods[i]);
1968 // read the lod vertex data.
1969 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
1970 // if reading, must bkup all original vertices from VB.
1971 // this is done in serialLodVertexData(). by subset
1974 // Now, just first lod is loaded (but if too old file)
1975 _NbLodLoaded= numLodToLoad;
1977 // If version doen't have boneNames, must build BoneId now.
1978 if(verHeader <= 2)
1980 buildBoneUsageVer2 ();
1985 // ***************************************************************************
1986 void CMeshMRMGeom::loadNextLod(NLMISC::IStream &f)
1988 // If all is loaded, quit.
1989 if(getNbLodLoaded() == getNbLod())
1990 return;
1992 // Set pos to good lod.
1993 f.seek(_LodInfos[_NbLodLoaded].LodOffset, NLMISC::IStream::begin);
1995 // Serial this lod data.
1996 // read the lod face data.
1997 f.serial(_Lods[_NbLodLoaded]);
1998 // read the lod vertex data.
1999 serialLodVertexData(f, _LodInfos[_NbLodLoaded].StartAddWedge, _LodInfos[_NbLodLoaded].EndAddWedges);
2000 // if reading, must bkup all original vertices from VB.
2001 // this is done in serialLodVertexData(). by subset
2004 // Inc LodLoaded count.
2005 _NbLodLoaded++;
2009 // ***************************************************************************
2010 void CMeshMRMGeom::unloadNextLod(NLMISC::IStream &f)
2012 // If just first lod remain (or no lod), quit
2013 if(getNbLodLoaded() <= 1)
2014 return;
2016 // Reset the entire Lod object. (Free Memory).
2017 contReset(_Lods[_NbLodLoaded-1]);
2020 // Dec LodLoaded count.
2021 _NbLodLoaded--;
2025 // ***************************************************************************
2026 void CMeshMRMGeom::bkupOriginalSkinVertices()
2028 nlassert(_Skinned);
2030 // bkup the entire array.
2031 bkupOriginalSkinVerticesSubset(0, _VBufferFinal.getNumVertices());
2035 // ***************************************************************************
2036 void CMeshMRMGeom::bkupOriginalSkinVerticesSubset(uint wedgeStart, uint wedgeEnd)
2038 nlassert(_Skinned);
2040 CVertexBufferReadWrite vba;
2041 _VBufferFinal.lock (vba);
2043 // Copy VBuffer content into Original vertices normals.
2044 if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
2046 // copy vertices from VBuffer. (NB: useless geomorphed vertices are still copied, but doesn't matter).
2047 _OriginalSkinVertices.resize(_VBufferFinal.getNumVertices());
2048 for(uint i=wedgeStart; i<wedgeEnd;i++)
2050 _OriginalSkinVertices[i]= *vba.getVertexCoordPointer(i);
2053 if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
2055 // copy normals from VBuffer. (NB: useless geomorphed normals are still copied, but doesn't matter).
2056 _OriginalSkinNormals.resize(_VBufferFinal.getNumVertices());
2057 for(uint i=wedgeStart; i<wedgeEnd;i++)
2059 _OriginalSkinNormals[i]= *vba.getNormalCoordPointer(i);
2063 // is there tangent space added ?
2064 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
2066 // yes, backup it
2067 nlassert(_VBufferFinal.getNumTexCoordUsed() > 0);
2068 uint tgSpaceStage = _VBufferFinal.getNumTexCoordUsed() - 1;
2069 _OriginalTGSpace.resize(_VBufferFinal.getNumVertices());
2070 for(uint i=wedgeStart; i<wedgeEnd;i++)
2072 _OriginalTGSpace[i]= *(CVector*)vba.getTexCoordPointer(i, tgSpaceStage);
2078 // ***************************************************************************
2079 void CMeshMRMGeom::restoreOriginalSkinVertices()
2081 nlassert(_Skinned);
2083 CVertexBufferReadWrite vba;
2084 _VBufferFinal.lock (vba);
2086 // Copy VBuffer content into Original vertices normals.
2087 if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
2089 // copy vertices from VBuffer. (NB: useless geomorphed vertices are still copied, but doesn't matter).
2090 for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
2092 *vba.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
2095 if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
2097 // copy normals from VBuffer. (NB: useless geomorphed normals are still copied, but doesn't matter).
2098 for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
2100 *vba.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
2103 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
2105 uint numTexCoords = _VBufferFinal.getNumTexCoordUsed();
2106 nlassert(numTexCoords >= 2);
2107 nlassert(_OriginalTGSpace.size() == _VBufferFinal.getNumVertices());
2108 // copy tangent space vectors
2109 for(uint i = 0; i < _VBufferFinal.getNumVertices(); ++i)
2111 *(CVector*)vba.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
2117 // ***************************************************************************
2118 void CMeshMRMGeom::restoreOriginalSkinPart(CLod &lod)
2120 nlassert(_Skinned);
2124 YOYO: _Skinned mrms no more support vertexBufferHard
2125 see note in renderSkin()
2128 // get vertexPtr / normalOff.
2129 //===========================
2130 CVertexBufferReadWrite vba;
2131 _VBufferFinal.lock (vba);
2132 uint8 *destVertexPtr= (uint8*)vba.getVertexCoordPointer();
2133 uint flags= _VBufferFinal.getVertexFormat();
2134 sint32 vertexSize= _VBufferFinal.getVertexSize();
2135 // must have XYZ.
2136 nlassert(flags & CVertexBuffer::PositionFlag);
2138 // Compute offset of each component of the VB.
2139 sint32 normalOff;
2140 if(flags & CVertexBuffer::NormalFlag)
2141 normalOff= _VBufferFinal.getNormalOff();
2142 else
2143 normalOff= 0;
2146 // compute src array.
2147 CVector *srcVertexPtr;
2148 CVector *srcNormalPtr= NULL;
2149 srcVertexPtr= &_OriginalSkinVertices[0];
2150 if(normalOff)
2151 srcNormalPtr= &(_OriginalSkinNormals[0]);
2154 // copy skinning.
2155 //===========================
2156 for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
2158 uint nInf= (uint)lod.InfluencedVertices[i].size();
2159 if( nInf==0 )
2160 continue;
2161 uint32 *infPtr= &(lod.InfluencedVertices[i][0]);
2163 // for all InfluencedVertices only.
2164 for(;nInf>0;nInf--, infPtr++)
2166 uint index= *infPtr;
2167 CVector *srcVertex= srcVertexPtr + index;
2168 CVector *srcNormal= srcNormalPtr + index;
2169 uint8 *dstVertexVB= destVertexPtr + index * vertexSize;
2170 CVector *dstVertex= (CVector*)(dstVertexVB);
2171 CVector *dstNormal= (CVector*)(dstVertexVB + normalOff);
2174 // Vertex.
2175 *dstVertex= *srcVertex;
2176 // Normal.
2177 if(normalOff)
2178 *dstNormal= *srcNormal;
2183 // clean this lod part. (NB: this is not optimal, but sufficient :) ).
2184 lod.OriginalSkinRestored= true;
2187 // ***************************************************************************
2189 float CMeshMRMGeom::getNumTriangles (float distance)
2191 // NB: this is an approximation, but this is continious.
2192 return _LevelDetail.getNumTriangles(distance);
2197 // ***************************************************************************
2198 void CMeshMRMGeom::computeBonesId (CSkeletonModel *skeleton)
2200 // Already computed ?
2201 if (!_BoneIdComputed)
2203 // Get a pointer on the skeleton
2204 nlassert (skeleton);
2205 if (skeleton)
2207 // **** For each bones, compute remap
2208 std::vector<uint> remap;
2209 skeleton->remapSkinBones(_BonesName, _BonesId, remap);
2212 // **** Remap the vertices, and compute Bone Spheres.
2214 // Find the Geomorph space: to process only real vertices, not geomorphed ones.
2215 uint nGeomSpace= 0;
2216 uint lod;
2217 for (lod=0; lod<_Lods.size(); lod++)
2219 nGeomSpace= max(nGeomSpace, (uint)_Lods[lod].Geomorphs.size());
2222 // Prepare Sphere compute
2223 nlassert(_OriginalSkinVertices.size() == _SkinWeights.size());
2224 static std::vector<CAABBox> boneBBoxes;
2225 static std::vector<bool> boneBBEmpty;
2226 boneBBoxes.clear();
2227 boneBBEmpty.clear();
2228 boneBBoxes.resize(_BonesId.size());
2229 boneBBEmpty.resize(_BonesId.size(), true);
2231 // Remap the vertex, and compute the bone spheres. see CTransform::getSkinBoneSphere() doc.
2232 // for true vertices
2233 uint vert;
2234 for (vert=nGeomSpace; vert<_SkinWeights.size(); vert++)
2236 // get the vertex position.
2237 CVector vertex= _OriginalSkinVertices[vert];
2239 // For each weight
2240 uint weight;
2241 for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
2243 // Active ?
2244 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
2246 // Check id
2247 uint srcId= _SkinWeights[vert].MatrixId[weight];
2248 nlassert (srcId < remap.size());
2249 // remap
2250 _SkinWeights[vert].MatrixId[weight] = remap[srcId];
2252 // if the boneId is valid (ie found)
2253 if(_BonesId[srcId]>=0)
2255 // transform the vertex pos in BoneSpace
2256 CVector p= skeleton->Bones[_BonesId[srcId]].getBoneBase().InvBindPos * vertex;
2257 // extend the bone bbox.
2258 if(boneBBEmpty[srcId])
2260 boneBBoxes[srcId].setCenter(p);
2261 boneBBEmpty[srcId]= false;
2263 else
2265 boneBBoxes[srcId].extend(p);
2269 else
2270 break;
2274 // Compile spheres
2275 _BonesSphere.resize(_BonesId.size());
2276 for(uint bone=0;bone<_BonesSphere.size();bone++)
2278 // If the bone is empty, mark with -1 in the radius.
2279 if(boneBBEmpty[bone])
2281 _BonesSphere[bone].Radius= -1;
2283 else
2285 _BonesSphere[bone].Center= boneBBoxes[bone].getCenter();
2286 _BonesSphere[bone].Radius= boneBBoxes[bone].getRadius();
2290 // **** Remap the vertex influence by lods
2291 for (lod=0; lod<_Lods.size(); lod++)
2293 // For each matrix used
2294 uint matrix;
2295 for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
2297 // Check
2298 nlassert (_Lods[lod].MatrixInfluences[matrix]<remap.size());
2300 // Remap
2301 _Lods[lod].MatrixInfluences[matrix] = remap[_Lods[lod].MatrixInfluences[matrix]];
2305 // **** Remap Shadow Vertices.
2306 for(vert=0;vert<_ShadowSkin.Vertices.size();vert++)
2308 CShadowVertex &v= _ShadowSkin.Vertices[vert];
2309 // Check id
2310 nlassert (v.MatrixId < remap.size());
2311 v.MatrixId= remap[v.MatrixId];
2314 // Computed
2315 _BoneIdComputed = true;
2319 // Already extended ?
2320 if (!_BoneIdExtended)
2322 nlassert (skeleton);
2323 if (skeleton)
2325 // the total bone Usage of the mesh.
2326 vector<bool> boneUsage;
2327 boneUsage.resize(skeleton->Bones.size(), false);
2329 // for all Bones marked as valid.
2330 uint i;
2331 for(i=0; i<_BonesId.size(); i++)
2333 // if not a valid boneId, skip it.
2334 if(_BonesId[i]<0)
2335 continue;
2337 // mark him and his father in boneUsage.
2338 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
2341 // fill _BonesIdExt with bones of _BonesId and their parents.
2342 _BonesIdExt.clear();
2343 for(i=0; i<boneUsage.size();i++)
2345 // if the bone is used by the mesh, add it to BoneIdExt.
2346 if(boneUsage[i])
2347 _BonesIdExt.push_back(i);
2352 // Extended
2353 _BoneIdExtended= true;
2359 // ***************************************************************************
2360 void CMeshMRMGeom::buildBoneUsageVer2 ()
2362 if(_Skinned)
2364 // parse all vertices, couting MaxBoneId used.
2365 uint32 maxBoneId= 0;
2366 // for each vertex
2367 uint vert;
2368 for (vert=0; vert<_SkinWeights.size(); vert++)
2370 // For each weight
2371 for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
2373 // Active ?
2374 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
2376 maxBoneId= max(_SkinWeights[vert].MatrixId[weight], maxBoneId);
2381 // alloc an array of maxBoneId+1, reset to 0.
2382 std::vector<uint8> boneUsage;
2383 boneUsage.resize(maxBoneId+1, 0);
2385 // reparse all vertices, counting usage for each bone.
2386 for (vert=0; vert<_SkinWeights.size(); vert++)
2388 // For each weight
2389 for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
2391 // Active ?
2392 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
2394 // mark this bone as used.
2395 boneUsage[_SkinWeights[vert].MatrixId[weight]]= 1;
2400 // For each bone used
2401 _BonesId.clear();
2402 for(uint i=0; i<boneUsage.size();i++)
2404 // if the bone is used by the mesh, add it to BoneId.
2405 if(boneUsage[i])
2406 _BonesId.push_back(i);
2412 // ***************************************************************************
2413 void CMeshMRMGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
2415 // For all Bones used.
2416 for(uint i=0; i<_BonesIdExt.size();i++)
2418 uint boneId= _BonesIdExt[i];
2419 // Some explicit Error.
2420 if(boneId>=sm->Bones.size())
2421 nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
2422 // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
2423 if(increment)
2424 sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
2425 else
2426 sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
2431 // ***************************************************************************
2432 void CMeshMRMGeom::compileRunTime()
2434 _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
2436 // Compute if can support SkinGrouping rendering
2437 if(_Lods.empty() || !_Skinned)
2439 _SupportSkinGrouping= false;
2440 _SupportShadowSkinGrouping= false;
2442 else
2444 // The Mesh must follow those restrictions, to support group skinning
2445 _SupportSkinGrouping=
2446 _VBufferFinal.getVertexFormat() == NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT &&
2447 _VBufferFinal.getNumVertices() < NL3D_MESH_SKIN_MANAGER_MAXVERTICES &&
2448 !_MeshVertexProgram;
2450 // Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
2451 _SupportShadowSkinGrouping= !_ShadowSkin.Vertices.empty() &&
2452 NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT==CVertexBuffer::PositionFlag &&
2453 _ShadowSkin.Vertices.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES;
2456 // Support MeshBlockRendering only if not skinned/meshMorphed.
2457 _SupportMeshBlockRendering= !_Skinned && _MeshMorpher.BlendShapes.empty();
2459 // \todo yoyo: support later MeshVertexProgram
2460 _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MeshVertexProgram==NULL;
2464 // ***************************************************************************
2465 void CMeshMRMGeom::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags)
2467 // if no _Lods, no draw
2468 if(_Lods.empty())
2469 return;
2471 // get the result of the Load Balancing.
2472 float alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
2474 // choose the lod.
2475 float alphaLod;
2476 sint numLod= chooseLod(alphaMRM, alphaLod);
2478 // Render the choosen Lod.
2479 CLod &lod= _Lods[numLod];
2481 // get the mesh instance.
2482 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
2484 // Profile all pass.
2485 uint triCount= 0;
2486 for (uint i=0;i<lod.RdrPass.size();i++)
2488 CRdrPass &rdrPass= lod.RdrPass[i];
2489 // Profile with the Materials of the MeshInstance.
2490 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
2491 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
2493 triCount+= rdrPass.PBlock.getNumIndexes()/3;
2497 // Profile
2498 if(triCount)
2500 // tri per VBFormat
2501 rdrTrav->Scene->incrementProfileTriVBFormat(rdrTrav->Scene->BenchRes.MeshMRMProfileTriVBFormat,
2502 _VBufferFinal.getVertexFormat(), triCount);
2504 // VBHard
2505 if(_VBufferFinal.getPreferredMemory()!=CVertexBuffer::RAMPreferred)
2506 rdrTrav->Scene->BenchRes.NumMeshMRMVBufferHard++;
2507 else
2508 rdrTrav->Scene->BenchRes.NumMeshMRMVBufferStd++;
2510 // rendered in BlockRendering, only if not transparent pass (known it if RenderTransparentMaterial is set)
2511 if(supportMeshBlockRendering() && (rdrFlags & IMeshGeom::RenderTransparentMaterial)==0 )
2513 if(isMeshInVBHeap())
2515 rdrTrav->Scene->BenchRes.NumMeshMRMRdrBlockWithVBHeap++;
2516 rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrBlockWithVBHeap+= triCount;
2518 else
2520 rdrTrav->Scene->BenchRes.NumMeshMRMRdrBlock++;
2521 rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrBlock+= triCount;
2524 else
2526 rdrTrav->Scene->BenchRes.NumMeshMRMRdrNormal++;
2527 rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrNormal+= triCount;
2533 // ***************************************************************************
2534 bool CMeshMRMGeom::buildGeometryForLod(uint lodId, std::vector<CVector> &vertices, std::vector<uint32> &triangles) const
2536 if(lodId>=_Lods.size())
2537 return false;
2539 // avoid slow lock
2540 if(_VBufferFinal.isResident())
2541 return false;
2543 // clear first
2544 vertices.clear();
2545 triangles.clear();
2548 // **** First, for the lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
2549 static vector<sint> vertexRemap;
2550 vertexRemap.clear();
2551 // -1 means "not used"
2552 vertexRemap.resize(_VBufferFinal.getNumVertices(), -1);
2553 // count also total number of indices
2554 uint numTotalIndices= 0;
2555 // Parse all triangles.
2556 uint i;
2557 for(i=0;i<getNbRdrPass(lodId);i++)
2559 const CIndexBuffer &pb = getRdrPassPrimitiveBlock(lodId, i);
2560 // avoid slow lock
2561 if(pb.isResident())
2562 return false;
2563 CIndexBufferRead iba;
2564 pb.lock (iba);
2565 nlassert(iba.getFormat()==NL_MESH_MRM_INDEX_FORMAT);
2566 TMeshMRMIndexType *src= (TMeshMRMIndexType *) iba.getPtr();
2567 for(uint n= pb.getNumIndexes();n>0;n--, src++)
2569 uint idx= *src;
2570 // Flag the vertex with its own index => used.
2571 vertexRemap[idx]= idx;
2574 // total num indices
2575 numTotalIndices+= pb.getNumIndexes();
2577 // Special for Geomorphs: must take The End target vertex.
2578 const std::vector<CMRMWedgeGeom> &geomorphs= getGeomorphs(lodId);
2579 for(i=0;i<geomorphs.size();i++)
2581 uint trueIdx= geomorphs[i].End;
2582 // map to the Geomorph Target.
2583 vertexRemap[i]= trueIdx;
2584 // mark also the real vertex used as used.
2585 vertexRemap[trueIdx]= trueIdx;
2587 // if no index, abort
2588 if(numTotalIndices==0)
2589 return false;
2592 // **** count number of vertices really used (skip geomorphs)
2593 uint numUsedVertices=0;
2594 for(i=(uint)geomorphs.size();i<vertexRemap.size();i++)
2596 if(vertexRemap[i]>=0)
2597 numUsedVertices++;
2599 // if none, abort
2600 if(numUsedVertices==0)
2601 return false;
2602 // Then we have our vertices size
2603 vertices.resize(numUsedVertices);
2606 // **** Fill the vertex geometry
2608 // Lock input VB
2609 CVertexBufferRead vba;
2610 _VBufferFinal.lock(vba);
2612 // get the start vert, beginning at end of geomorphs
2613 const uint8 *pSrcVert= (const uint8*)vba.getVertexCoordPointer((uint)geomorphs.size());
2614 uint32 vertSize= _VBufferFinal.getVertexSize();
2615 CVector *pDstVert= &vertices[0];
2616 uint dstIndex= 0;
2618 // Then run all input vertices (skip geomorphs)
2619 for(i=(uint)geomorphs.size();i<vertexRemap.size();i++)
2621 // if the vertex is used
2622 if(vertexRemap[i]>=0)
2624 // Final remaping of vertex to final index
2625 vertexRemap[i]= dstIndex;
2626 // copy to dest
2627 *pDstVert= *(CVector*)pSrcVert;
2629 // next dest
2630 pDstVert++;
2631 dstIndex++;
2634 // next src
2635 pSrcVert+= vertSize;
2638 // should have fill the entire buffer
2639 nlassert(uint(pDstVert-(&vertices[0]))==numUsedVertices);
2641 // Resolve remapping for geomorphs
2642 for(i=0;i<geomorphs.size();i++)
2644 // use the same final index as the EndGeomorph vertex
2645 uint endGeomIdx= vertexRemap[i];
2646 vertexRemap[i]= vertexRemap[endGeomIdx];
2651 // **** Fill the indices
2652 triangles.resize(numTotalIndices);
2653 uint32 *pDstIndex= &triangles[0];
2654 // for all render pass
2655 for(i=0;i<getNbRdrPass(lodId);i++)
2657 const CIndexBuffer &pb = getRdrPassPrimitiveBlock(lodId, i);
2658 CIndexBufferRead iba;
2659 pb.lock (iba);
2660 TMeshMRMIndexType *src= (TMeshMRMIndexType *) iba.getPtr();
2661 for(uint n= pb.getNumIndexes();n>0;n--, src++)
2663 // resolve any geomorph, and final remapping
2664 uint remapedIdx= vertexRemap[*src];
2665 nlassert(remapedIdx<vertices.size());
2666 *pDstIndex= remapedIdx;
2667 pDstIndex++;
2670 // should have filled the entire buffer
2671 nlassert(uint(pDstIndex-(&triangles[0]))==numTotalIndices);
2674 return true;
2679 // ***************************************************************************
2680 // ***************************************************************************
2681 // Mesh Block Render Interface
2682 // ***************************************************************************
2683 // ***************************************************************************
2686 // ***************************************************************************
2687 bool CMeshMRMGeom::supportMeshBlockRendering () const
2690 Yoyo: Don't Support It for MRM because too Slow!!
2691 The problem is that lock() unlock() on each instance, on the same VBHeap IS AS SLOWER AS
2692 VB switching.
2694 TODO_OPTIMIZE: find a way to optimize MRM.
2696 return false;
2697 //return _SupportMeshBlockRendering;
2700 // ***************************************************************************
2701 bool CMeshMRMGeom::sortPerMaterial() const
2703 // Can't do it per material since 2 lods may not have the same number of RdrPass!!
2704 return false;
2706 // ***************************************************************************
2707 uint CMeshMRMGeom::getNumRdrPassesForMesh() const
2709 // not used...
2710 return 0;
2713 // ***************************************************************************
2714 uint CMeshMRMGeom::getNumRdrPassesForInstance(CMeshBaseInstance *inst) const
2716 return (uint)_Lods[_MBRCurrentLodId].RdrPass.size();
2718 // ***************************************************************************
2719 void CMeshMRMGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
2721 if(_Lods.empty())
2722 return;
2724 IDriver *drv= rdrCtx.Driver;
2726 if(rdrCtx.RenderThroughVBHeap)
2728 // Don't setup VB in this case, since use the VBHeap setuped one.
2730 else
2732 drv->activeVertexBuffer(_VBufferFinal);
2736 // force normalisation of normals..
2737 _MBRBkupNormalize= drv->isForceNormalize();
2738 drv->forceNormalize(true);
2741 // ***************************************************************************
2742 void CMeshMRMGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst)
2744 H_AUTO( NL3D_MeshMRMGeom_RenderNormal );
2746 if(_Lods.empty())
2747 return;
2749 // get the result of the Load Balancing.
2750 float alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
2752 // choose the lod.
2753 float alphaLod;
2754 _MBRCurrentLodId= chooseLod(alphaMRM, alphaLod);
2756 // Geomorph the choosen Lod (if not the coarser mesh).
2757 if(_MBRCurrentLodId>0)
2759 if(rdrCtx.RenderThroughVBHeap)
2760 applyGeomorphWithVBHardPtr(_Lods[_MBRCurrentLodId].Geomorphs, alphaLod, (uint8*)vbDst);
2761 else
2762 applyGeomorph(_Lods[_MBRCurrentLodId].Geomorphs, alphaLod);
2765 // set the instance worldmatrix.
2766 rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
2768 // setupLighting.
2769 inst->changeLightSetup(rdrCtx.RenderTrav);
2771 // ***************************************************************************
2772 void CMeshMRMGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
2774 if(_Lods.empty())
2775 return;
2777 CLod &lod= _Lods[_MBRCurrentLodId];
2778 CRdrPass &rdrPass= lod.RdrPass[rdrPassId];
2780 if ( mi->Materials[rdrPass.MaterialId].getBlend() == false )
2782 // CMaterial Ref
2783 CMaterial &material=mi->Materials[rdrPass.MaterialId];
2785 // Render with the Materials of the MeshInstance.
2786 if(rdrCtx.RenderThroughVBHeap)
2788 // render shifted primitives
2789 rdrCtx.Driver->activeIndexBuffer(rdrPass.VBHeapPBlock);
2790 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.VBHeapPBlock.getNumIndexes()/3);
2792 else
2794 rdrCtx.Driver->activeIndexBuffer(rdrPass.PBlock);
2795 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
2800 // ***************************************************************************
2801 void CMeshMRMGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
2803 if(_Lods.empty())
2804 return;
2806 // bkup force normalisation.
2807 rdrCtx.Driver->forceNormalize(_MBRBkupNormalize);
2811 // ***************************************************************************
2812 bool CMeshMRMGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
2814 // CMeshMRMGeom support VBHeap rendering, assuming _SupportMeshBlockRendering is true
2815 vertexFormat= _VBufferFinal.getVertexFormat();
2816 numVertices= _VBufferFinal.getNumVertices();
2817 return _SupportMeshBlockRendering;
2820 // ***************************************************************************
2821 void CMeshMRMGeom::computeMeshVBHeap(void *dst, uint indexStart)
2823 // Fill dst with Buffer content.
2824 CVertexBufferRead vba;
2825 _VBufferFinal.lock (vba);
2826 memcpy(dst, vba.getVertexCoordPointer(), _VBufferFinal.getNumVertices()*_VBufferFinal.getVertexSize() );
2828 // For All Lods
2829 for(uint lodId=0; lodId<_Lods.size();lodId++)
2831 CLod &lod= _Lods[lodId];
2833 // For all rdrPass.
2834 for(uint i=0;i<lod.RdrPass.size();i++)
2836 // shift the PB
2837 CIndexBuffer &srcPb= lod.RdrPass[i].PBlock;
2838 CIndexBuffer &dstPb= lod.RdrPass[i].VBHeapPBlock;
2839 uint j;
2841 // Tris.
2842 CIndexBufferRead ibaRead;
2843 srcPb.lock (ibaRead);
2844 CIndexBufferReadWrite ibaWrite;
2845 srcPb.lock (ibaWrite);
2846 dstPb.setNumIndexes(srcPb.getNumIndexes());
2847 // nico : apparently not used, so don't manage 16 bit index here
2848 nlassert(ibaRead.getIndexNumBytes() == sizeof(uint32));
2849 nlassert(ibaWrite.getIndexNumBytes() == sizeof(uint32));
2850 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32); // nico : apparently not called for now
2851 const uint32 *srcTriPtr= (const uint32 *) ibaRead.getPtr();
2852 uint32 *dstTriPtr= (uint32 *) ibaWrite.getPtr();
2853 for(j=0; j<dstPb.getNumIndexes();j++)
2855 dstTriPtr[j]= srcTriPtr[j]+indexStart;
2861 // ***************************************************************************
2862 bool CMeshMRMGeom::isActiveInstanceNeedVBFill() const
2864 // Yes, need it for geomorph
2865 return true;
2869 // ***************************************************************************
2870 // ***************************************************************************
2871 // CMeshMRM.
2872 // ***************************************************************************
2873 // ***************************************************************************
2877 // ***************************************************************************
2878 CMeshMRM::CMeshMRM()
2881 // ***************************************************************************
2882 void CMeshMRM::build (CMeshBase::CMeshBaseBuild &mBase, CMesh::CMeshBuild &m,
2883 std::vector<CMesh::CMeshBuild*> &listBS,
2884 const CMRMParameters &params)
2886 /// copy MeshBase info: materials ....
2887 CMeshBase::buildMeshBase (mBase);
2889 // Then build the geom.
2890 _MeshMRMGeom.build (m, listBS, (uint)mBase.Materials.size(), params);
2892 // ***************************************************************************
2893 void CMeshMRM::build (CMeshBase::CMeshBaseBuild &m, const CMeshMRMGeom &mgeom)
2895 /// copy MeshBase info: materials ....
2896 CMeshBase::buildMeshBase(m);
2898 // Then copy the geom.
2899 _MeshMRMGeom= mgeom;
2903 // ***************************************************************************
2904 void CMeshMRM::optimizeMaterialUsage(std::vector<sint> &remap)
2906 // For each material, count usage.
2907 vector<bool> materialUsed;
2908 materialUsed.resize(CMeshBase::_Materials.size(), false);
2909 for(uint lod=0;lod<getNbLod();lod++)
2911 for(uint rp=0;rp<getNbRdrPass(lod);rp++)
2913 uint matId= getRdrPassMaterial(lod, rp);
2914 // flag as used.
2915 materialUsed[matId]= true;
2919 // Apply it to meshBase
2920 CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
2922 // Apply lut to meshGeom.
2923 _MeshMRMGeom.applyMaterialRemap(remap);
2927 // ***************************************************************************
2928 CTransformShape *CMeshMRM::createInstance(CScene &scene)
2930 // Create a CMeshMRMInstance, an instance of a mesh.
2931 //===============================================
2932 CMeshMRMInstance *mi= (CMeshMRMInstance*)scene.createModel(NL3D::MeshMRMInstanceId);
2933 mi->Shape= this;
2935 // instanciate the material part of the MeshMRM, ie the CMeshBase.
2936 CMeshBase::instanciateMeshBase(mi, &scene);
2939 // do some instance init for MeshGeom
2940 _MeshMRMGeom.initInstance(mi);
2942 // init the FilterType
2943 mi->initRenderFilterType();
2945 return mi;
2949 // ***************************************************************************
2950 bool CMeshMRM::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
2952 return _MeshMRMGeom.clip(pyramid, worldMatrix);
2956 // ***************************************************************************
2957 void CMeshMRM::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
2959 // 0 or 0xFFFFFFFF
2960 uint32 mask= (0-(uint32)passOpaque);
2961 uint32 rdrFlags;
2962 // select rdrFlags, without ifs.
2963 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
2964 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
2965 // render the mesh
2966 _MeshMRMGeom.render(drv, trans, trans->getNumTrianglesAfterLoadBalancing(), rdrFlags, 1);
2970 // ***************************************************************************
2971 void CMeshMRM::serial(NLMISC::IStream &f)
2974 Version 0:
2975 - base version.
2977 (void)f.serialVersion(0);
2979 // serial Materials infos contained in CMeshBase.
2980 CMeshBase::serialMeshBase(f);
2983 // serial the geometry.
2984 _MeshMRMGeom.serial(f);
2988 // ***************************************************************************
2989 float CMeshMRM::getNumTriangles (float distance)
2991 return _MeshMRMGeom.getNumTriangles (distance);
2995 // ***************************************************************************
2996 const CMeshMRMGeom& CMeshMRM::getMeshGeom () const
2998 return _MeshMRMGeom;
3002 // ***************************************************************************
3003 void CMeshMRM::computeBonesId (CSkeletonModel *skeleton)
3005 _MeshMRMGeom.computeBonesId (skeleton);
3008 // ***************************************************************************
3009 void CMeshMRM::updateSkeletonUsage (CSkeletonModel *skeleton, bool increment)
3011 _MeshMRMGeom.updateSkeletonUsage(skeleton, increment);
3014 // ***************************************************************************
3015 void CMeshMRM::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
3017 _MeshMRMGeom.changeMRMDistanceSetup(distanceFinest, distanceMiddle, distanceCoarsest);
3020 // ***************************************************************************
3021 IMeshGeom *CMeshMRM::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
3023 // Ok if meshGeom is ok.
3024 if(_MeshMRMGeom.supportMeshBlockRendering())
3026 polygonCount= trans->getNumTrianglesAfterLoadBalancing();
3027 return (IMeshGeom*)&_MeshMRMGeom;
3029 else
3030 return NULL;
3033 // ***************************************************************************
3034 void CMeshMRM::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
3036 // 0 or 0xFFFFFFFF
3037 uint32 mask= (0-(uint32)passOpaque);
3038 uint32 rdrFlags;
3039 // select rdrFlags, without ifs.
3040 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
3041 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
3042 // profile the mesh
3043 _MeshMRMGeom.profileSceneRender(rdrTrav, trans, trans->getNumTrianglesAfterLoadBalancing(), rdrFlags);
3046 // ***************************************************************************
3047 void CMeshMRM::buildSystemGeometry()
3049 // clear any
3050 _SystemGeometry.clear();
3052 // don't build a system copy if skinned. In this case, ray intersection is done through CSkeletonModel
3053 // and intersectSkin() scheme
3054 if(_MeshMRMGeom.isSkinned())
3055 return;
3057 // Choose the best Lod available for system geometry
3058 if(_MeshMRMGeom.getNbLodLoaded()==0)
3059 return;
3060 uint lodId= _MeshMRMGeom.getNbLodLoaded()-1;
3062 // retrieve geometry (if VB/IB not resident)
3063 if( !_MeshMRMGeom.buildGeometryForLod(lodId, _SystemGeometry.Vertices, _SystemGeometry.Triangles) )
3065 _SystemGeometry.clear();
3068 // TestYoyo
3069 /*static uint32 totalMem= 0;
3070 totalMem+= _SystemGeometry.Vertices.size()*sizeof(CVector);
3071 totalMem+= _SystemGeometry.Triangles.size()*sizeof(uint32);
3072 nlinfo("CMeshMRM: TotalMem: %d", totalMem);*/
3076 // ***************************************************************************
3077 // ***************************************************************************
3078 // CMeshMRMGeom RawSkin optimisation
3079 // ***************************************************************************
3080 // ***************************************************************************
3083 // ***************************************************************************
3084 void CMeshMRMGeom::dirtMeshDataId()
3086 // see updateRawSkinNormal()
3087 _MeshDataId++;
3091 // ***************************************************************************
3092 void CMeshMRMGeom::updateRawSkinNormal(bool enabled, CMeshMRMInstance *mi, sint curLodId)
3094 if(!enabled)
3096 // if the instance cache is not cleared, must clear.
3097 if(mi->_RawSkinCache)
3098 mi->clearRawSkinCache();
3100 else
3102 // If the instance has no RawSkin, or has a too old RawSkin cache, must delete it, and recreate
3103 if( !mi->_RawSkinCache || mi->_RawSkinCache->MeshDataId!=_MeshDataId)
3105 // first delete if too old.
3106 if(mi->_RawSkinCache)
3107 mi->clearRawSkinCache();
3108 // Then recreate, and use _MeshDataId to verify that the instance works with same data.
3109 mi->_RawSkinCache= new CRawSkinNormalCache;
3110 mi->_RawSkinCache->MeshDataId= _MeshDataId;
3111 mi->_RawSkinCache->LodId= -1;
3115 /* If the instance rawSkin has a different Lod (or if -1), then must recreate it.
3116 NB: The lod may change each frame per instance, but suppose not so many change, so we can cache those data.
3118 if( mi->_RawSkinCache->LodId != curLodId )
3120 H_AUTO( NL3D_CMeshMRMGeom_updateRawSkinNormal );
3122 CVertexBufferRead vba;
3123 _VBufferFinal.lock (vba);
3125 CRawSkinNormalCache &skinLod= *mi->_RawSkinCache;
3126 CLod &lod= _Lods[curLodId];
3127 uint i;
3128 sint rawIdx;
3130 // Clear the raw skin mesh.
3131 skinLod.clearArrays();
3133 // Cache this lod
3134 mi->_RawSkinCache->LodId= curLodId;
3136 // For each matrix influence.
3137 nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
3139 // For each vertex, acknowledge if it is a src for geomorph.
3140 static vector<uint8> softVertices;
3141 softVertices.clear();
3142 softVertices.resize( _VBufferFinal.getNumVertices(), 0 );
3143 for(i=0;i<lod.Geomorphs.size();i++)
3145 softVertices[lod.Geomorphs[i].Start]= 1;
3146 softVertices[lod.Geomorphs[i].End]= 1;
3149 // The remap from old index in _VBufferFinal to RawSkin vertices (without Geomorphs).
3150 static vector<TMeshMRMIndexType> vertexRemap;
3151 vertexRemap.resize( _VBufferFinal.getNumVertices() );
3152 sint softSize[4];
3153 sint hardSize[4];
3154 sint softStart[4];
3155 sint hardStart[4];
3156 // count vertices
3157 skinLod.TotalSoftVertices= 0;
3158 skinLod.TotalHardVertices= 0;
3159 for(i=0;i<4;i++)
3161 softSize[i]= 0;
3162 hardSize[i]= 0;
3163 // Count.
3164 for(uint j=0;j<lod.InfluencedVertices[i].size();j++)
3166 uint vid= lod.InfluencedVertices[i][j];
3167 if(softVertices[vid])
3168 softSize[i]++;
3169 else
3170 hardSize[i]++;
3172 skinLod.TotalSoftVertices+= softSize[i];
3173 skinLod.TotalHardVertices+= hardSize[i];
3174 skinLod.SoftVertices[i]= softSize[i];
3175 skinLod.HardVertices[i]= hardSize[i];
3177 // compute offsets
3178 softStart[0]= 0;
3179 hardStart[0]= skinLod.TotalSoftVertices;
3180 for(i=1;i<4;i++)
3182 softStart[i]= softStart[i-1]+softSize[i-1];
3183 hardStart[i]= hardStart[i-1]+hardSize[i-1];
3185 // compute remap
3186 for(i=0;i<4;i++)
3188 uint softIdx= softStart[i];
3189 uint hardIdx= hardStart[i];
3190 for(uint j=0;j<lod.InfluencedVertices[i].size();j++)
3192 uint vid= lod.InfluencedVertices[i][j];
3193 if(softVertices[vid])
3194 vertexRemap[vid]= softIdx++;
3195 else
3196 vertexRemap[vid]= hardIdx++;
3201 // Resize the dest array.
3202 skinLod.Vertices1.resize((uint32)lod.InfluencedVertices[0].size());
3203 skinLod.Vertices2.resize((uint32)lod.InfluencedVertices[1].size());
3204 skinLod.Vertices3.resize((uint32)lod.InfluencedVertices[2].size());
3205 skinLod.Vertices4.resize((uint32)lod.InfluencedVertices[3].size());
3207 // Remap for BlendShape. Lasts 2 bits tells what RawSkin Array to seek (1 to 4),
3208 // low Bits indicate the number in them. 0xFFFFFFFF is a special value indicating "NotUsed in this lod"
3209 static vector<uint32> vertexFinalRemap;
3210 vertexFinalRemap.clear();
3211 vertexFinalRemap.resize(vertexRemap.size(), 0xFFFFFFFF);
3213 // 1 Matrix skinning.
3214 //========
3215 for(i=0;i<skinLod.Vertices1.size();i++)
3217 // get the dest vertex.
3218 uint vid= lod.InfluencedVertices[0][i];
3219 // where to store?
3220 rawIdx= vertexRemap[vid];
3221 if(softVertices[vid])
3222 rawIdx-= softStart[0];
3223 else
3224 rawIdx+= softSize[0]-hardStart[0];
3225 // for BlendShapes remapping
3226 vertexFinalRemap[vid]= (0<<30) + rawIdx;
3227 // fill raw struct
3228 skinLod.Vertices1[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
3229 skinLod.Vertices1[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
3230 skinLod.Vertices1[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
3231 skinLod.Vertices1[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
3234 // 2 Matrix skinning.
3235 //========
3236 for(i=0;i<skinLod.Vertices2.size();i++)
3238 // get the dest vertex.
3239 uint vid= lod.InfluencedVertices[1][i];
3240 // where to store?
3241 rawIdx= vertexRemap[vid];
3242 if(softVertices[vid])
3243 rawIdx-= softStart[1];
3244 else
3245 rawIdx+= softSize[1]-hardStart[1];
3246 // for BlendShapes remapping
3247 vertexFinalRemap[vid]= (1<<30) + rawIdx;
3248 // fill raw struct
3249 skinLod.Vertices2[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
3250 skinLod.Vertices2[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
3251 skinLod.Vertices2[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
3252 skinLod.Vertices2[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
3253 skinLod.Vertices2[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
3254 skinLod.Vertices2[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
3255 skinLod.Vertices2[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
3258 // 3 Matrix skinning.
3259 //========
3260 for(i=0;i<skinLod.Vertices3.size();i++)
3262 // get the dest vertex.
3263 uint vid= lod.InfluencedVertices[2][i];
3264 // where to store?
3265 rawIdx= vertexRemap[vid];
3266 if(softVertices[vid])
3267 rawIdx-= softStart[2];
3268 else
3269 rawIdx+= softSize[2]-hardStart[2];
3270 // for BlendShapes remapping
3271 vertexFinalRemap[vid]= (2<<30) + rawIdx;
3272 // fill raw struct
3273 skinLod.Vertices3[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
3274 skinLod.Vertices3[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
3275 skinLod.Vertices3[rawIdx].MatrixId[2]= _SkinWeights[vid].MatrixId[2];
3276 skinLod.Vertices3[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
3277 skinLod.Vertices3[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
3278 skinLod.Vertices3[rawIdx].Weights[2]= _SkinWeights[vid].Weights[2];
3279 skinLod.Vertices3[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
3280 skinLod.Vertices3[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
3281 skinLod.Vertices3[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
3284 // 4 Matrix skinning.
3285 //========
3286 for(i=0;i<skinLod.Vertices4.size();i++)
3288 // get the dest vertex.
3289 uint vid= lod.InfluencedVertices[3][i];
3290 // where to store?
3291 rawIdx= vertexRemap[vid];
3292 if(softVertices[vid])
3293 rawIdx-= softStart[3];
3294 else
3295 rawIdx+= softSize[3]-hardStart[3];
3296 // for BlendShapes remapping
3297 vertexFinalRemap[vid]= (3<<30) + rawIdx;
3298 // fill raw struct
3299 skinLod.Vertices4[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
3300 skinLod.Vertices4[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
3301 skinLod.Vertices4[rawIdx].MatrixId[2]= _SkinWeights[vid].MatrixId[2];
3302 skinLod.Vertices4[rawIdx].MatrixId[3]= _SkinWeights[vid].MatrixId[3];
3303 skinLod.Vertices4[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
3304 skinLod.Vertices4[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
3305 skinLod.Vertices4[rawIdx].Weights[2]= _SkinWeights[vid].Weights[2];
3306 skinLod.Vertices4[rawIdx].Weights[3]= _SkinWeights[vid].Weights[3];
3307 skinLod.Vertices4[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
3308 skinLod.Vertices4[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
3309 skinLod.Vertices4[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
3312 // Remap Geomorphs.
3313 //========
3314 uint numGeoms= (uint)lod.Geomorphs.size();
3315 skinLod.Geomorphs.resize( numGeoms );
3316 for(i=0;i<numGeoms;i++)
3318 // NB: don't add "numGeoms" to the index because RawSkin look in a TempArray in RAM, which start at 0...
3319 skinLod.Geomorphs[i].Start= vertexRemap[lod.Geomorphs[i].Start];
3320 skinLod.Geomorphs[i].End= vertexRemap[lod.Geomorphs[i].End];
3323 // Remap RdrPass.
3324 //========
3325 skinLod.RdrPass.resize(lod.RdrPass.size());
3326 for(i=0;i<skinLod.RdrPass.size();i++)
3328 // NB: since RawSkin is possible only with SkinGrouping, and since SkniGrouping is
3329 // possible only with no Quads/Lines, we should have only Tris here.
3330 // remap tris.
3331 skinLod.RdrPass[i].setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
3332 skinLod.RdrPass[i].setNumIndexes(lod.RdrPass[i].PBlock.getNumIndexes());
3333 CIndexBufferRead ibaRead;
3334 lod.RdrPass[i].PBlock.lock (ibaRead);
3335 CIndexBufferReadWrite ibaWrite;
3336 skinLod.RdrPass[i].lock (ibaWrite);
3337 if (skinLod.RdrPass[i].getFormat() == CIndexBuffer::Indices32)
3339 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
3340 const uint32 *srcTriPtr= (const uint32 *) ibaRead.getPtr();
3341 uint32 *dstTriPtr= (uint32 *) ibaWrite.getPtr();
3342 uint32 numIndices= lod.RdrPass[i].PBlock.getNumIndexes();
3343 for(uint j=0;j<numIndices;j++, srcTriPtr++, dstTriPtr++)
3345 uint vid= *srcTriPtr;
3346 // If this index refers to a Geomorphed vertex, don't modify!
3347 if(vid<numGeoms)
3348 *dstTriPtr= vid;
3349 else
3350 *dstTriPtr= vertexRemap[vid] + numGeoms;
3353 else
3355 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
3356 const uint16 *srcTriPtr= (const uint16 *) ibaRead.getPtr();
3357 uint16 *dstTriPtr= (uint16 *) ibaWrite.getPtr();
3358 uint32 numIndices= lod.RdrPass[i].PBlock.getNumIndexes();
3359 for(uint j=0;j<numIndices;j++, srcTriPtr++, dstTriPtr++)
3361 uint vid= *srcTriPtr;
3362 // If this index refers to a Geomorphed vertex, don't modify!
3363 if(vid<numGeoms)
3364 *dstTriPtr= vid;
3365 else
3366 *dstTriPtr= vertexRemap[vid] + numGeoms;
3371 // Case of MeshMorpher
3372 //========
3373 if(!_MeshMorpher.BlendShapes.empty())
3375 skinLod.VertexRemap.resize((uint32)vertexFinalRemap.size());
3377 for(i=0;i<vertexFinalRemap.size();i++)
3379 uint vfr= vertexFinalRemap[i];
3380 if(vfr!=0xFFFFFFFF)
3382 uint rsArrayId= vfr >> 30;
3383 uint rsIndex= vfr & ((1<<30)-1);
3384 switch(rsArrayId)
3386 case 0:
3387 skinLod.VertexRemap[i]= &skinLod.Vertices1[rsIndex].Vertex;
3388 break;
3389 case 1:
3390 skinLod.VertexRemap[i]= &skinLod.Vertices2[rsIndex].Vertex;
3391 break;
3392 case 2:
3393 skinLod.VertexRemap[i]= &skinLod.Vertices3[rsIndex].Vertex;
3394 break;
3395 case 3:
3396 skinLod.VertexRemap[i]= &skinLod.Vertices4[rsIndex].Vertex;
3397 break;
3400 else
3401 skinLod.VertexRemap[i]= NULL;
3409 // ***************************************************************************
3410 // ***************************************************************************
3411 // CMeshMRMGeom Shadow Skin Rendering
3412 // ***************************************************************************
3413 // ***************************************************************************
3416 // ***************************************************************************
3417 void CMeshMRMGeom::setShadowMesh(const std::vector<CShadowVertex> &shadowVertices, const std::vector<uint32> &triangles)
3419 _ShadowSkin.Vertices= shadowVertices;
3420 _ShadowSkin.Triangles= triangles;
3421 // update flag. Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
3422 _SupportShadowSkinGrouping= !_ShadowSkin.Vertices.empty() &&
3423 NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT==CVertexBuffer::PositionFlag &&
3424 _ShadowSkin.Vertices.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES;
3427 // ***************************************************************************
3428 uint CMeshMRMGeom::getNumShadowSkinVertices() const
3430 return (uint)_ShadowSkin.Vertices.size();
3433 // ***************************************************************************
3434 sint CMeshMRMGeom::renderShadowSkinGeom(CMeshMRMInstance *mi, uint remainingVertices, uint8 *vbDest)
3436 uint numVerts= (uint)_ShadowSkin.Vertices.size();
3438 // if no verts, no draw
3439 if(numVerts==0)
3440 return 0;
3442 // if no lods, there should be no verts, but still ensure no bug in skinning
3443 if(_Lods.empty())
3444 return 0;
3446 // If the Lod is too big to render in the VBufferHard
3447 if(numVerts>remainingVertices)
3448 // return Failure
3449 return -1;
3451 // get the skeleton model to which I am skinned
3452 CSkeletonModel *skeleton;
3453 skeleton = mi->getSkeletonModel();
3454 // must be skinned for renderSkin()
3455 nlassert(skeleton);
3458 // Profiling
3459 //===========
3460 H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow );
3463 // Skinning.
3464 //===========
3466 // skinning with normal, but no tangent space
3467 // For all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
3468 // NB: take the best lod since the lower lods cannot use other Matrix than the higher one.
3469 static vector<CMatrix3x4> boneMat3x4;
3470 CLod &lod= _Lods[_Lods.size()-1];
3471 computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton);
3473 _ShadowSkin.applySkin((CVector*)vbDest, boneMat3x4);
3476 // How many vertices are added to the VBuffer ???
3477 return numVerts;
3481 // ***************************************************************************
3482 void CMeshMRMGeom::renderShadowSkinPrimitives(CMeshMRMInstance *mi, CMaterial &castMat, IDriver *drv, uint baseVertex)
3484 nlassert(drv);
3486 if(_ShadowSkin.Triangles.empty())
3487 return;
3489 // Profiling
3490 //===========
3491 H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow );
3493 // NB: the skeleton matrix has already been setuped by CSkeletonModel
3494 // NB: the normalize flag has already been setuped by CSkeletonModel
3496 // TODO_SHADOW: optim: Special triangle cache for shadow!
3497 static CIndexBuffer shiftedTris;
3498 NL_SET_IB_NAME(shiftedTris, "CMeshMRMGeom::renderShadowSkinPrimitives::shiftedTris");
3499 if(shiftedTris.getNumIndexes()<_ShadowSkin.Triangles.size())
3501 shiftedTris.setFormat(NL_MESH_MRM_INDEX_FORMAT);
3502 shiftedTris.setNumIndexes((uint32)_ShadowSkin.Triangles.size());
3504 shiftedTris.setPreferredMemory(CIndexBuffer::RAMVolatile, false);
3506 CIndexBufferReadWrite iba;
3507 shiftedTris.lock(iba);
3508 const uint32 *src= &_ShadowSkin.Triangles[0];
3509 TMeshMRMIndexType *dst= (TMeshMRMIndexType *) iba.getPtr();
3510 for(uint n= (uint)_ShadowSkin.Triangles.size();n>0;n--, src++, dst++)
3512 *dst= (TMeshMRMIndexType)(*src + baseVertex);
3516 // Render Triangles with cache
3517 //===========
3519 uint numTris= (uint)_ShadowSkin.Triangles.size()/3;
3521 // Render with the Materials of the MeshInstance.
3522 drv->activeIndexBuffer(shiftedTris);
3523 drv->renderTriangles(castMat, 0, numTris);
3527 // ***************************************************************************
3528 bool CMeshMRMGeom::getSkinBoneBBox(CSkeletonModel *skeleton, NLMISC::CAABBox &bbox, uint boneId) const
3530 bbox.setCenter(CVector::Null);
3531 bbox.setHalfSize(CVector::Null);
3533 if(!skeleton)
3534 return false;
3536 // get the bindpos of the wanted bone
3537 nlassert(boneId<skeleton->Bones.size());
3538 const CMatrix &invBindPos= skeleton->Bones[boneId].getBoneBase().InvBindPos;
3541 // Find the Geomorph space: to process only real vertices, not geomorphed ones.
3542 uint nGeomSpace= 0;
3543 uint lod;
3544 for (lod=0; lod<_Lods.size(); lod++)
3546 nGeomSpace= max(nGeomSpace, (uint)_Lods[lod].Geomorphs.size());
3549 // Prepare Sphere compute
3550 nlassert(_OriginalSkinVertices.size() == _SkinWeights.size());
3551 bool bbEmpty= true;
3553 // Remap the vertex, and compute the wanted bone bbox
3554 // for true vertices
3555 for (uint vert=nGeomSpace; vert<_SkinWeights.size(); vert++)
3557 // get the vertex position.
3558 CVector vertex= _OriginalSkinVertices[vert];
3560 // For each weight
3561 uint weight;
3562 for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
3564 // Active ?
3565 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
3567 // Check id is the wanted one
3568 if(_SkinWeights[vert].MatrixId[weight]==boneId)
3570 // transform the vertex pos in BoneSpace
3571 CVector p= invBindPos * vertex;
3572 // extend the bone bbox.
3573 if(bbEmpty)
3575 bbox.setCenter(p);
3576 bbEmpty= false;
3578 else
3580 bbox.extend(p);
3584 else
3585 break;
3589 // return true if some influence found
3590 return !bbEmpty;
3594 // ***************************************************************************
3595 bool CMeshMRMGeom::intersectSkin(CMeshMRMInstance *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
3597 // for MeshMRM, Use the Shadow Skinning (simple and light version).
3599 // no inst/verts/lod => no intersection
3600 if(!mi || _ShadowSkin.Vertices.empty() || _Lods.empty())
3601 return false;
3602 CSkeletonModel *skeleton= mi->getSkeletonModel();
3603 if(!skeleton)
3604 return false;
3606 // Compute skinning with all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
3607 // NB: take the best lod (_Lods.back()) since the lower lods cannot use other Matrix than the higher one.
3608 return _ShadowSkin.getRayIntersection(toRaySpace, *skeleton, _Lods.back().MatrixInfluences, dist2D, distZ, computeDist2D);
3612 } // NL3D