From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- docs/doxygen/nel/mesh__mrm_8cpp-source.html | 2867 +++++++++++++++++++++++++++ 1 file changed, 2867 insertions(+) create mode 100644 docs/doxygen/nel/mesh__mrm_8cpp-source.html (limited to 'docs/doxygen/nel/mesh__mrm_8cpp-source.html') diff --git a/docs/doxygen/nel/mesh__mrm_8cpp-source.html b/docs/doxygen/nel/mesh__mrm_8cpp-source.html new file mode 100644 index 00000000..ce6580d5 --- /dev/null +++ b/docs/doxygen/nel/mesh__mrm_8cpp-source.html @@ -0,0 +1,2867 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

mesh_mrm.cpp

Go to the documentation of this file.
00001 
+00007 /* Copyright, 2001 Nevrax Ltd.
+00008  *
+00009  * This file is part of NEVRAX NEL.
+00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00011  * it under the terms of the GNU General Public License as published by
+00012  * the Free Software Foundation; either version 2, or (at your option)
+00013  * any later version.
+00014 
+00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00018  * General Public License for more details.
+00019 
+00020  * You should have received a copy of the GNU General Public License
+00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00023  * MA 02111-1307, USA.
+00024  */
+00025 
+00026 #include "std3d.h"
+00027 
+00028 #include "nel/misc/bsphere.h"
+00029 #include "nel/misc/system_info.h"
+00030 #include "nel/misc/hierarchical_timer.h"
+00031 #include "nel/misc/fast_mem.h"
+00032 #include "3d/mesh_mrm.h"
+00033 #include "3d/mrm_builder.h"
+00034 #include "3d/mrm_parameters.h"
+00035 #include "3d/mesh_mrm_instance.h"
+00036 #include "3d/scene.h"
+00037 #include "3d/skeleton_model.h"
+00038 #include "3d/stripifier.h"
+00039 #include "3d/mesh_blender.h"
+00040 #include "3d/render_trav.h"
+00041 #include "3d/fast_floor.h"
+00042 #include "3d/raw_skin.h"
+00043 #include "3d/shifted_triangle_cache.h"
+00044 
+00045 
+00046 using namespace NLMISC;
+00047 using namespace std;
+00048 
+00049 
+00050 namespace NL3D 
+00051 {
+00052 
+00053 
+00054 H_AUTO_DECL( NL3D_MeshMRMGeom_RenderSkinned )
+00055 
+00056 
+00057 // ***************************************************************************
+00058 // ***************************************************************************
+00059 // CMeshMRMGeom::CLod
+00060 // ***************************************************************************
+00061 // ***************************************************************************
+00062 
+00063         
+00064 // ***************************************************************************
+00065 void            CMeshMRMGeom::CLod::serial(NLMISC::IStream &f)
+00066 {
+00067         /*
+00068         Version 2:
+00069                 - precompute of triangle order. (nothing more to load).
+00070         Version 1:
+00071                 - add VertexBlocks;
+00072         Version 0:
+00073                 - base vdrsion.
+00074         */
+00075 
+00076         sint    ver= f.serialVersion(2);
+00077         uint    i;
+00078 
+00079         f.serial(NWedges);
+00080         f.serialCont(RdrPass);
+00081         f.serialCont(Geomorphs);
+00082         f.serialCont(MatrixInfluences);
+00083 
+00084         // Serial array of InfluencedVertices. NB: code written so far for NL3D_MESH_SKINNING_MAX_MATRIX==4 only.
+00085         nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
+00086         for(i= 0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
+00087         {
+00088                 f.serialCont(InfluencedVertices[i]);
+00089         }
+00090 
+00091         if(ver>=1)
+00092                 f.serialCont(SkinVertexBlocks);
+00093         else
+00094                 buildSkinVertexBlocks();
+00095 
+00096         // if >= version 2, reorder of triangles is precomputed, else compute it now.
+00097         if(ver<2)
+00098                 optimizeTriangleOrder();
+00099 
+00100 }
+00101 
+00102 
+00103 // ***************************************************************************
+00104 void            CMeshMRMGeom::CLod::buildSkinVertexBlocks()
+00105 {
+00106         contReset(SkinVertexBlocks);
+00107 
+00108 
+00109         // The list of vertices. true if used by this lod.
+00110         vector<bool>            vertexMap;
+00111         vertexMap.resize(NWedges, false);
+00112 
+00113 
+00114         // from InfluencedVertices, aknoledge what vertices are used.
+00115         uint    i;
+00116         for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
+00117         {
+00118                 uint            nInf= InfluencedVertices[i].size();
+00119                 if( nInf==0 )
+00120                         continue;
+00121                 uint32          *infPtr= &(InfluencedVertices[i][0]);
+00122 
+00123                 //  for all InfluencedVertices only.
+00124                 for(;nInf>0;nInf--, infPtr++)
+00125                 {
+00126                         uint    index= *infPtr;
+00127                         vertexMap[index]= true;
+00128                 }
+00129         }
+00130 
+00131         // For all vertices, test if they are used, and build the according SkinVertexBlocks;
+00132         CVertexBlock    *vBlock= NULL;
+00133         for(i=0; i<vertexMap.size();i++)
+00134         {
+00135                 if(vertexMap[i])
+00136                 {
+00137                         // preceding block?
+00138                         if(vBlock)
+00139                         {
+00140                                 // yes, extend it.
+00141                                 vBlock->NVertices++;
+00142                         }
+00143                         else
+00144                         {
+00145                                 // no, append a new one.
+00146                                 SkinVertexBlocks.push_back(CVertexBlock());
+00147                                 vBlock= &SkinVertexBlocks[SkinVertexBlocks.size()-1];
+00148                                 vBlock->VertexStart= i;
+00149                                 vBlock->NVertices= 1;
+00150                         }
+00151                 }
+00152                 else
+00153                 {
+00154                         // Finish the preceding block (if any).
+00155                         vBlock= NULL;
+00156                 }
+00157         }
+00158 
+00159 }
+00160 
+00161 
+00162 // ***************************************************************************
+00163 void            CMeshMRMGeom::CLod::optimizeTriangleOrder()
+00164 {
+00165         CStripifier             stripifier;
+00166 
+00167         // for all rdrpass
+00168         for(uint  rp=0; rp<RdrPass.size(); rp++ )
+00169         {
+00170                 // stripify list of triangles of this pass.
+00171                 CRdrPass        &pass= RdrPass[rp];
+00172                 stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
+00173         }
+00174 
+00175 }
+00176 
+00177 
+00178 // ***************************************************************************
+00179 // ***************************************************************************
+00180 // CMeshMRMGeom.
+00181 // ***************************************************************************
+00182 // ***************************************************************************
+00183 
+00184 
+00185 
+00186 
+00187 // ***************************************************************************
+00188 static  NLMISC::CAABBoxExt      makeBBox(const std::vector<CVector>     &Vertices)
+00189 {
+00190         NLMISC::CAABBox         ret;
+00191         nlassert(Vertices.size());
+00192         ret.setCenter(Vertices[0]);
+00193         for(sint i=0;i<(sint)Vertices.size();i++)
+00194         {
+00195                 ret.extend(Vertices[i]);
+00196         }
+00197 
+00198         return ret;
+00199 }
+00200 
+00201 
+00202 // ***************************************************************************
+00203 CMeshMRMGeom::CMeshMRMGeom()
+00204 {
+00205         _VertexBufferHardDirty= true;
+00206         _Skinned= false;
+00207         _NbLodLoaded= 0;
+00208         _BoneIdComputed = false;
+00209         _BoneIdExtended = false;
+00210         _PreciseClipping= false;
+00211         _SupportSkinGrouping= false;
+00212         _MeshDataId= 0;
+00213 }
+00214 
+00215 
+00216 // ***************************************************************************
+00217 CMeshMRMGeom::~CMeshMRMGeom()
+00218 {
+00219         deleteVertexBufferHard();
+00220 }
+00221 
+00222 
+00223 // ***************************************************************************
+00224 void                    CMeshMRMGeom::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
+00225 {
+00226         // check input.
+00227         if(distanceFinest<0)    return;
+00228         if(distanceMiddle<=distanceFinest)      return;
+00229         if(distanceCoarsest<=distanceMiddle)    return;
+00230 
+00231         // Change.
+00232         _LevelDetail.DistanceFinest= distanceFinest;
+00233         _LevelDetail.DistanceMiddle= distanceMiddle;
+00234         _LevelDetail.DistanceCoarsest= distanceCoarsest;
+00235 
+00236         // compile 
+00237         _LevelDetail.compileDistanceSetup();
+00238 }
+00239 
+00240 
+00241 // ***************************************************************************
+00242 void                    CMeshMRMGeom::build(CMesh::CMeshBuild &m, std::vector<CMesh::CMeshBuild*> &bsList,
+00243                                                                         uint numMaxMaterial, const CMRMParameters &params)
+00244 {
+00245 
+00246         // Dirt the VBuffer.
+00247         _VertexBufferHardDirty= true;
+00248 
+00249         // Empty geometry?
+00250         if(m.Vertices.size()==0 || m.Faces.size()==0)
+00251         {
+00252                 _VBufferFinal.setNumVertices(0);
+00253                 _VBufferFinal.reserve(0);
+00254                 _Lods.clear();
+00255                 _BBox.setCenter(CVector::Null);
+00256                 _BBox.setSize(CVector::Null);
+00257                 return;
+00258         }
+00259         nlassert(numMaxMaterial>0);
+00260 
+00261 
+00262         // SmartPtr Copy VertexProgram effect.
+00263         //================================================      
+00264         this->_MeshVertexProgram= m.MeshVertexProgram;
+00265 
+00266 
+00268         //======================
+00269         // NB: this is equivalent as building BBox from MRM VBuffer, because CMRMBuilder create new vertices 
+00270         // which are just interpolation of original vertices.
+00271         _BBox= makeBBox(m.Vertices);
+00272 
+00273 
+00275         //================================================
+00276         CMRMBuilder                     mrmBuilder;
+00277         CMeshBuildMRM           meshBuildMRM;
+00278 
+00279         mrmBuilder.compileMRM(m, bsList, params, meshBuildMRM, numMaxMaterial);
+00280 
+00281         // Then just copy result!
+00282         //================================================
+00283         _VBufferFinal= meshBuildMRM.VBuffer;
+00284         _Lods= meshBuildMRM.Lods;
+00285         _Skinned= meshBuildMRM.Skinned;
+00286         _SkinWeights= meshBuildMRM.SkinWeights;
+00287 
+00288         // Compute degradation control.
+00289         //================================================
+00290         _LevelDetail.DistanceFinest= meshBuildMRM.DistanceFinest;
+00291         _LevelDetail.DistanceMiddle= meshBuildMRM.DistanceMiddle;
+00292         _LevelDetail.DistanceCoarsest= meshBuildMRM.DistanceCoarsest;
+00293         nlassert(_LevelDetail.DistanceFinest>=0);
+00294         nlassert(_LevelDetail.DistanceMiddle > _LevelDetail.DistanceFinest);
+00295         nlassert(_LevelDetail.DistanceCoarsest > _LevelDetail.DistanceMiddle);
+00296         // Compute OODistDelta and DistancePow
+00297         _LevelDetail.compileDistanceSetup();
+00298 
+00299 
+00300         // Build the _LodInfos.
+00301         //================================================
+00302         _LodInfos.resize(_Lods.size());
+00303         uint32  precNWedges= 0;
+00304         uint    i;
+00305         for(i=0;i<_Lods.size();i++)
+00306         {
+00307                 _LodInfos[i].StartAddWedge= precNWedges;
+00308                 _LodInfos[i].EndAddWedges= _Lods[i].NWedges;
+00309                 precNWedges= _Lods[i].NWedges;
+00310                 // LodOffset is filled in serial() when stream is input.
+00311         }
+00312         // After build, all lods are present in memory. 
+00313         _NbLodLoaded= _Lods.size();
+00314 
+00315 
+00316         // For load balancing.
+00317         //================================================
+00318         // compute Max Face Used
+00319         _LevelDetail.MaxFaceUsed= 0;
+00320         _LevelDetail.MinFaceUsed= 0;
+00321         // Count of primitive block
+00322         if(_Lods.size()>0)
+00323         {
+00324                 uint    pb;
+00325                 // Compute MinFaces.
+00326                 CLod    &firstLod= _Lods[0];
+00327                 for (pb=0; pb<firstLod.RdrPass.size(); pb++)
+00328                 {
+00329                         CRdrPass &pass= firstLod.RdrPass[pb];
+00330                         // Sum tri
+00331                         _LevelDetail.MinFaceUsed+= pass.PBlock.getNumTriangles ();
+00332                 }
+00333                 // Compute MaxFaces.
+00334                 CLod    &lastLod= _Lods[_Lods.size()-1];
+00335                 for (pb=0; pb<lastLod.RdrPass.size(); pb++)
+00336                 {
+00337                         CRdrPass &pass= lastLod.RdrPass[pb];
+00338                         // Sum tri
+00339                         _LevelDetail.MaxFaceUsed+= pass.PBlock.getNumTriangles ();
+00340                 }
+00341         }
+00342 
+00343 
+00344         // For skinning.
+00345         //================================================
+00346         if( _Skinned )
+00347         {
+00348                 bkupOriginalSkinVertices();
+00349         }
+00350         // Inform that the mesh data has changed
+00351         dirtMeshDataId();
+00352 
+00353 
+00354         // For AGP SKinning optim, and for Render optim
+00355         //================================================
+00356         for(i=0;i<_Lods.size();i++)
+00357         {
+00358                 _Lods[i].buildSkinVertexBlocks();
+00359                 // sort triangles for better cache use.
+00360                 _Lods[i].optimizeTriangleOrder();
+00361         }
+00362 
+00363         // Copy Blend Shapes
+00364         //================================================      
+00365         _MeshMorpher.BlendShapes = meshBuildMRM.BlendShapes;
+00366         
+00367 
+00368         // Compact bone id and build a bone id names
+00369         //================================================      
+00370 
+00371         // Skinned ?
+00372         if (_Skinned)
+00373         {
+00374                 // Remap
+00375                 std::map<uint, uint> remap;
+00376 
+00377                 // Current bone
+00378                 uint currentBone = 0;
+00379 
+00380                 // Reserve memory
+00381                 _BonesName.reserve (m.BonesNames.size());
+00382 
+00383                 // For each vertices
+00384                 uint vert;
+00385                 for (vert=0; vert<_SkinWeights.size(); vert++)
+00386                 {
+00387                         // Found one ?
+00388                         bool found=false;
+00389                         
+00390                         // For each weight
+00391                         uint weight;
+00392                         for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
+00393                         {
+00394                                 // Active ?
+00395                                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
+00396                                 {
+00397                                         // Look for it
+00398                                         std::map<uint, uint>::iterator ite = remap.find (_SkinWeights[vert].MatrixId[weight]);
+00399 
+00400                                         // Find ?
+00401                                         if (ite == remap.end())
+00402                                         {
+00403                                                 // Insert it
+00404                                                 remap.insert (std::map<uint, uint>::value_type (_SkinWeights[vert].MatrixId[weight], currentBone));
+00405 
+00406                                                 // Check the id
+00407                                                 nlassert (_SkinWeights[vert].MatrixId[weight]<m.BonesNames.size());
+00408 
+00409                                                 // Set the bone name
+00410                                                 _BonesName.push_back (m.BonesNames[_SkinWeights[vert].MatrixId[weight]]);
+00411 
+00412                                                 // Set the local bone id
+00413                                                 _SkinWeights[vert].MatrixId[weight] = currentBone++;
+00414                                         }
+00415                                         else
+00416                                         {
+00417                                                 // Set the local bone id
+00418                                                 _SkinWeights[vert].MatrixId[weight] = ite->second;
+00419                                         }
+00420 
+00421                                         // Found one
+00422                                         found = true;
+00423                                 }
+00424                         }
+00425 
+00426                         // Found one ?
+00427                         nlassert (found);
+00428                 }
+00429 
+00430                 // Remap the vertex influence by lods
+00431                 uint lod;
+00432                 for (lod=0; lod<_Lods.size(); lod++)
+00433                 {
+00434                         // For each matrix used
+00435                         uint matrix;
+00436                         for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
+00437                         {
+00438                                 // Remap
+00439                                 std::map<uint, uint>::iterator ite = remap.find (_Lods[lod].MatrixInfluences[matrix]);
+00440 
+00441                                 // Find ?
+00442                                 nlassert (ite != remap.end());
+00443 
+00444                                 // Remap
+00445                                 _Lods[lod].MatrixInfluences[matrix] = ite->second;
+00446                         }
+00447                 }
+00448         }
+00449 
+00450         // Misc.
+00451         //===================
+00452         // Some runtime not serialized compilation
+00453         compileRunTime();
+00454 
+00455 }
+00456 
+00457 // ***************************************************************************
+00458 void    CMeshMRMGeom::applyMaterialRemap(const std::vector<sint> &remap)
+00459 {
+00460         for(uint lod=0;lod<getNbLod();lod++)
+00461         {
+00462                 for(uint rp=0;rp<getNbRdrPass(lod);rp++)
+00463                 {
+00464                         // remap
+00465                         uint32  &matId= _Lods[lod].RdrPass[rp].MaterialId;
+00466                         nlassert(remap[matId]>=0);
+00467                         matId= remap[matId];
+00468                 }
+00469         }
+00470 }
+00471 
+00472 // ***************************************************************************
+00473 void    CMeshMRMGeom::applyGeomorph(std::vector<CMRMWedgeGeom>  &geoms, float alphaLod, IVertexBufferHard *currentVBHard)
+00474 {
+00475         if(currentVBHard!=NULL)
+00476         {
+00477                 // must write into it
+00478                 uint8   *vertexDestPtr= (uint8*)currentVBHard->lock();
+00479                 nlassert(_VBufferFinal.getVertexSize() == currentVBHard->getVertexSize());
+00480 
+00481                 // apply the geomorph
+00482                 applyGeomorphWithVBHardPtr(geoms, alphaLod, vertexDestPtr);
+00483 
+00484                 // unlock. ATI: copy only geomorphed vertices.
+00485                 currentVBHard->unlock(0, geoms.size());
+00486         }
+00487         else
+00488                 applyGeomorphWithVBHardPtr(geoms, alphaLod, NULL);
+00489 
+00490 }
+00491 
+00492 
+00493 // ***************************************************************************
+00494 void    CMeshMRMGeom::applyGeomorphWithVBHardPtr(std::vector<CMRMWedgeGeom>  &geoms, float alphaLod, uint8 *vertexDestPtr)
+00495 {
+00496         // no geomorphs? quit.
+00497         if(geoms.size()==0)
+00498                 return;
+00499 
+00500         uint            i;
+00501         clamp(alphaLod, 0.f, 1.f);
+00502         float           a= alphaLod;
+00503         float           a1= 1 - alphaLod;
+00504         uint            ua= (uint)(a*256);
+00505         clamp(ua, (uint)0, (uint)256);
+00506         uint            ua1= 256 - ua;
+00507 
+00508 
+00509         // info from VBuffer.
+00510         uint8           *vertexPtr= (uint8*)_VBufferFinal.getVertexCoordPointer();
+00511         uint            flags= _VBufferFinal.getVertexFormat();
+00512         sint32          vertexSize= _VBufferFinal.getVertexSize();
+00513         // because of the unrolled code for 4 first UV, must assert this.
+00514         nlassert(CVertexBuffer::MaxStage>=4);
+00515         // must have XYZ.
+00516         nlassert(flags & CVertexBuffer::PositionFlag);
+00517 
+00518 
+00519         // If VBuffer Hard disabled
+00520         if(vertexDestPtr==NULL)
+00521         {
+00522                 // write into vertexPtr.
+00523                 vertexDestPtr= vertexPtr;
+00524         }
+00525 
+00526 
+00527         // if it is a common format
+00528         if( flags== (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag) &&
+00529                 _VBufferFinal.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2 )
+00530         {
+00531                 // use a faster method
+00532                 applyGeomorphPosNormalUV0(geoms, vertexPtr, vertexDestPtr, vertexSize, a, a1);
+00533         }
+00534         else
+00535         {
+00536                 // if an offset is 0, it means that the component is not in the VBuffer.
+00537                 sint32          normalOff;
+00538                 sint32          colorOff;
+00539                 sint32          specularOff;
+00540                 sint32          uvOff[CVertexBuffer::MaxStage];
+00541                 bool            has3Coords[CVertexBuffer::MaxStage];
+00542 
+00543 
+00544                 // Compute offset of each component of the VB.
+00545                 if(flags & CVertexBuffer::NormalFlag)
+00546                         normalOff= _VBufferFinal.getNormalOff();
+00547                 else
+00548                         normalOff= 0;
+00549                 if(flags & CVertexBuffer::PrimaryColorFlag)
+00550                         colorOff= _VBufferFinal.getColorOff();
+00551                 else
+00552                         colorOff= 0;
+00553                 if(flags & CVertexBuffer::SecondaryColorFlag)
+00554                         specularOff= _VBufferFinal.getSpecularOff();
+00555                 else
+00556                         specularOff= 0;
+00557                         
+00558                 for(i= 0; i<CVertexBuffer::MaxStage;i++)
+00559                 {
+00560                         if(flags & (CVertexBuffer::TexCoord0Flag<<i))
+00561                         {
+00562                                 uvOff[i]= _VBufferFinal.getTexCoordOff(i);                      
+00563                                 has3Coords[i] = (_VBufferFinal.getValueType(i + CVertexBuffer::TexCoord0) == CVertexBuffer::Float3);
+00564                         }
+00565                         else
+00566                         {
+00567                                 uvOff[i]= 0;
+00568                         }
+00569                 }
+00570 
+00571 
+00572                 // For all geomorphs.
+00573                 uint                    nGeoms= geoms.size();
+00574                 CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
+00575                 uint8                   *destPtr= vertexDestPtr;
+00576                 /* NB: optimisation: lot of "if" in this Loop, but because of BTB, they always cost nothing (prediction is good).
+00577                    NB: this also is why we unroll the 4 1st Uv. The other (if any), are done in the other loop.
+00578                    NB: optimisation for AGP write cominers: the order of write (vertex, normal, uvs...) is important for good
+00579                    use of AGP write combiners.
+00580                    We have 2 version : one that tests for 3 coordinates texture coords, and one that doesn't
+00581                 */
+00582 
+00583                 if (!has3Coords[0] && !has3Coords[1] && !has3Coords[2] && !has3Coords[3])
+00584                 {
+00585                         // there are no texture coordinate of dimension 3
+00586                         for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
+00587                         {
+00588                                 uint8                   *startPtr=      vertexPtr + ptrGeom->Start*vertexSize;
+00589                                 uint8                   *endPtr=        vertexPtr + ptrGeom->End*vertexSize;
+00590 
+00591                                 // Vertex.
+00592                                 {
+00593                                         CVector         *start= (CVector*)startPtr;
+00594                                         CVector         *end=   (CVector*)endPtr;
+00595                                         CVector         *dst=   (CVector*)destPtr;
+00596                                         *dst= *start * a + *end * a1;
+00597                                 }
+00598 
+00599                                 // Normal.
+00600                                 if(normalOff)
+00601                                 {
+00602                                         CVector         *start= (CVector*)(startPtr + normalOff);
+00603                                         CVector         *end=   (CVector*)(endPtr   + normalOff);
+00604                                         CVector         *dst=   (CVector*)(destPtr  + normalOff);
+00605                                         *dst= *start * a + *end * a1;
+00606                                 }
+00607 
+00608 
+00609                                 // Uvs.
+00610                                 // uv[0].
+00611                                 if(uvOff[0])
+00612                                 {                               
+00613                                         // Uv.
+00614                                         CUV                     *start= (CUV*)(startPtr + uvOff[0]);
+00615                                         CUV                     *end=   (CUV*)(endPtr   + uvOff[0]);
+00616                                         CUV                     *dst=   (CUV*)(destPtr  + uvOff[0]);
+00617                                         *dst= *start * a + *end * a1;                           
+00618                                 }
+00619                                 // uv[1].
+00620                                 if(uvOff[1])
+00621                                 {                               
+00622                                         // Uv.
+00623                                         CUV                     *start= (CUV*)(startPtr + uvOff[1]);
+00624                                         CUV                     *end=   (CUV*)(endPtr   + uvOff[1]);
+00625                                         CUV                     *dst=   (CUV*)(destPtr  + uvOff[1]);
+00626                                         *dst= *start * a + *end * a1;                           
+00627                                 }
+00628                                 // uv[2].
+00629                                 if(uvOff[2])
+00630                                 {                               
+00631                                         CUV                     *start= (CUV*)(startPtr + uvOff[2]);
+00632                                         CUV                     *end=   (CUV*)(endPtr   + uvOff[2]);
+00633                                         CUV                     *dst=   (CUV*)(destPtr  + uvOff[2]);
+00634                                         *dst= *start * a + *end * a1;                           
+00635                                 }
+00636                                 // uv[3].
+00637                                 if(uvOff[3])
+00638                                 {                               
+00639                                         // Uv.
+00640                                         CUV                     *start= (CUV*)(startPtr + uvOff[3]);
+00641                                         CUV                     *end=   (CUV*)(endPtr   + uvOff[3]);
+00642                                         CUV                     *dst=   (CUV*)(destPtr  + uvOff[3]);
+00643                                         *dst= *start * a + *end * a1;                           
+00644                                 }
+00645                         }
+00646                 }
+00647                 else // THERE ARE TEXTURE COORDINATES OF DIMENSION 3
+00648                 {
+00649                         for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
+00650                         {
+00651                                 uint8                   *startPtr=      vertexPtr + ptrGeom->Start*vertexSize;
+00652                                 uint8                   *endPtr=        vertexPtr + ptrGeom->End*vertexSize;
+00653 
+00654                                 // Vertex.
+00655                                 {
+00656                                         CVector         *start= (CVector*)startPtr;
+00657                                         CVector         *end=   (CVector*)endPtr;
+00658                                         CVector         *dst=   (CVector*)destPtr;
+00659                                         *dst= *start * a + *end * a1;
+00660                                 }
+00661 
+00662                                 // Normal.
+00663                                 if(normalOff)
+00664                                 {
+00665                                         CVector         *start= (CVector*)(startPtr + normalOff);
+00666                                         CVector         *end=   (CVector*)(endPtr   + normalOff);
+00667                                         CVector         *dst=   (CVector*)(destPtr  + normalOff);
+00668                                         *dst= *start * a + *end * a1;
+00669                                 }
+00670                                 // Uvs.
+00671                                 // uv[0].
+00672                                 if(uvOff[0])
+00673                                 {
+00674                                         if (!has3Coords[0])
+00675                                         {
+00676                                                 // Uv.
+00677                                                 CUV                     *start= (CUV*)(startPtr + uvOff[0]);
+00678                                                 CUV                     *end=   (CUV*)(endPtr   + uvOff[0]);
+00679                                                 CUV                     *dst=   (CUV*)(destPtr  + uvOff[0]);
+00680                                                 *dst= *start * a + *end * a1;
+00681                                         }
+00682                                         else
+00683                                         {
+00684                                                 // Uv.
+00685                                                 CUVW            *start= (CUVW*)(startPtr + uvOff[0]);
+00686                                                 CUVW            *end=   (CUVW*)(endPtr   + uvOff[0]);
+00687                                                 CUVW            *dst=   (CUVW*)(destPtr  + uvOff[0]);
+00688                                                 *dst= *start * a + *end * a1;
+00689                                         }
+00690                                 }
+00691                                 // uv[1].
+00692                                 if(uvOff[1])
+00693                                 {
+00694                                         if (!has3Coords[1])
+00695                                         {
+00696                                                 // Uv.
+00697                                                 CUV                     *start= (CUV*)(startPtr + uvOff[1]);
+00698                                                 CUV                     *end=   (CUV*)(endPtr   + uvOff[1]);
+00699                                                 CUV                     *dst=   (CUV*)(destPtr  + uvOff[1]);
+00700                                                 *dst= *start * a + *end * a1;
+00701                                         }
+00702                                         else
+00703                                         {
+00704                                                 // Uv.
+00705                                                 CUVW            *start= (CUVW*)(startPtr + uvOff[1]);
+00706                                                 CUVW            *end=   (CUVW*)(endPtr   + uvOff[1]);
+00707                                                 CUVW            *dst=   (CUVW*)(destPtr  + uvOff[1]);
+00708                                                 *dst= *start * a + *end * a1;
+00709                                         }
+00710                                 }
+00711                                 // uv[2].
+00712                                 if(uvOff[2])
+00713                                 {
+00714                                         if (!has3Coords[2])
+00715                                         {
+00716                                                 // Uv.
+00717                                                 CUV                     *start= (CUV*)(startPtr + uvOff[2]);
+00718                                                 CUV                     *end=   (CUV*)(endPtr   + uvOff[2]);
+00719                                                 CUV                     *dst=   (CUV*)(destPtr  + uvOff[2]);
+00720                                                 *dst= *start * a + *end * a1;
+00721                                         }
+00722                                         else
+00723                                         {
+00724                                                 // Uv.
+00725                                                 CUVW            *start= (CUVW*)(startPtr + uvOff[2]);
+00726                                                 CUVW            *end=   (CUVW*)(endPtr   + uvOff[2]);
+00727                                                 CUVW            *dst=   (CUVW*)(destPtr  + uvOff[2]);
+00728                                                 *dst= *start * a + *end * a1;
+00729                                         }
+00730                                 }
+00731                                 // uv[3].
+00732                                 if(uvOff[3])
+00733                                 {
+00734                                         if (!has3Coords[3])
+00735                                         {
+00736                                                 // Uv.
+00737                                                 CUV                     *start= (CUV*)(startPtr + uvOff[3]);
+00738                                                 CUV                     *end=   (CUV*)(endPtr   + uvOff[3]);
+00739                                                 CUV                     *dst=   (CUV*)(destPtr  + uvOff[3]);
+00740                                                 *dst= *start * a + *end * a1;
+00741                                         }
+00742                                         else
+00743                                         {
+00744                                                 // Uv.
+00745                                                 CUVW            *start= (CUVW*)(startPtr + uvOff[3]);
+00746                                                 CUVW            *end=   (CUVW*)(endPtr   + uvOff[3]);
+00747                                                 CUVW            *dst=   (CUVW*)(destPtr  + uvOff[3]);
+00748                                                 *dst= *start * a + *end * a1;
+00749                                         }
+00750                                 }
+00751                                 // color.
+00752                                 if(colorOff)
+00753                                 {
+00754                                         CRGBA           *start= (CRGBA*)(startPtr + colorOff);
+00755                                         CRGBA           *end=   (CRGBA*)(endPtr   + colorOff);
+00756                                         CRGBA           *dst=   (CRGBA*)(destPtr  + colorOff);
+00757                                         dst->blendFromui(*start, *end,  ua1);
+00758                                 }
+00759                                 // specular.
+00760                                 if(specularOff)
+00761                                 {
+00762                                         CRGBA           *start= (CRGBA*)(startPtr + specularOff);
+00763                                         CRGBA           *end=   (CRGBA*)(endPtr   + specularOff);
+00764                                         CRGBA           *dst=   (CRGBA*)(destPtr  + specularOff);
+00765                                         dst->blendFromui(*start, *end,  ua1);
+00766                                 }
+00767                         }
+00768                 }
+00769 
+00770 
+00771                 // Process extra UVs (maybe never, so don't bother optims :)).
+00772                 // For all stages after 4.
+00773                 for(i=4;i<CVertexBuffer::MaxStage;i++)
+00774                 {
+00775                         uint                    nGeoms= geoms.size();
+00776                         CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
+00777                         uint8                   *destPtr= vertexDestPtr;
+00778 
+00779                         if(uvOff[i]==0)
+00780                                 continue;
+00781 
+00782                         // For all geomorphs.
+00783                         for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
+00784                         {
+00785                                 uint8                   *startPtr=      vertexPtr + ptrGeom->Start*vertexSize;
+00786                                 uint8                   *endPtr=        vertexPtr + ptrGeom->End*vertexSize;
+00787 
+00788                                 // uv[i].
+00789                                 // Uv.
+00790                                 if (!has3Coords[i])
+00791                                 {
+00792                                         CUV                     *start= (CUV*)(startPtr + uvOff[i]);
+00793                                         CUV                     *end=   (CUV*)(endPtr   + uvOff[i]);
+00794                                         CUV                     *dst=   (CUV*)(destPtr  + uvOff[i]);
+00795                                         *dst= *start * a + *end * a1;
+00796                                 }
+00797                                 else
+00798                                 {
+00799                                         CUVW            *start= (CUVW*)(startPtr + uvOff[i]);
+00800                                         CUVW            *end=   (CUVW*)(endPtr  + uvOff[i]);
+00801                                         CUVW            *dst=   (CUVW*)(destPtr + uvOff[i]);
+00802                                         *dst= *start * a + *end * a1;
+00803                                 }
+00804                         }
+00805                 }
+00806         }
+00807 }
+00808 
+00809 
+00810 // ***************************************************************************
+00811 void    CMeshMRMGeom::applyGeomorphPosNormalUV0(std::vector<CMRMWedgeGeom>  &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, float a, float a1)
+00812 {
+00813         nlassert(vertexSize==32);
+00814 
+00815 
+00816         // For all geomorphs.
+00817         uint                    nGeoms= geoms.size();
+00818         CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
+00819         uint8                   *destPtr= vertexDestPtr;
+00820         for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
+00821         {
+00822                 // Consider the Pos/Normal/UV as an array of 8 float to interpolate.
+00823                 float                   *start= (float*)(vertexPtr + (ptrGeom->Start<<5));
+00824                 float                   *end=   (float*)(vertexPtr + (ptrGeom->End<<5));
+00825                 float                   *dst=   (float*)(destPtr);
+00826 
+00827                 // unrolled
+00828                 dst[0]= start[0] * a + end[0]* a1;
+00829                 dst[1]= start[1] * a + end[1]* a1;
+00830                 dst[2]= start[2] * a + end[2]* a1;
+00831                 dst[3]= start[3] * a + end[3]* a1;
+00832                 dst[4]= start[4] * a + end[4]* a1;
+00833                 dst[5]= start[5] * a + end[5]* a1;
+00834                 dst[6]= start[6] * a + end[6]* a1;
+00835                 dst[7]= start[7] * a + end[7]* a1;
+00836         }
+00837 }
+00838 
+00839 
+00840 // ***************************************************************************
+00841 void    CMeshMRMGeom::initInstance(CMeshBaseInstance *mbi)
+00842 {
+00843         // init the instance with _MeshVertexProgram infos
+00844         if(_MeshVertexProgram)
+00845                 _MeshVertexProgram->initInstance(mbi);
+00846 }
+00847 
+00848 
+00849 // ***************************************************************************
+00850 bool    CMeshMRMGeom::clip(const std::vector<CPlane>    &pyramid, const CMatrix &worldMatrix)
+00851 {
+00852         // Speed Clip: clip just the sphere.
+00853         CBSphere        localSphere(_BBox.getCenter(), _BBox.getRadius());
+00854         CBSphere        worldSphere;
+00855 
+00856         // transform the sphere in WorldMatrix (with nearly good scale info).
+00857         localSphere.applyTransform(worldMatrix, worldSphere);
+00858 
+00859         // if out of only plane, entirely out.
+00860         for(sint i=0;i<(sint)pyramid.size();i++)
+00861         {
+00862                 // We are sure that pyramid has normalized plane normals.
+00863                 // if SpherMax OUT return false.
+00864                 float   d= pyramid[i]*worldSphere.Center;
+00865                 if(d>worldSphere.Radius)
+00866                         return false;
+00867         }
+00868 
+00869         // test if must do a precise clip, according to mesh size.
+00870         if( _PreciseClipping )
+00871         {
+00872                 CPlane  localPlane;
+00873 
+00874                 // if out of only plane, entirely out.
+00875                 for(sint i=0;i<(sint)pyramid.size();i++)
+00876                 {
+00877                         // Transform the pyramid in Object space.
+00878                         localPlane= pyramid[i]*worldMatrix;
+00879                         // localPlane must be normalized, because worldMatrix mya have a scale.
+00880                         localPlane.normalize();
+00881                         // if the box is not partially inside the plane, quit
+00882                         if( !_BBox.clipBack(localPlane) )
+00883                                 return false;
+00884                 }
+00885         }
+00886 
+00887         return true;
+00888 }
+00889 
+00890 
+00891 // ***************************************************************************
+00892 inline sint     CMeshMRMGeom::chooseLod(float alphaMRM, float &alphaLod)
+00893 {
+00894         // Choose what Lod to draw.
+00895         alphaMRM*= _Lods.size()-1;
+00896         sint    numLod= (sint)ceil(alphaMRM);
+00897         if(numLod==0)
+00898         {
+00899                 numLod= 0;
+00900                 alphaLod= 0;
+00901         }
+00902         else
+00903         {
+00904                 // Lerp beetween lod i-1 and lod i.
+00905                 alphaLod= alphaMRM-(numLod-1);
+00906         }
+00907 
+00908 
+00909         // If lod chosen is not loaded, take the best loaded.
+00910         if(numLod>=(sint)_NbLodLoaded)
+00911         {
+00912                 numLod= _NbLodLoaded-1;
+00913                 alphaLod= 1;
+00914         }
+00915 
+00916         return numLod;
+00917 }
+00918 
+00919 
+00920 // ***************************************************************************
+00921 void    CMeshMRMGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
+00922 {
+00923         nlassert(drv);
+00924         if(_Lods.size()==0)
+00925                 return;
+00926 
+00927 
+00928         // get the meshMRM instance.
+00929         CMeshBaseInstance       *mi= safe_cast<CMeshBaseInstance*>(trans);
+00930         // get a ptr on scene
+00931         CScene                          *ownerScene= mi->getScene();
+00932         // get a ptr on renderTrav
+00933         CRenderTrav                     *renderTrav= ownerScene->getRenderTrav();
+00934 
+00935 
+00936         // get the result of the Load Balancing.
+00937         float   alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
+00938 
+00939         // choose the lod.
+00940         float   alphaLod;
+00941         sint    numLod= chooseLod(alphaMRM, alphaLod);
+00942 
+00943 
+00944         // Render the choosen Lod.
+00945         CLod    &lod= _Lods[numLod];
+00946         if(lod.RdrPass.size()==0)
+00947                 return;
+00948 
+00949 
+00950         // Update the vertexBufferHard (if possible).
+00951         // \toto yoyo: TODO_OPTIMIZE: allocate only what is needed for the current Lod (Max of all instances, like
+00952         // the loading....) (see loadHeader()).
+00953         updateVertexBufferHard(drv, _VBufferFinal.getNumVertices());
+00954         /* currentVBHard is NULL if must disable it temporarily
+00955                 For now, never disable it, but switch of VBHard may be VERY EXPENSIVE if NV_vertex_array_range2 is not
+00956                 supported (old drivers).
+00957         */
+00958         IVertexBufferHard               *currentVBHard= _VBHard;
+00959 
+00960 
+00961         // get the skeleton model to which I am binded (else NULL).
+00962         CSkeletonModel *skeleton;
+00963         skeleton = mi->getSkeletonModel();
+00964         // The mesh must not be skinned for render()
+00965         nlassert(!(_Skinned && mi->isSkinned() && skeleton));
+00966         bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
+00967         bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
+00968 
+00969 
+00970         // Profiling
+00971         //===========
+00972         H_AUTO( NL3D_MeshMRMGeom_RenderNormal );
+00973 
+00974 
+00975         // Morphing
+00976         // ========
+00977         if (bMorphApplied)
+00978         {
+00979                 // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
+00980                 // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
+00981                 // are written in the preceding call to restoreOriginalSkinPart.
+00982                 if (_Skinned)
+00983                 {
+00984                         _MeshMorpher.initSkinned(&_VBufferOriginal,
+00985                                                                  &_VBufferFinal,
+00986                                                                  currentVBHard,
+00987                                                                  useTangentSpace,
+00988                                                                  &_OriginalSkinVertices,
+00989                                                                  &_OriginalSkinNormals,
+00990                                                                  useTangentSpace ? &_OriginalTGSpace : NULL,
+00991                                                                  false );
+00992                         _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
+00993                 }
+00994                 else // Not even skinned so we have to do all the stuff
+00995                 {
+00996                         _MeshMorpher.init(&_VBufferOriginal,
+00997                                                                  &_VBufferFinal,
+00998                                                                  currentVBHard,
+00999                                                                  useTangentSpace);
+01000                         _MeshMorpher.update (mi->getBlendShapeFactors());
+01001                 }
+01002         }
+01003 
+01004         // Skinning.
+01005         //===========
+01006         // if mesh is skinned (but here skin not applied), we must copy vertices/normals from original vertices.
+01007         if (_Skinned)
+01008         {
+01009                 // do it for this Lod only, and if cache say it is necessary.
+01010                 if (!lod.OriginalSkinRestored)
+01011                         restoreOriginalSkinPart(lod, currentVBHard);
+01012         }
+01013 
+01014 
+01015         // set the instance worldmatrix.
+01016         drv->setupModelMatrix(trans->getWorldMatrix());
+01017 
+01018 
+01019         // Geomorph.
+01020         //===========
+01021         // Geomorph the choosen Lod (if not the coarser mesh).
+01022         if(numLod>0)
+01023         {
+01024                 applyGeomorph(lod.Geomorphs, alphaLod, currentVBHard);
+01025         }
+01026 
+01027 
+01028         // force normalisation of normals..
+01029         bool    bkupNorm= drv->isForceNormalize();
+01030         drv->forceNormalize(true);                      
+01031 
+01032 
+01033         // Setup meshVertexProgram
+01034         //===========
+01035 
+01036         // use MeshVertexProgram effect?
+01037         bool    useMeshVP= _MeshVertexProgram != NULL;
+01038         if( useMeshVP )
+01039         {
+01040                 CMatrix         invertedObjectMatrix;
+01041                 invertedObjectMatrix = trans->getWorldMatrix().inverted();
+01042                 // really ok if success to begin VP
+01043                 useMeshVP= _MeshVertexProgram->begin(drv, mi->getScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
+01044         }
+01045         
+01046 
+01047         // Render the lod.
+01048         //===========
+01049         // active VB.
+01050         if(currentVBHard)
+01051                 drv->activeVertexBufferHard(currentVBHard);
+01052         else
+01053                 drv->activeVertexBuffer(_VBufferFinal);
+01054 
+01055 
+01056         // Global alpha used ?
+01057         uint32  globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
+01058         uint8   globalAlphaInt=(uint8)OptFastFloor(globalAlpha*255);
+01059 
+01060         // Render all pass.
+01061         if (globalAlphaUsed)
+01062         {
+01063                 bool    gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
+01064 
+01065                 // for all passes
+01066                 for(uint i=0;i<lod.RdrPass.size();i++)
+01067                 {
+01068                         CRdrPass        &rdrPass= lod.RdrPass[i];
+01069 
+01070                         if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
+01071                                  ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
+01072                         {
+01073                                 // CMaterial Ref
+01074                                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
+01075 
+01076                                 // Use a MeshBlender to modify material and driver.
+01077                                 CMeshBlender    blender;
+01078                                 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
+01079 
+01080                                 // Setup VP material
+01081                                 if (useMeshVP)
+01082                                 {
+01083                                         if(currentVBHard)
+01084                                                 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
+01085                                         else
+01086                                                 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
+01087                                 }
+01088 
+01089                                 // Render
+01090                                 drv->render(rdrPass.PBlock, material);
+01091 
+01092                                 // Resetup material/driver
+01093                                 blender.restoreRender(material, drv, gaDisableZWrite);
+01094                         }
+01095                 }
+01096         }
+01097         else
+01098         {
+01099                 for(uint i=0;i<lod.RdrPass.size();i++)
+01100                 {
+01101                         CRdrPass        &rdrPass= lod.RdrPass[i];
+01102 
+01103                         if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
+01104                                  ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
+01105                         {
+01106                                 // CMaterial Ref
+01107                                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
+01108 
+01109                                 // Setup VP material
+01110                                 if (useMeshVP)
+01111                                 {
+01112                                         if(currentVBHard)
+01113                                                 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
+01114                                         else
+01115                                                 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
+01116                                 }       
+01117 
+01118                                 // Render with the Materials of the MeshInstance.
+01119                                 drv->render(rdrPass.PBlock, material);
+01120                         }
+01121                 }
+01122         }
+01123 
+01124 
+01125         // End VertexProgram effect
+01126         if(useMeshVP)
+01127         {
+01128                 // end it.
+01129                 _MeshVertexProgram->end(drv);
+01130         }
+01131 
+01132 
+01133         // bkup force normalisation.
+01134         drv->forceNormalize(bkupNorm);
+01135 
+01136 }
+01137 
+01138 
+01139 // ***************************************************************************
+01140 void    CMeshMRMGeom::renderSkin(CTransformShape *trans, float alphaMRM)
+01141 {
+01142         if(_Lods.size()==0)
+01143                 return;
+01144 
+01145 
+01146         // get the meshMRM instance. only CMeshMRMInstance is possible when skinned (not MultiLod)
+01147         CMeshMRMInstance        *mi= safe_cast<CMeshMRMInstance*>(trans);
+01148         // get a ptr on scene
+01149         CScene                          *ownerScene= mi->getScene();
+01150         // get a ptr on renderTrav
+01151         CRenderTrav                     *renderTrav= ownerScene->getRenderTrav();
+01152         // get a ptr on the driver
+01153         IDriver                         *drv= renderTrav->getDriver();
+01154         nlassert(drv);
+01155 
+01156 
+01157         // choose the lod.
+01158         float   alphaLod;
+01159         sint    numLod= chooseLod(alphaMRM, alphaLod);
+01160 
+01161 
+01162         // Render the choosen Lod.
+01163         CLod    &lod= _Lods[numLod];
+01164         if(lod.RdrPass.size()==0)
+01165                 return;
+01166 
+01167 
+01168         /*
+01169                 YOYO: renderSkin() no more support vertexBufferHard()!!! for AGP Memory optimisation concern.
+01170                 AGP Skin rendering is made when supportSkinGrouping() is true
+01171                 Hence if a skin is to be rendered here, because it doesn't have a good vertex format, or it has
+01172                 MeshVertexProgram etc..., it will be rendered WITHOUT VBHard => slower.
+01173         */
+01174 
+01175 
+01176         // get the skeleton model to which I am skinned
+01177         CSkeletonModel *skeleton;
+01178         skeleton = mi->getSkeletonModel();
+01179         // must be skinned for renderSkin()
+01180         nlassert(_Skinned && mi->isSkinned() && skeleton);
+01181         bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
+01182         bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
+01183         bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
+01184 
+01185 
+01186         // Profiling
+01187         //===========
+01188         H_AUTO_USE( NL3D_MeshMRMGeom_RenderSkinned );
+01189 
+01190 
+01191         // Morphing
+01192         // ========
+01193         if (bMorphApplied)
+01194         {
+01195                 // Since Skinned we must update original skin vertices and normals because skinning use it
+01196                 _MeshMorpher.initSkinned(&_VBufferOriginal,
+01197                                                          &_VBufferFinal,
+01198                                                          NULL,
+01199                                                          useTangentSpace,
+01200                                                          &_OriginalSkinVertices,
+01201                                                          &_OriginalSkinNormals,
+01202                                                          useTangentSpace ? &_OriginalTGSpace : NULL,
+01203                                                          true );
+01204                 _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
+01205         }
+01206 
+01207         // Skinning.
+01208         //===========
+01209 
+01210         // Use RawSkin if possible: only if no morph, and only Vertex/Normal
+01211         updateRawSkinNormal(!bMorphApplied && !useTangentSpace && useNormal, mi, numLod);
+01212 
+01213         // applySkin.
+01214         //--------
+01215 
+01216         // If skin without normal (rare/usefull?) always simple (slow) case.
+01217         if(!useNormal)
+01218         {
+01219                 // skinning with just position
+01220                 applySkin (lod, skeleton);
+01221         }
+01222         else
+01223         {
+01224                 // Use SSE when possible
+01225                 if( CSystemInfo::hasSSE() )
+01226                 {
+01227                         // apply skin for this Lod only.
+01228                         if (!useTangentSpace)
+01229                         {
+01230                                 // skinning with normal, but no tangent space
+01231                                 if(mi->_RawSkinCache)
+01232                                         // Use faster RawSkin if possible.
+01233                                         applyRawSkinWithNormalSSE(lod, *(mi->_RawSkinCache), skeleton);
+01234                                 else
+01235                                         applySkinWithNormalSSE (lod, skeleton);
+01236                         }
+01237                         else
+01238                         {
+01239                                 // Tangent space stored in the last texture coordinate
+01240                                 applySkinWithTangentSpaceSSE(lod, skeleton, _VBufferFinal.getNumTexCoordUsed() - 1);
+01241                         }
+01242                 }
+01243                 // Standard FPU skinning
+01244                 else
+01245                 {
+01246                         // apply skin for this Lod only.
+01247                         if (!useTangentSpace)
+01248                         {
+01249                                 // skinning with normal, but no tangent space
+01250                                 if(mi->_RawSkinCache)
+01251                                         // Use faster RawSkin if possible.
+01252                                         applyRawSkinWithNormal (lod, *(mi->_RawSkinCache), skeleton);
+01253                                 else
+01254                                         applySkinWithNormal (lod, skeleton);
+01255                         }
+01256                         else
+01257                         {
+01258                                 // Tangent space stored in the last texture coordinate
+01259                                 applySkinWithTangentSpace(lod, skeleton, _VBufferFinal.getNumTexCoordUsed() - 1);
+01260                         }
+01261                 }
+01262         }
+01263 
+01264         // endSkin.
+01265         //--------
+01266         // dirt this lod part. (NB: this is not optimal, but sufficient :) ).
+01267         lod.OriginalSkinRestored= false;
+01268 
+01269 
+01270         // NB: the skeleton matrix has already been setuped by CSkeletonModel
+01271         // NB: the normalize flag has already been setuped by CSkeletonModel
+01272 
+01273 
+01274         // Geomorph.
+01275         //===========
+01276         // Geomorph the choosen Lod (if not the coarser mesh).
+01277         if(numLod>0)
+01278         {
+01279                 applyGeomorph(lod.Geomorphs, alphaLod, NULL);
+01280         }
+01281 
+01282 
+01283         // Setup meshVertexProgram
+01284         //===========
+01285 
+01286         // use MeshVertexProgram effect?
+01287         bool    useMeshVP= _MeshVertexProgram != NULL;
+01288         if( useMeshVP )
+01289         {
+01290                 CMatrix         invertedObjectMatrix;
+01291                 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
+01292                 // really ok if success to begin VP
+01293                 useMeshVP= _MeshVertexProgram->begin(drv, mi->getScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
+01294         }
+01295         
+01296 
+01297         // Render the lod.
+01298         //===========
+01299         // active VB.
+01300         drv->activeVertexBuffer(_VBufferFinal);
+01301 
+01302 
+01303         // Render all pass.
+01304         for(uint i=0;i<lod.RdrPass.size();i++)
+01305         {
+01306                 CRdrPass        &rdrPass= lod.RdrPass[i];
+01307 
+01308                 // CMaterial Ref
+01309                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
+01310 
+01311                 // Setup VP material
+01312                 if (useMeshVP)
+01313                 {
+01314                         _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
+01315                 }
+01316 
+01317                 // Render with the Materials of the MeshInstance.
+01318                 drv->render(rdrPass.PBlock, material);
+01319         }
+01320 
+01321         // End VertexProgram effect
+01322         if(useMeshVP)
+01323         {
+01324                 // end it.
+01325                 _MeshVertexProgram->end(drv);
+01326         }
+01327 }
+01328 
+01329 
+01330 // ***************************************************************************
+01331 bool    CMeshMRMGeom::supportSkinGrouping() const
+01332 {
+01333         return _SupportSkinGrouping;
+01334 }
+01335 
+01336 // ***************************************************************************
+01337 sint    CMeshMRMGeom::renderSkinGroupGeom(CMeshMRMInstance      *mi, float alphaMRM, uint remainingVertices, uint8 *vbDest)
+01338 {
+01339         // get a ptr on scene
+01340         CScene                          *ownerScene= mi->getScene();
+01341         // get a ptr on renderTrav
+01342         CRenderTrav                     *renderTrav= ownerScene->getRenderTrav();
+01343         // get a ptr on the driver
+01344         IDriver                         *drv= renderTrav->getDriver();
+01345         nlassert(drv);
+01346 
+01347 
+01348         // choose the lod.
+01349         float   alphaLod;
+01350         sint    numLod= chooseLod(alphaMRM, alphaLod);
+01351         _LastLodComputed= numLod;
+01352 
+01353 
+01354         // Render the choosen Lod.
+01355         CLod    &lod= _Lods[numLod];
+01356         if(lod.RdrPass.size()==0)
+01357                 // return no vertices added
+01358                 return 0;
+01359 
+01360         // If the Lod is too big to render in the VBufferHard
+01361         if(lod.NWedges>remainingVertices)
+01362                 // return Failure
+01363                 return -1;
+01364 
+01365         // get the skeleton model to which I am skinned
+01366         CSkeletonModel *skeleton;
+01367         skeleton = mi->getSkeletonModel();
+01368         // must be skinned for renderSkin()
+01369         nlassert(_Skinned && mi->isSkinned() && skeleton);
+01370         bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
+01371         bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
+01372         nlassert(useNormal);
+01373 
+01374 
+01375         // Profiling
+01376         //===========
+01377         H_AUTO_USE( NL3D_MeshMRMGeom_RenderSkinned );
+01378 
+01379 
+01380         // Morphing
+01381         // ========
+01382         if (bMorphApplied)
+01383         {
+01384                 // Since Skinned we must update original skin vertices and normals because skinning use it
+01385                 // NB: no need to setup vertexBufferHard, because not update in SkinningMode, but if the skin is not applied,
+01386                 // which is not the case here
+01387                 _MeshMorpher.initSkinned(&_VBufferOriginal,
+01388                                                          &_VBufferFinal,
+01389                                                          NULL,
+01390                                                          false,
+01391                                                          &_OriginalSkinVertices,
+01392                                                          &_OriginalSkinNormals,
+01393                                                          NULL,
+01394                                                          true );
+01395                 _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
+01396         }
+01397 
+01398         // Skinning.
+01399         //===========
+01400 
+01401         // Use RawSkin if possible: only if no morph, and only Vertex/Normal
+01402         updateRawSkinNormal(!bMorphApplied, mi, numLod);
+01403 
+01404         // applySkin.
+01405         //--------
+01406 
+01407         // Use SSE when possible
+01408         if( CSystemInfo::hasSSE() )
+01409         {
+01410                 // skinning with normal, but no tangent space
+01411                 if(mi->_RawSkinCache)
+01412                         // Use faster RawSkin if possible.
+01413                         applyRawSkinWithNormalSSE(lod, *(mi->_RawSkinCache), skeleton);
+01414                 else
+01415                         applySkinWithNormalSSE (lod, skeleton);
+01416         }
+01417         // Standard FPU skinning
+01418         else
+01419         {
+01420                 // skinning with normal, but no tangent space
+01421                 if(mi->_RawSkinCache)
+01422                         // Use faster RawSkin if possible.
+01423                         applyRawSkinWithNormal (lod, *(mi->_RawSkinCache), skeleton);
+01424                 else
+01425                         applySkinWithNormal (lod, skeleton);
+01426         }
+01427 
+01428         // endSkin.
+01429         //--------
+01430         // Fill the usefull AGP memory (if any one loaded/Used).
+01431         fillAGPSkinPartWithVBHardPtr(lod, vbDest);
+01432         // dirt this lod part. (NB: this is not optimal, but sufficient :) ).
+01433         lod.OriginalSkinRestored= false;
+01434 
+01435 
+01436         // NB: the skeleton matrix has already been setuped by CSkeletonModel
+01437         // NB: the normalize flag has already been setuped by CSkeletonModel
+01438 
+01439 
+01440         // Geomorph.
+01441         //===========
+01442         // Geomorph the choosen Lod (if not the coarser mesh).
+01443         if(numLod>0)
+01444         {
+01445                 applyGeomorphWithVBHardPtr(lod.Geomorphs, alphaLod, vbDest);
+01446         }
+01447 
+01448         // How many vertices are added to the VBuffer ???
+01449         return lod.NWedges;
+01450 }
+01451 
+01452 // ***************************************************************************
+01453 void    CMeshMRMGeom::renderSkinGroupPrimitives(CMeshMRMInstance        *mi, uint baseVertex)
+01454 {
+01455         // get a ptr on scene
+01456         CScene                          *ownerScene= mi->getScene();
+01457         // get a ptr on renderTrav
+01458         CRenderTrav                     *renderTrav= ownerScene->getRenderTrav();
+01459         // get a ptr on the driver
+01460         IDriver                         *drv= renderTrav->getDriver();
+01461         nlassert(drv);
+01462 
+01463         // Get the lod choosen in renderSkinGroupGeom()
+01464         CLod    &lod= _Lods[_LastLodComputed];
+01465 
+01466 
+01467         // Profiling
+01468         //===========
+01469         H_AUTO_USE( NL3D_MeshMRMGeom_RenderSkinned );
+01470 
+01471         // must update primitive cache
+01472         updateShiftedTriangleCache(mi, _LastLodComputed, baseVertex);
+01473         nlassert(mi->_ShiftedTriangleCache);
+01474 
+01475         // Render Quad or line, if needed (Yoyo: maybe never :/)
+01476         //===========
+01477         if(mi->_ShiftedTriangleCache->HasQuadOrLine)
+01478         {
+01479                 for(uint i=0;i<lod.RdrPass.size();i++)
+01480                 {
+01481                         CRdrPass        &rdrPass= lod.RdrPass[i];
+01482 
+01483                         // CMaterial Ref
+01484                         CMaterial &material=mi->Materials[rdrPass.MaterialId];
+01485 
+01486 
+01487                         // Compute a PBlock (static to avoid reallocation) shifted to baseVertex
+01488                         static  CPrimitiveBlock         dstPBlock;
+01489                         dstPBlock.setNumLine(0);
+01490                         dstPBlock.setNumQuad(0);
+01491                         // Lines.
+01492                         uint    numLines= rdrPass.PBlock.getNumLine();
+01493                         if(numLines)
+01494                         {
+01495                                 uint    nIds= numLines*2;
+01496                                 // allocate, in the tmp buffer
+01497                                 dstPBlock.setNumLine(numLines);
+01498                                 // index, and fill
+01499                                 uint32  *pSrcLine= rdrPass.PBlock.getLinePointer();
+01500                                 uint32  *pDstLine= dstPBlock.getLinePointer();
+01501                                 for(;nIds>0;nIds--,pSrcLine++,pDstLine++)
+01502                                         *pDstLine= *pSrcLine + baseVertex;
+01503                         }
+01504                         // Quads
+01505                         uint    numQuads= rdrPass.PBlock.getNumQuad();
+01506                         if(numQuads)
+01507                         {
+01508                                 uint    nIds= numQuads*4;
+01509                                 // allocate, in the tmp buffer
+01510                                 dstPBlock.setNumQuad(numQuads);
+01511                                 // index, and fill
+01512                                 uint32  *pSrcQuad= rdrPass.PBlock.getQuadPointer();
+01513                                 uint32  *pDstQuad= dstPBlock.getQuadPointer();
+01514                                 for(;nIds>0;nIds--,pSrcQuad++,pDstQuad++)
+01515                                         *pDstQuad= *pSrcQuad + baseVertex;
+01516                         }
+01517 
+01518 
+01519                         // Render with the Materials of the MeshInstance.
+01520                         drv->render(dstPBlock, material);
+01521                 }
+01522         }
+01523 
+01524         // Render Triangles with cache
+01525         //===========
+01526         for(uint i=0;i<lod.RdrPass.size();i++)
+01527         {
+01528                 CRdrPass        &rdrPass= lod.RdrPass[i];
+01529 
+01530                 // CMaterial Ref
+01531                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
+01532 
+01533                 // Get the shifted triangles.
+01534                 CShiftedTriangleCache::CRdrPass         &shiftedRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
+01535 
+01536                 // This speed up 4 ms for 80K polys.
+01537                 uint    memToCache= shiftedRdrPass.NumTriangles*12;
+01538                 memToCache= min(memToCache, 4096U);
+01539                 CFastMem::precache(shiftedRdrPass.Triangles, memToCache);
+01540 
+01541                 // Render with the Materials of the MeshInstance.
+01542                 drv->renderTriangles(material, shiftedRdrPass.Triangles, shiftedRdrPass.NumTriangles);
+01543         }
+01544 }
+01545 
+01546 
+01547 // ***************************************************************************
+01548 void    CMeshMRMGeom::updateShiftedTriangleCache(CMeshMRMInstance *mi, sint curLodId, uint baseVertex)
+01549 {
+01550         // if the instance has a cache, but not sync to us, delete it.
+01551         if( mi->_ShiftedTriangleCache && (
+01552                 mi->_ShiftedTriangleCache->MeshDataId != _MeshDataId ||
+01553                 mi->_ShiftedTriangleCache->LodId != curLodId ||
+01554                 mi->_ShiftedTriangleCache->BaseVertex != baseVertex) )
+01555         {
+01556                 mi->clearShiftedTriangleCache();
+01557         }
+01558 
+01559         // If the instance has not a valid cache, must create it.
+01560         if( !mi->_ShiftedTriangleCache )
+01561         {
+01562                 mi->_ShiftedTriangleCache= new CShiftedTriangleCache;
+01563                 // Fill the cache Key.
+01564                 mi->_ShiftedTriangleCache->MeshDataId= _MeshDataId;
+01565                 mi->_ShiftedTriangleCache->LodId= curLodId;
+01566                 mi->_ShiftedTriangleCache->BaseVertex= baseVertex;
+01567 
+01568                 // Default.
+01569                 mi->_ShiftedTriangleCache->HasQuadOrLine= false;
+01570 
+01571                 // Build RdrPass
+01572                 CLod    &lod= _Lods[curLodId];
+01573                 mi->_ShiftedTriangleCache->RdrPass.resize(lod.RdrPass.size());
+01574 
+01575                 // First pass, count number of triangles, and fill header info
+01576                 uint    totalTri= 0;
+01577                 uint    i;
+01578                 for(i=0;i<lod.RdrPass.size();i++)
+01579                 {
+01580                         CRdrPass        &srcRdrPass= lod.RdrPass[i];
+01581                         mi->_ShiftedTriangleCache->RdrPass[i].NumTriangles= srcRdrPass.PBlock.getNumTri();
+01582                         totalTri+= srcRdrPass.PBlock.getNumTri();
+01583                         // Has quad or line??
+01584                         if( srcRdrPass.PBlock.getNumQuad() || srcRdrPass.PBlock.getNumLine() )
+01585                                 // Yes => must inform the cache
+01586                                 mi->_ShiftedTriangleCache->HasQuadOrLine= true;
+01587                 }
+01588 
+01589                 // Allocate triangles indices.
+01590                 mi->_ShiftedTriangleCache->RawIndices.resize(totalTri*3);
+01591                 uint32          *rawPtr= mi->_ShiftedTriangleCache->RawIndices.getPtr();
+01592 
+01593                 // Second pass, fill ptrs, and fill Arrays
+01594                 uint    indexTri= 0;
+01595                 for(i=0;i<lod.RdrPass.size();i++)
+01596                 {
+01597                         CRdrPass                                                &srcRdrPass= lod.RdrPass[i];
+01598                         CShiftedTriangleCache::CRdrPass &dstRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
+01599                         dstRdrPass.Triangles= rawPtr + indexTri*3;
+01600 
+01601                         // Fill the array
+01602                         uint    numTris= srcRdrPass.PBlock.getNumTri();
+01603                         if(numTris)
+01604                         {
+01605                                 uint    nIds= numTris*3;
+01606                                 // index, and fill
+01607                                 uint32  *pSrcTri= srcRdrPass.PBlock.getTriPointer();
+01608                                 uint32  *pDstTri= dstRdrPass.Triangles;
+01609                                 for(;nIds>0;nIds--,pSrcTri++,pDstTri++)
+01610                                         *pDstTri= *pSrcTri + baseVertex;
+01611                         }
+01612 
+01613                         // Next
+01614                         indexTri+= dstRdrPass.NumTriangles;
+01615                 }
+01616         }
+01617 }
+01618 
+01619 
+01620 // ***************************************************************************
+01621 void    CMeshMRMGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+01622 {
+01623         // because of complexity, serial is separated in save / load.
+01624 
+01625         if(f.isReading())
+01626                 load(f);
+01627         else
+01628                 save(f);
+01629 
+01630 }
+01631 
+01632 
+01633 
+01634 // ***************************************************************************
+01635 sint    CMeshMRMGeom::loadHeader(NLMISC::IStream &f) throw(NLMISC::EStream)
+01636 {
+01637         /*
+01638         Version 4:
+01639                 - serial SkinWeights per MRM, not per Lod
+01640         Version 3:
+01641                 - Bones names.
+01642         Version 2:
+01643                 - Mesh Vertex Program.
+01644         Version 1:
+01645                 - added blend shapes
+01646         Version 0:
+01647                 - base version.
+01648         */
+01649         sint    ver= f.serialVersion(4);
+01650 
+01651         // if >= version 3, serial boens names
+01652         if(ver>=3)
+01653         {
+01654                 f.serialCont (_BonesName);
+01655         }
+01656 
+01657         // Version3-: Bones index are in skeleton model id list
+01658         _BoneIdComputed = (ver < 3);
+01659         // Must always recompute usage of parents of bones used.
+01660         _BoneIdExtended = false;
+01661 
+01662         // Mesh Vertex Program.
+01663         if (ver >= 2)
+01664         {
+01665                 IMeshVertexProgram      *mvp= NULL;
+01666                 f.serialPolyPtr(mvp);
+01667                 _MeshVertexProgram= mvp;
+01668         }
+01669         else
+01670         {
+01671                 // release vp
+01672                 _MeshVertexProgram= NULL;
+01673         }
+01674 
+01675         // blend shapes
+01676         if (ver >= 1)
+01677                 f.serial (_MeshMorpher);
+01678 
+01679         // serial Basic info.
+01680         // ==================
+01681         f.serial(_Skinned);
+01682         f.serial(_BBox);
+01683         f.serial(_LevelDetail.MaxFaceUsed);
+01684         f.serial(_LevelDetail.MinFaceUsed);
+01685         f.serial(_LevelDetail.DistanceFinest);
+01686         f.serial(_LevelDetail.DistanceMiddle);
+01687         f.serial(_LevelDetail.DistanceCoarsest);
+01688         f.serial(_LevelDetail.OODistanceDelta);
+01689         f.serial(_LevelDetail.DistancePow);
+01690         // preload the Lods.
+01691         f.serialCont(_LodInfos);
+01692 
+01693         // read/save number of wedges.
+01694         /* NB: prepare memory space too for vertices.
+01695                 \todo yoyo: TODO_OPTIMIZE. for now there is no Lod memory profit with vertices / skinWeights.
+01696                 But resizing arrays is a problem because of reallocation...
+01697         */
+01698         uint32  nWedges;
+01699         f.serial(nWedges);
+01700         // Prepare the VBuffer.
+01701         _VBufferFinal.serialHeader(f);
+01702         // If skinned, must allocate skinWeights.
+01703         contReset(_SkinWeights);
+01704         if(_Skinned)
+01705         {
+01706                 _SkinWeights.resize(nWedges);
+01707         }
+01708 
+01709 
+01710         // If new version, serial SkinWeights in header, not in lods.
+01711         if(ver >= 4)
+01712         {
+01713                 f.serialCont(_SkinWeights);
+01714         }
+01715 
+01716 
+01717         // Serial lod offsets.
+01718         // ==================
+01719         // This is the reference pos, to load / save relative offsets.
+01720         sint32                  startPos = f.getPos();
+01721         // Those are the lodOffsets, relative to startPos.
+01722         vector<sint32>  lodOffsets;
+01723         lodOffsets.resize(_LodInfos.size(), 0);
+01724 
+01725         // read all relative offsets, and build the absolute offset of LodInfos.
+01726         for(uint i=0;i<_LodInfos.size(); i++)
+01727         {
+01728                 f.serial(lodOffsets[i]);
+01729                 _LodInfos[i].LodOffset= startPos + lodOffsets[i];
+01730         }
+01731 
+01732 
+01733         // resest the Lod arrays. NB: each Lod is empty, and ready to receive Lod data.
+01734         // ==================
+01735         contReset(_Lods);
+01736         _Lods.resize(_LodInfos.size());
+01737 
+01738         // Flag the fact that no lod is loaded for now.
+01739         _NbLodLoaded= 0;
+01740 
+01741         // Inform that the mesh data has changed
+01742         dirtMeshDataId();
+01743 
+01744 
+01745         // Some runtime not serialized compilation
+01746         compileRunTime();
+01747 
+01748         // return version of the header
+01749         return ver;
+01750 }
+01751 
+01752 
+01753 // ***************************************************************************
+01754 void    CMeshMRMGeom::load(NLMISC::IStream &f) throw(NLMISC::EStream)
+01755 {
+01756 
+01757         // because loading, flag the VertexBufferHard.
+01758         _VertexBufferHardDirty= true;
+01759 
+01760 
+01761         // Load the header of the stream.
+01762         // ==================
+01763         sint    verHeader= loadHeader(f);
+01764 
+01765         // Read All lod subsets.
+01766         // ==================
+01767         for(uint i=0;i<_LodInfos.size(); i++)
+01768         {
+01769                 // read the lod face data.
+01770                 f.serial(_Lods[i]);
+01771                 // read the lod vertex data.
+01772                 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
+01773                 // if reading, must bkup all original vertices from VB.
+01774                 // this is done in serialLodVertexData(). by subset
+01775         }
+01776 
+01777         // Now, all lods are loaded.
+01778         _NbLodLoaded= _Lods.size();
+01779 
+01780         // If version doen't have boneNames, must build BoneId now.
+01781         if(verHeader <= 2)
+01782         {
+01783                 buildBoneUsageVer2 ();
+01784         }
+01785 }
+01786 
+01787 
+01788 // ***************************************************************************
+01789 void    CMeshMRMGeom::save(NLMISC::IStream &f) throw(NLMISC::EStream)
+01790 {
+01791         /*
+01792         Version 4:
+01793                 - serial SkinWeights per MRM, not per Lod
+01794         Version 3:
+01795                 - Bones names.
+01796         Version 2:
+01797                 - Mesh Vertex Program.
+01798         Version 1:
+01799                 - added blend shapes
+01800         Version 0:
+01801                 - base version.
+01802         */
+01803         sint    ver= f.serialVersion(4);
+01804         uint    i;
+01805 
+01806         // if >= version 3, serial bones names
+01807         f.serialCont (_BonesName);
+01808 
+01809         // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed! 
+01810         nlassert (_BoneIdComputed==false);
+01811 
+01812         // Mesh Vertex Program.
+01813         if (ver >= 2)
+01814         {
+01815                 IMeshVertexProgram      *mvp= NULL;
+01816                 mvp= _MeshVertexProgram;
+01817                 f.serialPolyPtr(mvp);
+01818         }
+01819 
+01820         // blend shapes
+01821         if (ver >= 1)
+01822                 f.serial (_MeshMorpher);
+01823 
+01824         // must have good original Skinned Vertex before writing.
+01825         if( _Skinned )
+01826         {
+01827                 restoreOriginalSkinVertices();
+01828         }
+01829 
+01830 
+01831         // serial Basic info.
+01832         // ==================
+01833         f.serial(_Skinned);
+01834         f.serial(_BBox);
+01835         f.serial(_LevelDetail.MaxFaceUsed);
+01836         f.serial(_LevelDetail.MinFaceUsed);
+01837         f.serial(_LevelDetail.DistanceFinest);
+01838         f.serial(_LevelDetail.DistanceMiddle);
+01839         f.serial(_LevelDetail.DistanceCoarsest);
+01840         f.serial(_LevelDetail.OODistanceDelta);
+01841         f.serial(_LevelDetail.DistancePow);
+01842         f.serialCont(_LodInfos);
+01843 
+01844         // save number of wedges.
+01845         uint32  nWedges;
+01846         nWedges= _VBufferFinal.getNumVertices();
+01847         f.serial(nWedges);
+01848         // Save the VBuffer header.
+01849         _VBufferFinal.serialHeader(f);
+01850 
+01851 
+01852         // If new version, serial SkinWeights in header, not in lods.
+01853         if(ver >= 4)
+01854         {
+01855                 f.serialCont(_SkinWeights);
+01856         }
+01857 
+01858 
+01859         // Serial lod offsets.
+01860         // ==================
+01861         // This is the reference pos, to load / save relative offsets.
+01862         sint32                  startPos = f.getPos();
+01863         // Those are the lodOffsets, relative to startPos.
+01864         vector<sint32>  lodOffsets;
+01865         lodOffsets.resize(_LodInfos.size(), 0);
+01866 
+01867         // write all dummy offset. For now (since we don't know what to set), compute the offset of 
+01868         // the sint32 to come back in serial lod parts below.
+01869         for(i=0;i<_LodInfos.size(); i++)
+01870         {
+01871                 lodOffsets[i]= f.getPos();
+01872                 f.serial(lodOffsets[i]);
+01873         }
+01874 
+01875         // Serial lod subsets.
+01876         // ==================
+01877 
+01878         // Save all the lods.
+01879         for(i=0;i<_LodInfos.size(); i++)
+01880         {
+01881                 // get current absolute position.
+01882                 sint32  absCurPos= f.getPos();
+01883 
+01884                 // come back to "relative lodOffset" absolute position in the stream. (temp stored in lodOffset[i]).
+01885                 f.seek(lodOffsets[i], IStream::begin);
+01886 
+01887                 // write the relative position of the lod to the stream.
+01888                 sint32  relCurPos= absCurPos - startPos;
+01889                 f.serial(relCurPos);
+01890 
+01891                 // come back to absCurPos, to save the lod.
+01892                 f.seek(absCurPos, IStream::begin);
+01893 
+01894                 // And so now, save the lod.
+01895                 // write the lod face data.
+01896                 f.serial(_Lods[i]);
+01897                 // write the lod vertex data.
+01898                 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
+01899         }
+01900 
+01901 
+01902 }
+01903 
+01904 
+01905 
+01906 // ***************************************************************************
+01907 void    CMeshMRMGeom::serialLodVertexData(NLMISC::IStream &f, uint startWedge, uint endWedge)
+01908 {
+01909         /*
+01910         Version 1:
+01911                 - serial SkinWeights per MRM, not per Lod
+01912         */
+01913         sint    ver= f.serialVersion(1);
+01914 
+01915         // VBuffer part.
+01916         _VBufferFinal.serialSubset(f, startWedge, endWedge);
+01917 
+01918         // SkinWeights.
+01919         if(_Skinned)
+01920         {
+01921                 // Serialize SkinWeight per lod only for old versions.
+01922                 if(ver<1)
+01923                 {
+01924                         for(uint i= startWedge; i<endWedge; i++)
+01925                         {
+01926                                 f.serial(_SkinWeights[i]);
+01927                         }
+01928                 }
+01929                 // if reading, must copy original vertices from VB.
+01930                 if( f.isReading())
+01931                 {
+01932                         bkupOriginalSkinVerticesSubset(startWedge, endWedge);
+01933                 }
+01934         }
+01935 }
+01936 
+01937 
+01938 
+01939 // ***************************************************************************
+01940 void    CMeshMRMGeom::loadFirstLod(NLMISC::IStream &f)
+01941 {
+01942 
+01943         // because loading, flag the VertexBufferHard.
+01944         _VertexBufferHardDirty= true;
+01945 
+01946         // Load the header of the stream.
+01947         // ==================
+01948         sint    verHeader= loadHeader(f);
+01949 
+01950 
+01951         // If empty MRM, quit.
+01952         if(_LodInfos.size()==0)
+01953                 return;
+01954 
+01955         /* If the version is <4, then SkinWeights are serialised per Lod.
+01956                 But for computebonesId(), we must have all SkinWeights RIGHT NOW.
+01957                 Hence, if too old version (<4), serialize all the MRM....
+01958         */
+01959         uint    numLodToLoad;
+01960         if(verHeader<4)
+01961                 numLodToLoad= _LodInfos.size();
+01962         else
+01963                 numLodToLoad= 1;
+01964 
+01965 
+01966         // Read lod subset(s).
+01967         // ==================
+01968         for(uint i=0;i<numLodToLoad; i++)
+01969         {
+01970                 // read the lod face data.
+01971                 f.serial(_Lods[i]);
+01972                 // read the lod vertex data.
+01973                 serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
+01974                 // if reading, must bkup all original vertices from VB.
+01975                 // this is done in serialLodVertexData(). by subset
+01976         }
+01977 
+01978         // Now, just first lod is loaded (but if too old file)
+01979         _NbLodLoaded= numLodToLoad;
+01980 
+01981         // If version doen't have boneNames, must build BoneId now.
+01982         if(verHeader <= 2)
+01983         {
+01984                 buildBoneUsageVer2 ();
+01985         }
+01986 }
+01987 
+01988 
+01989 // ***************************************************************************
+01990 void    CMeshMRMGeom::loadNextLod(NLMISC::IStream &f)
+01991 {
+01992 
+01993         // because loading, flag the VertexBufferHard.
+01994         _VertexBufferHardDirty= true;
+01995 
+01996         // If all is loaded, quit.
+01997         if(getNbLodLoaded() == getNbLod())
+01998                 return;
+01999 
+02000         // Set pos to good lod.
+02001         f.seek(_LodInfos[_NbLodLoaded].LodOffset, IStream::begin);
+02002 
+02003         // Serial this lod data.
+02004         // read the lod face data.
+02005         f.serial(_Lods[_NbLodLoaded]);
+02006         // read the lod vertex data.
+02007         serialLodVertexData(f, _LodInfos[_NbLodLoaded].StartAddWedge, _LodInfos[_NbLodLoaded].EndAddWedges);
+02008         // if reading, must bkup all original vertices from VB.
+02009         // this is done in serialLodVertexData(). by subset
+02010 
+02011 
+02012         // Inc LodLoaded count.
+02013         _NbLodLoaded++;
+02014 }
+02015 
+02016 
+02017 // ***************************************************************************
+02018 void    CMeshMRMGeom::unloadNextLod(NLMISC::IStream &f)
+02019 {
+02020         // If just first lod remain (or no lod), quit
+02021         if(getNbLodLoaded() <= 1)
+02022                 return;
+02023 
+02024         // Reset the entire Lod object. (Free Memory).
+02025         contReset(_Lods[_NbLodLoaded-1]);
+02026 
+02027 
+02028         // Dec LodLoaded count.
+02029         _NbLodLoaded--;
+02030 }
+02031 
+02032 
+02033 // ***************************************************************************
+02034 void    CMeshMRMGeom::bkupOriginalSkinVertices()
+02035 {
+02036         nlassert(_Skinned);
+02037 
+02038         // bkup the entire array.
+02039         bkupOriginalSkinVerticesSubset(0, _VBufferFinal.getNumVertices());
+02040 }
+02041 
+02042 
+02043 // ***************************************************************************
+02044 void    CMeshMRMGeom::bkupOriginalSkinVerticesSubset(uint wedgeStart, uint wedgeEnd)
+02045 {
+02046         nlassert(_Skinned);
+02047 
+02048         // Copy VBuffer content into Original vertices normals.
+02049         if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
+02050         {
+02051                 // copy vertices from VBuffer. (NB: unusefull geomorphed vertices are still copied, but doesn't matter).
+02052                 _OriginalSkinVertices.resize(_VBufferFinal.getNumVertices());
+02053                 for(uint i=wedgeStart; i<wedgeEnd;i++)
+02054                 {
+02055                         _OriginalSkinVertices[i]= *(CVector*)_VBufferFinal.getVertexCoordPointer(i);
+02056                 }
+02057         }
+02058         if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
+02059         {
+02060                 // copy normals from VBuffer. (NB: unusefull geomorphed normals are still copied, but doesn't matter).
+02061                 _OriginalSkinNormals.resize(_VBufferFinal.getNumVertices());
+02062                 for(uint i=wedgeStart; i<wedgeEnd;i++)
+02063                 {
+02064                         _OriginalSkinNormals[i]= *(CVector*)_VBufferFinal.getNormalCoordPointer(i);
+02065                 }
+02066         }
+02067 
+02068         // is there tangent space added ?
+02069         if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
+02070         {
+02071                 // yes, backup it
+02072                 nlassert(_VBufferFinal.getNumTexCoordUsed() > 0);
+02073                 uint tgSpaceStage = _VBufferFinal.getNumTexCoordUsed() - 1;
+02074                 _OriginalTGSpace.resize(_VBufferFinal.getNumVertices());
+02075                 for(uint i=wedgeStart; i<wedgeEnd;i++)
+02076                 {
+02077                         _OriginalTGSpace[i]= *(CVector*)_VBufferFinal.getTexCoordPointer(i, tgSpaceStage);
+02078                 }
+02079         }
+02080 }
+02081 
+02082 
+02083 // ***************************************************************************
+02084 void    CMeshMRMGeom::restoreOriginalSkinVertices()
+02085 {
+02086         nlassert(_Skinned);
+02087 
+02088         // Copy VBuffer content into Original vertices normals.
+02089         if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
+02090         {
+02091                 // copy vertices from VBuffer. (NB: unusefull geomorphed vertices are still copied, but doesn't matter).
+02092                 for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
+02093                 {
+02094                         *(CVector*)_VBufferFinal.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
+02095                 }
+02096         }
+02097         if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
+02098         {
+02099                 // copy normals from VBuffer. (NB: unusefull geomorphed normals are still copied, but doesn't matter).
+02100                 for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
+02101                 {
+02102                         *(CVector*)_VBufferFinal.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
+02103                 }
+02104         }
+02105         if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
+02106         {
+02107                 uint numTexCoords = _VBufferFinal.getNumTexCoordUsed();
+02108                 nlassert(numTexCoords >= 2);
+02109                 nlassert(_OriginalTGSpace.size() == _VBufferFinal.getNumVertices());
+02110                 // copy tangent space vectors
+02111                 for(uint i = 0; i < _VBufferFinal.getNumVertices(); ++i)
+02112                 {
+02113                         *(CVector*)_VBufferFinal.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
+02114                 }
+02115         }
+02116 }
+02117 
+02118 
+02119 // ***************************************************************************
+02120 void    CMeshMRMGeom::restoreOriginalSkinPart(CLod &lod, IVertexBufferHard *currentVBHard)
+02121 {
+02122         nlassert(_Skinned);
+02123 
+02124 
+02125         /*
+02126                 YOYO: _Skinned mrms no more support vertexBufferHard
+02127                 see note in renderSkin()
+02128         */
+02129 
+02130         // get vertexPtr / normalOff.
+02131         //===========================
+02132         uint8           *destVertexPtr= (uint8*)_VBufferFinal.getVertexCoordPointer();
+02133         uint            flags= _VBufferFinal.getVertexFormat();
+02134         sint32          vertexSize= _VBufferFinal.getVertexSize();
+02135         // must have XYZ.
+02136         nlassert(flags & CVertexBuffer::PositionFlag);
+02137 
+02138         // Compute offset of each component of the VB.
+02139         sint32          normalOff;
+02140         if(flags & CVertexBuffer::NormalFlag)
+02141                 normalOff= _VBufferFinal.getNormalOff();
+02142         else
+02143                 normalOff= 0;
+02144 
+02145 
+02146         // compute src array.
+02147         CVector                         *srcVertexPtr;
+02148         CVector                         *srcNormalPtr= NULL;
+02149         srcVertexPtr= &_OriginalSkinVertices[0];
+02150         if(normalOff)
+02151                 srcNormalPtr= &(_OriginalSkinNormals[0]);
+02152 
+02153 
+02154         // copy skinning.
+02155         //===========================
+02156         for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
+02157         {
+02158                 uint            nInf= lod.InfluencedVertices[i].size();
+02159                 if( nInf==0 )
+02160                         continue;
+02161                 uint32          *infPtr= &(lod.InfluencedVertices[i][0]);
+02162 
+02163                 //  for all InfluencedVertices only.
+02164                 for(;nInf>0;nInf--, infPtr++)
+02165                 {
+02166                         uint    index= *infPtr;
+02167                         CVector                         *srcVertex= srcVertexPtr + index;
+02168                         CVector                         *srcNormal= srcNormalPtr + index;
+02169                         uint8                           *dstVertexVB= destVertexPtr + index * vertexSize;
+02170                         CVector                         *dstVertex= (CVector*)(dstVertexVB);
+02171                         CVector                         *dstNormal= (CVector*)(dstVertexVB + normalOff);
+02172 
+02173 
+02174                         // Vertex.
+02175                         *dstVertex= *srcVertex;
+02176                         // Normal.
+02177                         if(normalOff)
+02178                                 *dstNormal= *srcNormal;
+02179                 }
+02180         }
+02181 
+02182 
+02183         // clean this lod part. (NB: this is not optimal, but sufficient :) ).
+02184         lod.OriginalSkinRestored= true;
+02185 }
+02186 
+02187 // ***************************************************************************
+02188 
+02189 float CMeshMRMGeom::getNumTriangles (float distance)
+02190 {
+02191         // NB: this is an approximation, but this is continious.
+02192         return _LevelDetail.getNumTriangles(distance);
+02193 }
+02194 
+02195 
+02196 
+02197 // ***************************************************************************
+02198 void                            CMeshMRMGeom::deleteVertexBufferHard()
+02199 {
+02200         // test (refptr) if the object still exist in memory.
+02201         if(_VBHard!=NULL)
+02202         {
+02203                 // A vbufferhard should still exist only if driver still exist.
+02204                 nlassert(_Driver!=NULL);
+02205 
+02206                 // delete it from driver.
+02207                 _Driver->deleteVertexBufferHard(_VBHard);
+02208                 _VBHard= NULL;
+02209         }
+02210 }
+02211 
+02212 // ***************************************************************************
+02213 void                            CMeshMRMGeom::updateVertexBufferHard(IDriver *drv, uint32 numVertices)
+02214 {
+02215         if(!drv->supportVertexBufferHard() || numVertices==0)
+02216                 return;
+02217 
+02218 
+02228         bool    avoidVBHard;
+02229         avoidVBHard= _Skinned || ( _MeshMorpher.BlendShapes.size()>0 && drv->slowUnlockVertexBufferHard() );
+02230         if( _VertexBufferHardDirty && avoidVBHard )
+02231         {
+02232                 // delete possible old VBHard.
+02233                 if(_VBHard!=NULL)
+02234                 {
+02235                         // VertexBufferHard lifetime < Driver lifetime.
+02236                         nlassert(_Driver!=NULL);
+02237                         _Driver->deleteVertexBufferHard(_VBHard);
+02238                 }
+02239                 return;
+02240         }
+02241 
+02242 
+02243         // If the vbufferhard is not here, or if dirty, or if do not have enough vertices.
+02244         if(_VBHard==NULL || _VertexBufferHardDirty || _VBHard->getNumVertices() < numVertices)
+02245         {
+02246                 _VertexBufferHardDirty= false;
+02247 
+02248                 // delete possible old _VBHard.
+02249                 if(_VBHard!=NULL)
+02250                 {
+02251                         // VertexBufferHard lifetime < Driver lifetime.
+02252                         nlassert(_Driver!=NULL);
+02253                         _Driver->deleteVertexBufferHard(_VBHard);
+02254                 }
+02255 
+02256                 // bkup drv in a refptr. (so we know if the vbuffer hard has to be deleted).
+02257                 _Driver= drv;
+02258                 // try to create new one, in AGP Ram
+02259                 _VBHard= _Driver->createVertexBufferHard(_VBufferFinal.getVertexFormat(), _VBufferFinal.getValueTypePointer (), numVertices, IDriver::VBHardAGP);
+02260 
+02261 
+02262                 // If KO, use normal VertexBuffer, else, Fill it with VertexBuffer.
+02263                 if(_VBHard!=NULL)
+02264                 {
+02265                         void    *vertexPtr= _VBHard->lock();
+02266 
+02267                         nlassert(_VBufferFinal.getVertexFormat() == _VBHard->getVertexFormat());
+02268                         nlassert(_VBufferFinal.getNumVertices() >= numVertices);
+02269                         nlassert(_VBufferFinal.getVertexSize() == _VBHard->getVertexSize());
+02270 
+02271                         // \todo yoyo: TODO_DX8 and DX8 ???
+02272                         // Because same internal format, just copy all block.
+02273                         memcpy(vertexPtr, _VBufferFinal.getVertexCoordPointer(), numVertices * _VBufferFinal.getVertexSize() );
+02274 
+02275                         _VBHard->unlock();
+02276                 }
+02277         }
+02278 
+02279 }
+02280 
+02281 // ***************************************************************************
+02282 void    CMeshMRMGeom::computeBonesId (CSkeletonModel *skeleton)
+02283 {
+02284         // Already computed ?
+02285         if (!_BoneIdComputed)
+02286         {
+02287                 // Get a pointer on the skeleton
+02288                 nlassert (skeleton);
+02289                 if (skeleton)
+02290                 {
+02291                         // Resize boneId to the good size.
+02292                         _BonesId.resize(_BonesName.size());
+02293 
+02294                         // Remap bones id table
+02295                         std::vector<uint> remap (_BonesName.size());
+02296 
+02297                         // For each bones
+02298                         uint bone;
+02299                         for (bone=0; bone<remap.size(); bone++)
+02300                         {
+02301                                 // Look for the bone
+02302                                 sint32 boneId = skeleton->getBoneIdByName (_BonesName[bone]);
+02303 
+02304                                 // Setup the _BoneId.
+02305                                 _BonesId[bone]= boneId;
+02306 
+02307                                 // Bones found ?
+02308                                 if (boneId != -1)
+02309                                 {
+02310                                         // Set the bone id
+02311                                         remap[bone] = (uint32)boneId;
+02312                                 }
+02313                                 else
+02314                                 {
+02315                                         // Put id 0
+02316                                         remap[bone] = 0;
+02317 
+02318                                         // Error
+02319                                         nlwarning ("Bone %s not found in the skeleton.", _BonesName[bone].c_str());
+02320                                 }
+02321                         }
+02322 
+02323                         // Remap the vertex
+02324                         uint vert;
+02325                         for (vert=0; vert<_SkinWeights.size(); vert++)
+02326                         {
+02327                                 // For each weight
+02328                                 uint weight;
+02329                                 for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
+02330                                 {
+02331                                         // Active ?
+02332                                         if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
+02333                                         {
+02334                                                 // Check id
+02335                                                 nlassert (_SkinWeights[vert].MatrixId[weight] < remap.size());
+02336                                                 _SkinWeights[vert].MatrixId[weight] = remap[_SkinWeights[vert].MatrixId[weight]];
+02337                                         }
+02338                                 }                               
+02339                         }
+02340 
+02341                         // Remap the vertex influence by lods
+02342                         uint lod;
+02343                         for (lod=0; lod<_Lods.size(); lod++)
+02344                         {
+02345                                 // For each matrix used
+02346                                 uint matrix;
+02347                                 for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
+02348                                 {
+02349                                         // Check
+02350                                         nlassert (_Lods[lod].MatrixInfluences[matrix]<remap.size());
+02351 
+02352                                         // Remap
+02353                                         _Lods[lod].MatrixInfluences[matrix] = remap[_Lods[lod].MatrixInfluences[matrix]];
+02354                                 }
+02355                         }
+02356 
+02357                         // Computed
+02358                         _BoneIdComputed = true;
+02359                 }
+02360         }
+02361 
+02362         // Already extended ?
+02363         if (!_BoneIdExtended)
+02364         {
+02365                 nlassert (skeleton);
+02366                 if (skeleton)
+02367                 {
+02368                         // the total bone Usage of the mesh.
+02369                         vector<bool>    boneUsage;
+02370                         boneUsage.resize(skeleton->Bones.size(), false);
+02371 
+02372                         // for all Bones marked as valid.
+02373                         uint    i;
+02374                         for(i=0; i<_BonesId.size(); i++)
+02375                         {
+02376                                 // if not a valid boneId, skip it.
+02377                                 if(_BonesId[i]<0)
+02378                                         continue;
+02379 
+02380                                 // mark him and his father in boneUsage.
+02381                                 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
+02382                         }
+02383 
+02384                         // fill _BonesIdExt with bones of _BonesId and their parents.
+02385                         _BonesIdExt.clear();
+02386                         for(i=0; i<boneUsage.size();i++)
+02387                         {
+02388                                 // if the bone is used by the mesh, add it to BoneIdExt.
+02389                                 if(boneUsage[i])
+02390                                         _BonesIdExt.push_back(i);
+02391                         }
+02392 
+02393                 }
+02394 
+02395                 // Extended
+02396                 _BoneIdExtended= true;
+02397         }
+02398 
+02399 }
+02400 
+02401 
+02402 // ***************************************************************************
+02403 void    CMeshMRMGeom::buildBoneUsageVer2 ()
+02404 {
+02405         if(_Skinned)
+02406         {
+02407                 // parse all vertices, couting MaxBoneId used.
+02408                 uint32  maxBoneId= 0;
+02409                 // for each vertex
+02410                 uint vert;
+02411                 for (vert=0; vert<_SkinWeights.size(); vert++)
+02412                 {
+02413                         // For each weight
+02414                         for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
+02415                         {
+02416                                 // Active ?
+02417                                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
+02418                                 {
+02419                                         maxBoneId= max(_SkinWeights[vert].MatrixId[weight], maxBoneId);
+02420                                 }
+02421                         }                               
+02422                 }
+02423 
+02424                 // alloc an array of maxBoneId+1, reset to 0.
+02425                 std::vector<uint8>              boneUsage;
+02426                 boneUsage.resize(maxBoneId+1, 0);
+02427 
+02428                 // reparse all vertices, counting usage for each bone.
+02429                 for (vert=0; vert<_SkinWeights.size(); vert++)
+02430                 {
+02431                         // For each weight
+02432                         for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
+02433                         {
+02434                                 // Active ?
+02435                                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
+02436                                 {
+02437                                         // mark this bone as used.
+02438                                         boneUsage[_SkinWeights[vert].MatrixId[weight]]= 1;
+02439                                 }
+02440                         }                               
+02441                 }
+02442 
+02443                 // For each bone used
+02444                 _BonesId.clear();
+02445                 for(uint i=0; i<boneUsage.size();i++)
+02446                 {
+02447                         // if the bone is used by the mesh, add it to BoneId.
+02448                         if(boneUsage[i])
+02449                                 _BonesId.push_back(i);
+02450                 }
+02451         }
+02452 }
+02453 
+02454 
+02455 // ***************************************************************************
+02456 void    CMeshMRMGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
+02457 {
+02458         // For all Bones used.
+02459         for(uint i=0; i<_BonesIdExt.size();i++)
+02460         {
+02461                 uint    boneId= _BonesIdExt[i];
+02462                 // Some explicit Error.
+02463                 if(boneId>=sm->Bones.size())
+02464                         nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
+02465                 // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
+02466                 if(increment)
+02467                         sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
+02468                 else
+02469                         sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
+02470         }
+02471 }
+02472 
+02473 
+02474 // ***************************************************************************
+02475 void    CMeshMRMGeom::compileRunTime()
+02476 {
+02477         _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
+02478 
+02479         // Compute if can support SkinGrouping rendering
+02480         if(_Lods.size()==0 || !_Skinned)
+02481                 _SupportSkinGrouping= false;
+02482         else
+02483         {
+02484                 // The Mesh must follow thos restrictions, to support group skinning
+02485                 _SupportSkinGrouping=
+02486                         _VBufferFinal.getVertexFormat() == NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT &&
+02487                         _VBufferFinal.getNumVertices() < NL3D_MESH_SKIN_MANAGER_MAXVERTICES &&
+02488                         !_MeshVertexProgram;
+02489         }
+02490 
+02491 }
+02492 
+02493 
+02494 // ***************************************************************************
+02495 // ***************************************************************************
+02496 // Mesh Block Render Interface
+02497 // ***************************************************************************
+02498 // ***************************************************************************
+02499 
+02500 
+02501 // ***************************************************************************
+02502 bool    CMeshMRMGeom::supportMeshBlockRendering () const
+02503 {
+02504         // \todo yoyo: TODO_OPTIMIZE support MeshBlockRendering with MRM
+02505         return false;
+02506 }
+02507 
+02508 // ***************************************************************************
+02509 bool    CMeshMRMGeom::sortPerMaterial() const
+02510 {
+02511         return false;
+02512 }
+02513 // ***************************************************************************
+02514 uint    CMeshMRMGeom::getNumRdrPasses() const 
+02515 {
+02516         return 0;
+02517 }
+02518 // ***************************************************************************
+02519 void    CMeshMRMGeom::beginMesh(CMeshGeomRenderContext &rdrCtx) 
+02520 {
+02521 }
+02522 // ***************************************************************************
+02523 void    CMeshMRMGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount) 
+02524 {
+02525 }
+02526 // ***************************************************************************
+02527 void    CMeshMRMGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId) 
+02528 {
+02529 }
+02530 // ***************************************************************************
+02531 void    CMeshMRMGeom::endMesh(CMeshGeomRenderContext &rdrCtx) 
+02532 {
+02533 }
+02534 
+02535 
+02536 // ***************************************************************************
+02537 // ***************************************************************************
+02538 // CMeshMRM.
+02539 // ***************************************************************************
+02540 // ***************************************************************************
+02541 
+02542 
+02543 
+02544 // ***************************************************************************
+02545 CMeshMRM::CMeshMRM()
+02546 {
+02547 }
+02548 // ***************************************************************************
+02549 void                    CMeshMRM::build (CMeshBase::CMeshBaseBuild &mBase, CMesh::CMeshBuild &m, 
+02550                                                                  std::vector<CMesh::CMeshBuild*> &listBS,
+02551                                                                  const CMRMParameters &params)
+02552 {
+02554         CMeshBase::buildMeshBase (mBase);
+02555 
+02556         // Then build the geom.
+02557         _MeshMRMGeom.build (m, listBS, mBase.Materials.size(), params);
+02558 }
+02559 // ***************************************************************************
+02560 void                    CMeshMRM::build (CMeshBase::CMeshBaseBuild &m, const CMeshMRMGeom &mgeom)
+02561 {
+02563         CMeshBase::buildMeshBase(m);
+02564 
+02565         // Then copy the geom.
+02566         _MeshMRMGeom= mgeom;
+02567 }
+02568 
+02569 
+02570 // ***************************************************************************
+02571 void                    CMeshMRM::optimizeMaterialUsage(std::vector<sint> &remap)
+02572 {
+02573         // For each material, count usage.
+02574         vector<bool>    materialUsed;
+02575         materialUsed.resize(CMeshBase::_Materials.size(), false);
+02576         for(uint lod=0;lod<getNbLod();lod++)
+02577         {
+02578                 for(uint rp=0;rp<getNbRdrPass(lod);rp++)
+02579                 {
+02580                         uint    matId= getRdrPassMaterial(lod, rp);
+02581                         // flag as used.
+02582                         materialUsed[matId]= true;
+02583                 }
+02584         }
+02585 
+02586         // Apply it to meshBase
+02587         CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
+02588 
+02589         // Apply lut to meshGeom.
+02590         _MeshMRMGeom.applyMaterialRemap(remap);
+02591 }
+02592 
+02593 
+02594 // ***************************************************************************
+02595 CTransformShape         *CMeshMRM::createInstance(CScene &scene)
+02596 {
+02597         // Create a CMeshMRMInstance, an instance of a mesh.
+02598         //===============================================
+02599         CMeshMRMInstance                *mi= (CMeshMRMInstance*)scene.createModel(NL3D::MeshMRMInstanceId);
+02600         mi->Shape= this;
+02601 
+02602 
+02603         // instanciate the material part of the MeshMRM, ie the CMeshBase.
+02604         CMeshBase::instanciateMeshBase(mi, &scene);
+02605 
+02606 
+02607         // do some instance init for MeshGeom
+02608         _MeshMRMGeom.initInstance(mi);
+02609 
+02610         return mi;
+02611 }
+02612 
+02613 
+02614 // ***************************************************************************
+02615 bool    CMeshMRM::clip(const std::vector<CPlane>        &pyramid, const CMatrix &worldMatrix)
+02616 {
+02617         return _MeshMRMGeom.clip(pyramid, worldMatrix);
+02618 }
+02619 
+02620 
+02621 // ***************************************************************************
+02622 void    CMeshMRM::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
+02623 {
+02624         // 0 or 0xFFFFFFFF
+02625         uint32  mask= (0-(uint32)passOpaque);
+02626         uint32  rdrFlags;
+02627         // select rdrFlags, without ifs.
+02628         rdrFlags=       mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
+02629         rdrFlags|=      ~mask & (IMeshGeom::RenderTransparentMaterial);
+02630         // render the mesh
+02631         _MeshMRMGeom.render(drv, trans, trans->getNumTrianglesAfterLoadBalancing(), rdrFlags, 1);
+02632 }
+02633 
+02634 
+02635 // ***************************************************************************
+02636 void    CMeshMRM::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
+02637 {
+02638         /*
+02639         Version 0:
+02640                 - base version.
+02641         */
+02642         (void)f.serialVersion(0);
+02643 
+02644         // serial Materials infos contained in CMeshBase.
+02645         CMeshBase::serialMeshBase(f);
+02646 
+02647 
+02648         // serial the geometry.
+02649         _MeshMRMGeom.serial(f);
+02650 }
+02651 
+02652 
+02653 // ***************************************************************************
+02654 float   CMeshMRM::getNumTriangles (float distance)
+02655 {
+02656         return _MeshMRMGeom.getNumTriangles (distance);
+02657 }
+02658 
+02659 
+02660 // ***************************************************************************
+02661 const CMeshMRMGeom& CMeshMRM::getMeshGeom () const
+02662 {
+02663         return _MeshMRMGeom;
+02664 }
+02665 
+02666 
+02667 // ***************************************************************************
+02668 void    CMeshMRM::computeBonesId (CSkeletonModel *skeleton)
+02669 {
+02670         _MeshMRMGeom.computeBonesId (skeleton);
+02671 }
+02672 
+02673 // ***************************************************************************
+02674 void    CMeshMRM::updateSkeletonUsage (CSkeletonModel *skeleton, bool increment)
+02675 {
+02676         _MeshMRMGeom.updateSkeletonUsage(skeleton, increment);
+02677 }
+02678 
+02679 // ***************************************************************************
+02680 void    CMeshMRM::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
+02681 {
+02682         _MeshMRMGeom.changeMRMDistanceSetup(distanceFinest, distanceMiddle, distanceCoarsest);
+02683 }
+02684 
+02685 // ***************************************************************************
+02686 // ***************************************************************************
+02687 // CMeshMRMGeom RawSkin optimisation
+02688 // ***************************************************************************
+02689 // ***************************************************************************
+02690 
+02691 
+02692 // ***************************************************************************
+02693 void            CMeshMRMGeom::dirtMeshDataId()
+02694 {
+02695         // see updateRawSkinNormal()
+02696         _MeshDataId++;
+02697 }
+02698 
+02699 
+02700 // ***************************************************************************
+02701 void            CMeshMRMGeom::updateRawSkinNormal(bool enabled, CMeshMRMInstance *mi, sint curLodId)
+02702 {
+02703         if(!enabled)
+02704         {
+02705                 // if the instance cache is not cleared, must clear.
+02706                 if(mi->_RawSkinCache)
+02707                         mi->clearRawSkinCache();
+02708         }
+02709         else
+02710         {
+02711                 // If the instance has no RawSkin, or has a too old RawSkin cache, must delete it, and recreate
+02712                 if( !mi->_RawSkinCache || mi->_RawSkinCache->MeshDataId!=_MeshDataId)
+02713                 {
+02714                         // first delete if too old.
+02715                         if(mi->_RawSkinCache)
+02716                                 mi->clearRawSkinCache();
+02717                         // Then recreate, and use _MeshDataId to verify that the instance works with same data.
+02718                         mi->_RawSkinCache= new CRawSkinNormalCache;
+02719                         mi->_RawSkinCache->MeshDataId= _MeshDataId;
+02720                         mi->_RawSkinCache->LodId= -1;
+02721                 }
+02722 
+02723 
+02724                 /* If the instance rawSkin has a different Lod (or if -1), then must recreate it.
+02725                         NB: The lod may change each frame per instance, but suppose not so many change, so we can cache those data.
+02726                 */
+02727                 if( mi->_RawSkinCache->LodId != curLodId )
+02728                 {
+02729                         H_AUTO( NL3D_CMeshMRMGeom_updateRawSkinNormal );
+02730 
+02731                         CRawSkinNormalCache     &skinLod= *mi->_RawSkinCache;
+02732                         CLod                            &lod= _Lods[curLodId];
+02733                         uint                            i;
+02734 
+02735                         // Clear the raw skin mesh.
+02736                         skinLod.clearArrays();
+02737 
+02738                         // Cache this lod
+02739                         mi->_RawSkinCache->LodId= curLodId;
+02740 
+02741                         // For each matrix influence.
+02742                         nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
+02743 
+02744                         // Resize the dest array.
+02745                         skinLod.Vertices1.resize(lod.InfluencedVertices[0].size());
+02746                         skinLod.Vertices2.resize(lod.InfluencedVertices[1].size());
+02747                         skinLod.Vertices3.resize(lod.InfluencedVertices[2].size());
+02748                         skinLod.Vertices4.resize(lod.InfluencedVertices[3].size());
+02749 
+02750                         // 1 Matrix skinning.
+02751                         //========
+02752                         for(i=0;i<skinLod.Vertices1.size();i++)
+02753                         {
+02754                                 // get the dest vertex.
+02755                                 uint    vid= lod.InfluencedVertices[0][i];
+02756                                 // fill raw struct
+02757                                 skinLod.Vertices1[i].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
+02758                                 skinLod.Vertices1[i].Vertex= _OriginalSkinVertices[vid];
+02759                                 skinLod.Vertices1[i].Normal= _OriginalSkinNormals[vid];
+02760                                 skinLod.Vertices1[i].VertexId= vid;
+02761                         }
+02762 
+02763                         // 2 Matrix skinning.
+02764                         //========
+02765                         for(i=0;i<skinLod.Vertices2.size();i++)
+02766                         {
+02767                                 // get the dest vertex.
+02768                                 uint    vid= lod.InfluencedVertices[1][i];
+02769                                 // fill raw struct
+02770                                 skinLod.Vertices2[i].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
+02771                                 skinLod.Vertices2[i].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
+02772                                 skinLod.Vertices2[i].Weights[0]= _SkinWeights[vid].Weights[0];
+02773                                 skinLod.Vertices2[i].Weights[1]= _SkinWeights[vid].Weights[1];
+02774                                 skinLod.Vertices2[i].Vertex= _OriginalSkinVertices[vid];
+02775                                 skinLod.Vertices2[i].Normal= _OriginalSkinNormals[vid];
+02776                                 skinLod.Vertices2[i].VertexId= vid;
+02777                         }
+02778 
+02779                         // 3 Matrix skinning.
+02780                         //========
+02781                         for(i=0;i<skinLod.Vertices3.size();i++)
+02782                         {
+02783                                 // get the dest vertex.
+02784                                 uint    vid= lod.InfluencedVertices[2][i];
+02785                                 // fill raw struct
+02786                                 skinLod.Vertices3[i].SkinWeight= _SkinWeights[vid];
+02787                                 skinLod.Vertices3[i].Vertex= _OriginalSkinVertices[vid];
+02788                                 skinLod.Vertices3[i].Normal= _OriginalSkinNormals[vid];
+02789                                 skinLod.Vertices3[i].VertexId= vid;
+02790                         }
+02791 
+02792                         // 4 Matrix skinning.
+02793                         //========
+02794                         for(i=0;i<skinLod.Vertices4.size();i++)
+02795                         {
+02796                                 // get the dest vertex.
+02797                                 uint    vid= lod.InfluencedVertices[3][i];
+02798                                 // fill raw struct
+02799                                 skinLod.Vertices4[i].SkinWeight= _SkinWeights[vid];
+02800                                 skinLod.Vertices4[i].Vertex= _OriginalSkinVertices[vid];
+02801                                 skinLod.Vertices4[i].Normal= _OriginalSkinNormals[vid];
+02802                                 skinLod.Vertices4[i].VertexId= vid;
+02803                         }
+02804 
+02805                 }
+02806         }
+02807 }
+02808 
+02809 
+02810 } // NL3D
+02811 
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1