1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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
;
49 H_AUTO_DECL( NL3D_MeshMRMGeom_RenderShadow
)
52 // ***************************************************************************
53 // ***************************************************************************
55 // ***************************************************************************
56 // ***************************************************************************
59 // ***************************************************************************
60 void CMeshMRMGeom::CLod::serial(NLMISC::IStream
&f
)
64 - precompute of triangle order. (nothing more to load).
71 sint ver
= f
.serialVersion(2);
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
]);
87 f
.serialCont(SkinVertexBlocks
);
89 buildSkinVertexBlocks();
91 // if >= version 2, reorder of triangles is precomputed, else compute it now.
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.
111 for(i
=0;i
<NL3D_MESH_SKINNING_MAX_MATRIX
;i
++)
113 uint nInf
= (uint
)InfluencedVertices
[i
].size();
116 uint32
*infPtr
= &(InfluencedVertices
[i
][0]);
118 // for all InfluencedVertices only.
119 for(;nInf
>0;nInf
--, 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
++)
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;
149 // Finish the preceding block (if any).
157 // ***************************************************************************
158 void CMeshMRMGeom::CLod::optimizeTriangleOrder()
160 CStripifier stripifier
;
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 // ***************************************************************************
176 // ***************************************************************************
177 // ***************************************************************************
182 // ***************************************************************************
183 static NLMISC::CAABBoxExt
makeBBox(const std::vector
<CVector
> &Vertices
)
186 nlassert(!Vertices
.empty());
187 ret
.setCenter(Vertices
[0]);
188 for(sint i
=0;i
<(sint
)Vertices
.size();i
++)
190 ret
.extend(Vertices
[i
]);
197 // ***************************************************************************
198 CMeshMRMGeom::CMeshMRMGeom()
202 _BoneIdComputed
= false;
203 _BoneIdExtended
= false;
204 _PreciseClipping
= false;
205 _SupportSkinGrouping
= false;
207 _SupportMeshBlockRendering
= false;
209 _SupportShadowSkinGrouping
= false;
213 // ***************************************************************************
214 CMeshMRMGeom::~CMeshMRMGeom()
219 // ***************************************************************************
220 void CMeshMRMGeom::changeMRMDistanceSetup(float distanceFinest
, float distanceMiddle
, float distanceCoarsest
)
223 if(distanceFinest
<0) return;
224 if(distanceMiddle
<=distanceFinest
) return;
225 if(distanceCoarsest
<=distanceMiddle
) return;
228 _LevelDetail
.DistanceFinest
= distanceFinest
;
229 _LevelDetail
.DistanceMiddle
= distanceMiddle
;
230 _LevelDetail
.DistanceCoarsest
= distanceCoarsest
;
233 _LevelDetail
.compileDistanceSetup();
237 // ***************************************************************************
238 void CMeshMRMGeom::build(CMesh::CMeshBuild
&m
, std::vector
<CMesh::CMeshBuild
*> &bsList
,
239 uint numMaxMaterial
, const CMRMParameters
¶ms
)
242 if(m
.Vertices
.empty() || m
.Faces
.empty())
244 _VBufferFinal
.setNumVertices(0);
245 _VBufferFinal
.reserve(0);
247 _BBox
.setCenter(CVector::Null
);
248 _BBox
.setSize(CVector::Null
);
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;
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
318 CLod
&firstLod
= _Lods
[0];
319 for (pb
=0; pb
<firstLod
.RdrPass
.size(); pb
++)
321 CRdrPass
&pass
= firstLod
.RdrPass
[pb
];
323 _LevelDetail
.MinFaceUsed
+= pass
.PBlock
.getNumIndexes ()/3;
326 CLod
&lastLod
= _Lods
[_Lods
.size()-1];
327 for (pb
=0; pb
<lastLod
.RdrPass
.size(); pb
++)
329 CRdrPass
&pass
= lastLod
.RdrPass
[pb
];
331 _LevelDetail
.MaxFaceUsed
+= pass
.PBlock
.getNumIndexes ()/3;
337 //================================================
340 bkupOriginalSkinVertices();
342 // Inform that the mesh data has changed
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();
356 //================================================
357 _MeshMorpher
.BlendShapes
= meshBuildMRM
.BlendShapes
;
360 // Compact bone id and build a bone id names
361 //================================================
367 std::map
<uint
, uint
> remap
;
370 uint currentBone
= 0;
373 _BonesName
.reserve (m
.BonesNames
.size());
377 for (vert
=0; vert
<_SkinWeights
.size(); vert
++)
384 for (weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
387 if ((_SkinWeights
[vert
].Weights
[weight
]>0)||(weight
==0))
390 std::map
<uint
, uint
>::iterator ite
= remap
.find (_SkinWeights
[vert
].MatrixId
[weight
]);
393 if (ite
== remap
.end())
396 remap
.insert (std::map
<uint
, uint
>::value_type (_SkinWeights
[vert
].MatrixId
[weight
], currentBone
));
399 nlassert (_SkinWeights
[vert
].MatrixId
[weight
]<m
.BonesNames
.size());
402 _BonesName
.push_back (m
.BonesNames
[_SkinWeights
[vert
].MatrixId
[weight
]]);
404 // Set the local bone id
405 _SkinWeights
[vert
].MatrixId
[weight
] = currentBone
++;
409 // Set the local bone id
410 _SkinWeights
[vert
].MatrixId
[weight
] = ite
->second
;
422 // Remap the vertex influence by lods
424 for (lod
=0; lod
<_Lods
.size(); lod
++)
426 // For each matrix used
428 for (matrix
=0; matrix
<_Lods
[lod
].MatrixInfluences
.size(); matrix
++)
431 std::map
<uint
, uint
>::iterator ite
= remap
.find (_Lods
[lod
].MatrixInfluences
[matrix
]);
434 nlassert (ite
!= remap
.end());
437 _Lods
[lod
].MatrixInfluences
[matrix
] = ite
->second
;
443 //===================
444 // Some runtime not serialized compilation
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
++)
457 uint32
&matId
= _Lods
[lod
].RdrPass
[rp
].MaterialId
;
458 nlassert(remap
[matId
]>=0);
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.
478 clamp(alphaLod
, 0.f
, 1.f
);
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);
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
);
514 uint ua
= (uint
)(a
*256);
515 clamp(ua
, (uint
)0, (uint
)256);
518 // if an offset is 0, it means that the component is not in the VBuffer.
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();
531 if(flags
& CVertexBuffer::PrimaryColorFlag
)
532 colorOff
= _VBufferFinal
.getColorOff();
535 if(flags
& CVertexBuffer::SecondaryColorFlag
)
536 specularOff
= _VBufferFinal
.getSpecularOff();
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
);
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
;
575 CVector
*start
= (CVector
*)startPtr
;
576 CVector
*end
= (CVector
*)endPtr
;
577 CVector
*dst
= (CVector
*)destPtr
;
578 *dst
= *start
* a
+ *end
* a1
;
584 CVector
*start
= (CVector
*)(startPtr
+ normalOff
);
585 CVector
*end
= (CVector
*)(endPtr
+ normalOff
);
586 CVector
*dst
= (CVector
*)(destPtr
+ normalOff
);
587 *dst
= *start
* a
+ *end
* a1
;
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
;
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
;
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
;
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
;
638 CVector
*start
= (CVector
*)startPtr
;
639 CVector
*end
= (CVector
*)endPtr
;
640 CVector
*dst
= (CVector
*)destPtr
;
641 *dst
= *start
* a
+ *end
* a1
;
647 CVector
*start
= (CVector
*)(startPtr
+ normalOff
);
648 CVector
*end
= (CVector
*)(endPtr
+ normalOff
);
649 CVector
*dst
= (CVector
*)(destPtr
+ normalOff
);
650 *dst
= *start
* a
+ *end
* a1
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
736 CRGBA
*start
= (CRGBA
*)(startPtr
+ colorOff
);
737 CRGBA
*end
= (CRGBA
*)(endPtr
+ colorOff
);
738 CRGBA
*dst
= (CRGBA
*)(destPtr
+ colorOff
);
739 dst
->blendFromui(*start
, *end
, ua1
);
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
;
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
;
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
;
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
);
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
)
851 // test if must do a precise clip, according to mesh size.
852 if( _PreciseClipping
)
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
) )
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
);
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;
902 // ***************************************************************************
903 void CMeshMRMGeom::render(IDriver
*drv
, CTransformShape
*trans
, float polygonCount
, uint32 rdrFlags
, float globalAlpha
)
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
);
923 sint numLod
= chooseLod(alphaMRM
, alphaLod
);
926 // Render the choosen Lod.
927 CLod
&lod
= _Lods
[numLod
];
928 if(lod
.RdrPass
.empty())
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();
947 H_AUTO( NL3D_MeshMRMGeom_RenderNormal
);
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.
959 _MeshMorpher
.initSkinned(&_VBufferOriginal
,
962 &_OriginalSkinVertices
,
963 &_OriginalSkinNormals
,
964 useTangentSpace
? &_OriginalTGSpace
: NULL
,
966 _MeshMorpher
.updateSkinned (mi
->getBlendShapeFactors());
968 else // Not even skinned so we have to do all the stuff
970 _MeshMorpher
.init(&_VBufferOriginal
,
973 _MeshMorpher
.update (mi
->getBlendShapeFactors());
979 // if mesh is skinned (but here skin not applied), we must copy vertices/normals from original vertices.
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());
994 // Geomorph the choosen Lod (if not the coarser mesh).
997 applyGeomorph(lod
.Geomorphs
, alphaLod
);
1001 // force normalisation of normals..
1002 bool bkupNorm
= drv
->isForceNormalize();
1003 drv
->forceNormalize(true);
1006 // Setup meshVertexProgram
1009 // use MeshVertexProgram effect?
1010 bool useMeshVP
= _MeshVertexProgram
!= NULL
;
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
);
1023 drv
->activeVertexBuffer(_VBufferFinal
);
1026 // Global alpha used ?
1027 uint32 globalAlphaUsed
= rdrFlags
& IMeshGeom::RenderGlobalAlpha
;
1028 uint8 globalAlphaInt
=(uint8
)NLMISC::OptFastFloor(globalAlpha
*255);
1031 if (globalAlphaUsed
)
1033 bool gaDisableZWrite
= (rdrFlags
& IMeshGeom::RenderGADisableZWrite
)?true:false;
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
) ) )
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
1053 _MeshVertexProgram
->setupForMaterial(material
, drv
, ownerScene
, &_VBufferFinal
);
1057 drv
->activeIndexBuffer(rdrPass
.PBlock
);
1058 drv
->renderTriangles(material
, 0, rdrPass
.PBlock
.getNumIndexes()/3);
1060 // Resetup material/driver
1061 blender
.restoreRender(material
, drv
, gaDisableZWrite
);
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
) ) )
1075 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
1077 // Setup VP material
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
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
);
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();
1127 sint numLod
= chooseLod(alphaMRM
, alphaLod
);
1130 // Render the choosen Lod.
1131 CLod
&lod
= _Lods
[numLod
];
1132 if(lod
.RdrPass
.empty())
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();
1156 H_AUTO( NL3D_MeshMRMGeom_renderSkin_go
);
1163 // Since Skinned we must update original skin vertices and normals because skinning use it
1164 _MeshMorpher
.initSkinned(&_VBufferOriginal
,
1167 &_OriginalSkinVertices
,
1168 &_OriginalSkinNormals
,
1169 useTangentSpace
? &_OriginalTGSpace
: NULL
,
1171 _MeshMorpher
.updateSkinned (mi
->getBlendShapeFactors());
1177 // Never use RawSkin. Actually used in skinGrouping.
1178 updateRawSkinNormal(false, mi
, numLod
);
1183 // If skin without normal (rare/useful?) always simple (slow) case.
1186 // skinning with just position
1187 applySkin (lod
, skeleton
);
1191 // apply skin for this Lod only.
1192 if (!useTangentSpace
)
1194 // skinning with normal, but no tangent space
1195 applySkinWithNormal (lod
, skeleton
);
1199 // Tangent space stored in the last texture coordinate
1200 applySkinWithTangentSpace(lod
, skeleton
, _VBufferFinal
.getNumTexCoordUsed() - 1);
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
1216 // Geomorph the choosen Lod (if not the coarser mesh).
1219 applyGeomorph(lod
.Geomorphs
, alphaLod
);
1223 // Setup meshVertexProgram
1226 // use MeshVertexProgram effect?
1227 bool useMeshVP
= _MeshVertexProgram
!= NULL
;
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
);
1240 drv
->activeVertexBuffer(_VBufferFinal
);
1244 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
1246 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
1249 CMaterial
&material
=mi
->Materials
[rdrPass
.MaterialId
];
1251 // Setup VP material
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
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();
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
1305 // If the Lod is too big to render in the VBufferHard
1306 if(lod
.NWedges
>remainingVertices
)
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
);
1322 H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom_go
);
1328 // Use RawSkin?. compute before morphing, cause of updateRawSkin
1329 updateRawSkinNormal(true, mi
, numLod
);
1330 nlassert(mi
->_RawSkinCache
);
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());
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.
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();
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
1391 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
1393 CRdrPass
&rdrPass
= lod
.RdrPass
[i
];
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 );
1406 if(material.getShader()==CMaterial::Specular)
1408 CSmartPtr<ITexture> tex= material.getTexture(0);
1409 material.setShader(CMaterial::Normal);
1410 material.setTexture(0, tex );
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);
1426 specRdrPass
.SpecId
= 0;
1428 specRdrPass
.SpecId
= drv
->getTextureHandle( *specTex
);
1429 // Append it to the list
1430 specularRdrPasses
.push_back(specRdrPass
);
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();
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
1468 CRdrPass
&rdrPass
= lod
.RdrPass
[rdrPassId
];
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
;
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
];
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
;
1525 mi
->_ShiftedTriangleCache
->RdrPass
.resize((uint32
)pbList
.size());
1527 // First pass, count number of triangles, and fill header info
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
1548 for(i
=0;i
<pbList
.size();i
++)
1550 CShiftedTriangleCache::CRdrPass
&dstRdrPass
= mi
->_ShiftedTriangleCache
->RdrPass
[i
];
1551 dstRdrPass
.Triangles
= indexTri
*3;
1554 uint numTris
= pbList
[i
]->getNumIndexes()/3;
1557 uint nIds
= numTris
*3;
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
;
1569 indexTri
+= dstRdrPass
.NumTriangles
;
1574 nlassert(ibaWrite
.getFormat() == CIndexBuffer::Indices16
);
1575 uint16
*dstPtr
= (uint16
*) ibaWrite
.getPtr();
1576 // Second pass, fill ptrs, and fill Arrays
1578 for(i
=0;i
<pbList
.size();i
++)
1580 CShiftedTriangleCache::CRdrPass
&dstRdrPass
= mi
->_ShiftedTriangleCache
->RdrPass
[i
];
1581 dstRdrPass
.Triangles
= indexTri
*3;
1584 uint numTris
= pbList
[i
]->getNumIndexes()/3;
1587 uint nIds
= numTris
*3;
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
;
1599 indexTri
+= dstRdrPass
.NumTriangles
;
1606 // ***************************************************************************
1607 void CMeshMRMGeom::serial(NLMISC::IStream
&f
)
1609 // because of complexity, serial is separated in save / load.
1620 // ***************************************************************************
1621 sint
CMeshMRMGeom::loadHeader(NLMISC::IStream
&f
)
1627 - serial SkinWeights per MRM, not per Lod
1631 - Mesh Vertex Program.
1633 - added blend shapes
1637 sint ver
= f
.serialVersion(5);
1640 // if >= version 3, serial boens names
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.
1654 IMeshVertexProgram
*mvp
= NULL
;
1655 f
.serialPolyPtr(mvp
);
1656 _MeshVertexProgram
= mvp
;
1661 _MeshVertexProgram
= NULL
;
1666 f
.serial (_MeshMorpher
);
1668 // serial Basic info.
1669 // ==================
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...
1689 // Prepare the VBuffer.
1690 _VBufferFinal
.serialHeader(f
);
1691 // If skinned, must allocate skinWeights.
1692 contReset(_SkinWeights
);
1695 _SkinWeights
.resize(nWedges
);
1699 // If new version, serial SkinWeights in header, not in lods.
1702 f
.serialCont(_SkinWeights
);
1706 // if >= version 5, serial Shadow Skin Information
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 // ==================
1733 _Lods
.resize(_LodInfos
.size());
1735 // Flag the fact that no lod is loaded for now.
1738 // Inform that the mesh data has changed
1742 // Some runtime not serialized compilation
1745 // return version of the header
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.
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.
1775 buildBoneUsageVer2 ();
1780 // ***************************************************************************
1781 void CMeshMRMGeom::save(NLMISC::IStream
&f
)
1787 - serial SkinWeights per MRM, not per Lod
1791 - Mesh Vertex Program.
1793 - added blend shapes
1797 sint ver
= f
.serialVersion(5);
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.
1809 IMeshVertexProgram
*mvp
= NULL
;
1810 mvp
= _MeshVertexProgram
;
1811 f
.serialPolyPtr(mvp
);
1816 f
.serial (_MeshMorpher
);
1818 // must have good original Skinned Vertex before writing.
1821 restoreOriginalSkinVertices();
1825 // serial Basic info.
1826 // ==================
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.
1840 nWedges
= _VBufferFinal
.getNumVertices();
1842 // Save the VBuffer header.
1843 _VBufferFinal
.serialHeader(f
);
1846 // If new version, serial SkinWeights in header, not in lods.
1849 f
.serialCont(_SkinWeights
);
1852 // if >= version 5, serial Shadow Skin Information
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.
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
)
1911 - serial SkinWeights per MRM, not per Lod
1913 sint ver
= f
.serialVersion(1);
1916 _VBufferFinal
.serialSubset(f
, startWedge
, endWedge
);
1921 // Serialize SkinWeight per lod only for old versions.
1924 for(uint i
= startWedge
; i
<endWedge
; i
++)
1926 f
.serial(_SkinWeights
[i
]);
1929 // if reading, must copy original vertices from VB.
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())
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....
1957 numLodToLoad
= (uint
)_LodInfos
.size();
1962 // Read lod subset(s).
1963 // ==================
1964 for(uint i
=0;i
<numLodToLoad
; i
++)
1966 // read the lod face data.
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.
1980 buildBoneUsageVer2 ();
1985 // ***************************************************************************
1986 void CMeshMRMGeom::loadNextLod(NLMISC::IStream
&f
)
1988 // If all is loaded, quit.
1989 if(getNbLodLoaded() == getNbLod())
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.
2009 // ***************************************************************************
2010 void CMeshMRMGeom::unloadNextLod(NLMISC::IStream
&f
)
2012 // If just first lod remain (or no lod), quit
2013 if(getNbLodLoaded() <= 1)
2016 // Reset the entire Lod object. (Free Memory).
2017 contReset(_Lods
[_NbLodLoaded
-1]);
2020 // Dec LodLoaded count.
2025 // ***************************************************************************
2026 void CMeshMRMGeom::bkupOriginalSkinVertices()
2030 // bkup the entire array.
2031 bkupOriginalSkinVerticesSubset(0, _VBufferFinal
.getNumVertices());
2035 // ***************************************************************************
2036 void CMeshMRMGeom::bkupOriginalSkinVerticesSubset(uint wedgeStart
, uint wedgeEnd
)
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())
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()
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
)
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();
2136 nlassert(flags
& CVertexBuffer::PositionFlag
);
2138 // Compute offset of each component of the VB.
2140 if(flags
& CVertexBuffer::NormalFlag
)
2141 normalOff
= _VBufferFinal
.getNormalOff();
2146 // compute src array.
2147 CVector
*srcVertexPtr
;
2148 CVector
*srcNormalPtr
= NULL
;
2149 srcVertexPtr
= &_OriginalSkinVertices
[0];
2151 srcNormalPtr
= &(_OriginalSkinNormals
[0]);
2155 //===========================
2156 for(uint i
=0;i
<NL3D_MESH_SKINNING_MAX_MATRIX
;i
++)
2158 uint nInf
= (uint
)lod
.InfluencedVertices
[i
].size();
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
);
2175 *dstVertex
= *srcVertex
;
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
);
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.
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
;
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
2234 for (vert
=nGeomSpace
; vert
<_SkinWeights
.size(); vert
++)
2236 // get the vertex position.
2237 CVector vertex
= _OriginalSkinVertices
[vert
];
2241 for (weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
2244 if ((_SkinWeights
[vert
].Weights
[weight
]>0)||(weight
==0))
2247 uint srcId
= _SkinWeights
[vert
].MatrixId
[weight
];
2248 nlassert (srcId
< remap
.size());
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;
2265 boneBBoxes
[srcId
].extend(p
);
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;
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
2295 for (matrix
=0; matrix
<_Lods
[lod
].MatrixInfluences
.size(); matrix
++)
2298 nlassert (_Lods
[lod
].MatrixInfluences
[matrix
]<remap
.size());
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
];
2310 nlassert (v
.MatrixId
< remap
.size());
2311 v
.MatrixId
= remap
[v
.MatrixId
];
2315 _BoneIdComputed
= true;
2319 // Already extended ?
2320 if (!_BoneIdExtended
)
2322 nlassert (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.
2331 for(i
=0; i
<_BonesId
.size(); i
++)
2333 // if not a valid boneId, skip it.
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.
2347 _BonesIdExt
.push_back(i
);
2353 _BoneIdExtended
= true;
2359 // ***************************************************************************
2360 void CMeshMRMGeom::buildBoneUsageVer2 ()
2364 // parse all vertices, couting MaxBoneId used.
2365 uint32 maxBoneId
= 0;
2368 for (vert
=0; vert
<_SkinWeights
.size(); vert
++)
2371 for (uint weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
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
++)
2389 for (uint weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
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
2402 for(uint i
=0; i
<boneUsage
.size();i
++)
2404 // if the bone is used by the mesh, add it to BoneId.
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().
2424 sm
->incBoneUsage(boneId
, CSkeletonModel::UsageNormal
);
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;
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
2471 // get the result of the Load Balancing.
2472 float alphaMRM
= _LevelDetail
.getLevelDetailFromPolyCount(polygonCount
);
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.
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;
2501 rdrTrav
->Scene
->incrementProfileTriVBFormat(rdrTrav
->Scene
->BenchRes
.MeshMRMProfileTriVBFormat
,
2502 _VBufferFinal
.getVertexFormat(), triCount
);
2505 if(_VBufferFinal
.getPreferredMemory()!=CVertexBuffer::RAMPreferred
)
2506 rdrTrav
->Scene
->BenchRes
.NumMeshMRMVBufferHard
++;
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
;
2520 rdrTrav
->Scene
->BenchRes
.NumMeshMRMRdrBlock
++;
2521 rdrTrav
->Scene
->BenchRes
.NumMeshMRMTriRdrBlock
+= triCount
;
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())
2540 if(_VBufferFinal
.isResident())
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.
2557 for(i
=0;i
<getNbRdrPass(lodId
);i
++)
2559 const CIndexBuffer
&pb
= getRdrPassPrimitiveBlock(lodId
, i
);
2563 CIndexBufferRead 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
++)
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)
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)
2600 if(numUsedVertices
==0)
2602 // Then we have our vertices size
2603 vertices
.resize(numUsedVertices
);
2606 // **** Fill the vertex geometry
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];
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
;
2627 *pDstVert
= *(CVector
*)pSrcVert
;
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
;
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
;
2670 // should have filled the entire buffer
2671 nlassert(uint(pDstIndex
-(&triangles
[0]))==numTotalIndices
);
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
2694 TODO_OPTIMIZE: find a way to optimize MRM.
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!!
2706 // ***************************************************************************
2707 uint
CMeshMRMGeom::getNumRdrPassesForMesh() const
2713 // ***************************************************************************
2714 uint
CMeshMRMGeom::getNumRdrPassesForInstance(CMeshBaseInstance
*inst
) const
2716 return (uint
)_Lods
[_MBRCurrentLodId
].RdrPass
.size();
2718 // ***************************************************************************
2719 void CMeshMRMGeom::beginMesh(CMeshGeomRenderContext
&rdrCtx
)
2724 IDriver
*drv
= rdrCtx
.Driver
;
2726 if(rdrCtx
.RenderThroughVBHeap
)
2728 // Don't setup VB in this case, since use the VBHeap setuped one.
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
);
2749 // get the result of the Load Balancing.
2750 float alphaMRM
= _LevelDetail
.getLevelDetailFromPolyCount(polygonCount
);
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
);
2762 applyGeomorph(_Lods
[_MBRCurrentLodId
].Geomorphs
, alphaLod
);
2765 // set the instance worldmatrix.
2766 rdrCtx
.Driver
->setupModelMatrix(inst
->getWorldMatrix());
2769 inst
->changeLightSetup(rdrCtx
.RenderTrav
);
2771 // ***************************************************************************
2772 void CMeshMRMGeom::renderPass(CMeshGeomRenderContext
&rdrCtx
, CMeshBaseInstance
*mi
, float polygonCount
, uint rdrPassId
)
2777 CLod
&lod
= _Lods
[_MBRCurrentLodId
];
2778 CRdrPass
&rdrPass
= lod
.RdrPass
[rdrPassId
];
2780 if ( mi
->Materials
[rdrPass
.MaterialId
].getBlend() == false )
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);
2794 rdrCtx
.Driver
->activeIndexBuffer(rdrPass
.PBlock
);
2795 rdrCtx
.Driver
->renderTriangles(material
, 0, rdrPass
.PBlock
.getNumIndexes()/3);
2800 // ***************************************************************************
2801 void CMeshMRMGeom::endMesh(CMeshGeomRenderContext
&rdrCtx
)
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() );
2829 for(uint lodId
=0; lodId
<_Lods
.size();lodId
++)
2831 CLod
&lod
= _Lods
[lodId
];
2834 for(uint i
=0;i
<lod
.RdrPass
.size();i
++)
2837 CIndexBuffer
&srcPb
= lod
.RdrPass
[i
].PBlock
;
2838 CIndexBuffer
&dstPb
= lod
.RdrPass
[i
].VBHeapPBlock
;
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
2869 // ***************************************************************************
2870 // ***************************************************************************
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
¶ms
)
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
);
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
);
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();
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
)
2960 uint32 mask
= (0-(uint32
)passOpaque
);
2962 // select rdrFlags, without ifs.
2963 rdrFlags
= mask
& (IMeshGeom::RenderOpaqueMaterial
| IMeshGeom::RenderPassOpaque
);
2964 rdrFlags
|= ~mask
& (IMeshGeom::RenderTransparentMaterial
);
2966 _MeshMRMGeom
.render(drv
, trans
, trans
->getNumTrianglesAfterLoadBalancing(), rdrFlags
, 1);
2970 // ***************************************************************************
2971 void CMeshMRM::serial(NLMISC::IStream
&f
)
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
;
3033 // ***************************************************************************
3034 void CMeshMRM::profileSceneRender(CRenderTrav
*rdrTrav
, CTransformShape
*trans
, bool passOpaque
)
3037 uint32 mask
= (0-(uint32
)passOpaque
);
3039 // select rdrFlags, without ifs.
3040 rdrFlags
= mask
& (IMeshGeom::RenderOpaqueMaterial
| IMeshGeom::RenderPassOpaque
);
3041 rdrFlags
|= ~mask
& (IMeshGeom::RenderTransparentMaterial
);
3043 _MeshMRMGeom
.profileSceneRender(rdrTrav
, trans
, trans
->getNumTrianglesAfterLoadBalancing(), rdrFlags
);
3046 // ***************************************************************************
3047 void CMeshMRM::buildSystemGeometry()
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())
3057 // Choose the best Lod available for system geometry
3058 if(_MeshMRMGeom
.getNbLodLoaded()==0)
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();
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()
3091 // ***************************************************************************
3092 void CMeshMRMGeom::updateRawSkinNormal(bool enabled
, CMeshMRMInstance
*mi
, sint curLodId
)
3096 // if the instance cache is not cleared, must clear.
3097 if(mi
->_RawSkinCache
)
3098 mi
->clearRawSkinCache();
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
];
3130 // Clear the raw skin mesh.
3131 skinLod
.clearArrays();
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() );
3157 skinLod
.TotalSoftVertices
= 0;
3158 skinLod
.TotalHardVertices
= 0;
3164 for(uint j
=0;j
<lod
.InfluencedVertices
[i
].size();j
++)
3166 uint vid
= lod
.InfluencedVertices
[i
][j
];
3167 if(softVertices
[vid
])
3172 skinLod
.TotalSoftVertices
+= softSize
[i
];
3173 skinLod
.TotalHardVertices
+= hardSize
[i
];
3174 skinLod
.SoftVertices
[i
]= softSize
[i
];
3175 skinLod
.HardVertices
[i
]= hardSize
[i
];
3179 hardStart
[0]= skinLod
.TotalSoftVertices
;
3182 softStart
[i
]= softStart
[i
-1]+softSize
[i
-1];
3183 hardStart
[i
]= hardStart
[i
-1]+hardSize
[i
-1];
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
++;
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.
3215 for(i
=0;i
<skinLod
.Vertices1
.size();i
++)
3217 // get the dest vertex.
3218 uint vid
= lod
.InfluencedVertices
[0][i
];
3220 rawIdx
= vertexRemap
[vid
];
3221 if(softVertices
[vid
])
3222 rawIdx
-= softStart
[0];
3224 rawIdx
+= softSize
[0]-hardStart
[0];
3225 // for BlendShapes remapping
3226 vertexFinalRemap
[vid
]= (0<<30) + rawIdx
;
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.
3236 for(i
=0;i
<skinLod
.Vertices2
.size();i
++)
3238 // get the dest vertex.
3239 uint vid
= lod
.InfluencedVertices
[1][i
];
3241 rawIdx
= vertexRemap
[vid
];
3242 if(softVertices
[vid
])
3243 rawIdx
-= softStart
[1];
3245 rawIdx
+= softSize
[1]-hardStart
[1];
3246 // for BlendShapes remapping
3247 vertexFinalRemap
[vid
]= (1<<30) + rawIdx
;
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.
3260 for(i
=0;i
<skinLod
.Vertices3
.size();i
++)
3262 // get the dest vertex.
3263 uint vid
= lod
.InfluencedVertices
[2][i
];
3265 rawIdx
= vertexRemap
[vid
];
3266 if(softVertices
[vid
])
3267 rawIdx
-= softStart
[2];
3269 rawIdx
+= softSize
[2]-hardStart
[2];
3270 // for BlendShapes remapping
3271 vertexFinalRemap
[vid
]= (2<<30) + rawIdx
;
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.
3286 for(i
=0;i
<skinLod
.Vertices4
.size();i
++)
3288 // get the dest vertex.
3289 uint vid
= lod
.InfluencedVertices
[3][i
];
3291 rawIdx
= vertexRemap
[vid
];
3292 if(softVertices
[vid
])
3293 rawIdx
-= softStart
[3];
3295 rawIdx
+= softSize
[3]-hardStart
[3];
3296 // for BlendShapes remapping
3297 vertexFinalRemap
[vid
]= (3<<30) + rawIdx
;
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
);
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
];
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.
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!
3350 *dstTriPtr
= vertexRemap
[vid
] + numGeoms
;
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!
3366 *dstTriPtr
= vertexRemap
[vid
] + numGeoms
;
3371 // Case of MeshMorpher
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
];
3382 uint rsArrayId
= vfr
>> 30;
3383 uint rsIndex
= vfr
& ((1<<30)-1);
3387 skinLod
.VertexRemap
[i
]= &skinLod
.Vertices1
[rsIndex
].Vertex
;
3390 skinLod
.VertexRemap
[i
]= &skinLod
.Vertices2
[rsIndex
].Vertex
;
3393 skinLod
.VertexRemap
[i
]= &skinLod
.Vertices3
[rsIndex
].Vertex
;
3396 skinLod
.VertexRemap
[i
]= &skinLod
.Vertices4
[rsIndex
].Vertex
;
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
3442 // if no lods, there should be no verts, but still ensure no bug in skinning
3446 // If the Lod is too big to render in the VBufferHard
3447 if(numVerts
>remainingVertices
)
3451 // get the skeleton model to which I am skinned
3452 CSkeletonModel
*skeleton
;
3453 skeleton
= mi
->getSkeletonModel();
3454 // must be skinned for renderSkin()
3460 H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow
);
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 ???
3481 // ***************************************************************************
3482 void CMeshMRMGeom::renderShadowSkinPrimitives(CMeshMRMInstance
*mi
, CMaterial
&castMat
, IDriver
*drv
, uint baseVertex
)
3486 if(_ShadowSkin
.Triangles
.empty())
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
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
);
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.
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());
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
];
3562 for (weight
=0; weight
<NL3D_MESH_SKINNING_MAX_MATRIX
; weight
++)
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.
3589 // return true if some influence found
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())
3602 CSkeletonModel
*skeleton
= mi
->getSkeletonModel();
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
);