mesh_mrm.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/misc/bsphere.h"
00027 #include "nel/misc/system_info.h"
00028 #include "nel/misc/hierarchical_timer.h"
00029 #include "nel/misc/fast_mem.h"
00030 #include "nel/3d/mesh_mrm.h"
00031 #include "nel/3d/mrm_builder.h"
00032 #include "nel/3d/mrm_parameters.h"
00033 #include "nel/3d/mesh_mrm_instance.h"
00034 #include "nel/3d/scene.h"
00035 #include "nel/3d/skeleton_model.h"
00036 #include "nel/3d/stripifier.h"
00037 #include "nel/3d/mesh_blender.h"
00038 #include "nel/3d/render_trav.h"
00039 #include "nel/misc/fast_floor.h"
00040 #include "nel/3d/raw_skin.h"
00041 #include "nel/3d/shifted_triangle_cache.h"
00042 #include "nel/3d/texture_file.h"
00043 
00044 
00045 using namespace NLMISC;
00046 using namespace std;
00047 
00048 
00049 namespace NL3D
00050 {
00051 
00052 
00053 H_AUTO_DECL( NL3D_MeshMRMGeom_RenderShadow )
00054 
00055 
00056 // ***************************************************************************
00057 // ***************************************************************************
00058 // CMeshMRMGeom::CLod
00059 // ***************************************************************************
00060 // ***************************************************************************
00061 
00062 
00063 // ***************************************************************************
00064 void        CMeshMRMGeom::CLod::serial(NLMISC::IStream &f)
00065 {
00066     /*
00067     Version 2:
00068         - precompute of triangle order. (nothing more to load).
00069     Version 1:
00070         - add VertexBlocks;
00071     Version 0:
00072         - base vdrsion.
00073     */
00074 
00075     sint    ver= f.serialVersion(2);
00076     uint    i;
00077 
00078     f.serial(NWedges);
00079     f.serialCont(RdrPass);
00080     f.serialCont(Geomorphs);
00081     f.serialCont(MatrixInfluences);
00082 
00083     // Serial array of InfluencedVertices. NB: code written so far for NL3D_MESH_SKINNING_MAX_MATRIX==4 only.
00084     nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
00085     for(i= 0; i<NL3D_MESH_SKINNING_MAX_MATRIX; i++)
00086     {
00087         f.serialCont(InfluencedVertices[i]);
00088     }
00089 
00090     if(ver>=1)
00091         f.serialCont(SkinVertexBlocks);
00092     else
00093         buildSkinVertexBlocks();
00094 
00095     // if >= version 2, reorder of triangles is precomputed, else compute it now.
00096     if(ver<2)
00097         optimizeTriangleOrder();
00098 
00099 }
00100 
00101 
00102 // ***************************************************************************
00103 void        CMeshMRMGeom::CLod::buildSkinVertexBlocks()
00104 {
00105     contReset(SkinVertexBlocks);
00106 
00107 
00108     // The list of vertices. true if used by this lod.
00109     vector<bool>        vertexMap;
00110     vertexMap.resize(NWedges, false);
00111 
00112 
00113     // from InfluencedVertices, aknoledge what vertices are used.
00114     uint    i;
00115     for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00116     {
00117         uint        nInf= InfluencedVertices[i].size();
00118         if( nInf==0 )
00119             continue;
00120         uint32      *infPtr= &(InfluencedVertices[i][0]);
00121 
00122         //  for all InfluencedVertices only.
00123         for(;nInf>0;nInf--, infPtr++)
00124         {
00125             uint    index= *infPtr;
00126             vertexMap[index]= true;
00127         }
00128     }
00129 
00130     // For all vertices, test if they are used, and build the according SkinVertexBlocks;
00131     CVertexBlock    *vBlock= NULL;
00132     for(i=0; i<vertexMap.size();i++)
00133     {
00134         if(vertexMap[i])
00135         {
00136             // preceding block?
00137             if(vBlock)
00138             {
00139                 // yes, extend it.
00140                 vBlock->NVertices++;
00141             }
00142             else
00143             {
00144                 // no, append a new one.
00145                 SkinVertexBlocks.push_back(CVertexBlock());
00146                 vBlock= &SkinVertexBlocks[SkinVertexBlocks.size()-1];
00147                 vBlock->VertexStart= i;
00148                 vBlock->NVertices= 1;
00149             }
00150         }
00151         else
00152         {
00153             // Finish the preceding block (if any).
00154             vBlock= NULL;
00155         }
00156     }
00157 
00158 }
00159 
00160 
00161 // ***************************************************************************
00162 void        CMeshMRMGeom::CLod::optimizeTriangleOrder()
00163 {
00164     CStripifier     stripifier;
00165 
00166     // for all rdrpass
00167     for(uint  rp=0; rp<RdrPass.size(); rp++ )
00168     {
00169         // stripify list of triangles of this pass.
00170         CRdrPass    &pass= RdrPass[rp];
00171         stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
00172     }
00173 
00174 }
00175 
00176 
00177 // ***************************************************************************
00178 // ***************************************************************************
00179 // CMeshMRMGeom.
00180 // ***************************************************************************
00181 // ***************************************************************************
00182 
00183 
00184 
00185 
00186 // ***************************************************************************
00187 static  NLMISC::CAABBoxExt  makeBBox(const std::vector<CVector> &Vertices)
00188 {
00189     NLMISC::CAABBox     ret;
00190     nlassert(Vertices.size());
00191     ret.setCenter(Vertices[0]);
00192     for(sint i=0;i<(sint)Vertices.size();i++)
00193     {
00194         ret.extend(Vertices[i]);
00195     }
00196 
00197     return ret;
00198 }
00199 
00200 
00201 // ***************************************************************************
00202 CMeshMRMGeom::CMeshMRMGeom()
00203 {
00204     _Skinned= false;
00205     _NbLodLoaded= 0;
00206     _BoneIdComputed = false;
00207     _BoneIdExtended = false;
00208     _PreciseClipping= false;
00209     _SupportSkinGrouping= false;
00210     _MeshDataId= 0;
00211     _SupportMeshBlockRendering=  false;
00212     _MBRCurrentLodId= 0;
00213     _SupportShadowSkinGrouping= false;
00214 }
00215 
00216 
00217 // ***************************************************************************
00218 CMeshMRMGeom::~CMeshMRMGeom()
00219 {
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     // Empty geometry?
00246     if(m.Vertices.size()==0 || m.Faces.size()==0)
00247     {
00248         _VBufferFinal.setNumVertices(0);
00249         _VBufferFinal.reserve(0);
00250         _Lods.clear();
00251         _BBox.setCenter(CVector::Null);
00252         _BBox.setSize(CVector::Null);
00253         return;
00254     }
00255     nlassert(numMaxMaterial>0);
00256 
00257 
00258     // SmartPtr Copy VertexProgram effect.
00259     //================================================
00260     this->_MeshVertexProgram= m.MeshVertexProgram;
00261 
00262 
00264     //======================
00265     // NB: this is equivalent as building BBox from MRM VBuffer, because CMRMBuilder create new vertices
00266     // which are just interpolation of original vertices.
00267     _BBox= makeBBox(m.Vertices);
00268 
00269 
00271     //================================================
00272     CMRMBuilder         mrmBuilder;
00273     CMeshBuildMRM       meshBuildMRM;
00274 
00275     mrmBuilder.compileMRM(m, bsList, params, meshBuildMRM, numMaxMaterial);
00276 
00277     // Then just copy result!
00278     //================================================
00279     _VBufferFinal= meshBuildMRM.VBuffer;
00280     _Lods= meshBuildMRM.Lods;
00281     _Skinned= meshBuildMRM.Skinned;
00282     _SkinWeights= meshBuildMRM.SkinWeights;
00283 
00284     // Compute degradation control.
00285     //================================================
00286     _LevelDetail.DistanceFinest= meshBuildMRM.DistanceFinest;
00287     _LevelDetail.DistanceMiddle= meshBuildMRM.DistanceMiddle;
00288     _LevelDetail.DistanceCoarsest= meshBuildMRM.DistanceCoarsest;
00289     nlassert(_LevelDetail.DistanceFinest>=0);
00290     nlassert(_LevelDetail.DistanceMiddle > _LevelDetail.DistanceFinest);
00291     nlassert(_LevelDetail.DistanceCoarsest > _LevelDetail.DistanceMiddle);
00292     // Compute OODistDelta and DistancePow
00293     _LevelDetail.compileDistanceSetup();
00294 
00295 
00296     // Build the _LodInfos.
00297     //================================================
00298     _LodInfos.resize(_Lods.size());
00299     uint32  precNWedges= 0;
00300     uint    i;
00301     for(i=0;i<_Lods.size();i++)
00302     {
00303         _LodInfos[i].StartAddWedge= precNWedges;
00304         _LodInfos[i].EndAddWedges= _Lods[i].NWedges;
00305         precNWedges= _Lods[i].NWedges;
00306         // LodOffset is filled in serial() when stream is input.
00307     }
00308     // After build, all lods are present in memory.
00309     _NbLodLoaded= _Lods.size();
00310 
00311 
00312     // For load balancing.
00313     //================================================
00314     // compute Max Face Used
00315     _LevelDetail.MaxFaceUsed= 0;
00316     _LevelDetail.MinFaceUsed= 0;
00317     // Count of primitive block
00318     if(_Lods.size()>0)
00319     {
00320         uint    pb;
00321         // Compute MinFaces.
00322         CLod    &firstLod= _Lods[0];
00323         for (pb=0; pb<firstLod.RdrPass.size(); pb++)
00324         {
00325             CRdrPass &pass= firstLod.RdrPass[pb];
00326             // Sum tri
00327             _LevelDetail.MinFaceUsed+= pass.PBlock.getNumIndexes ()/3;
00328         }
00329         // Compute MaxFaces.
00330         CLod    &lastLod= _Lods[_Lods.size()-1];
00331         for (pb=0; pb<lastLod.RdrPass.size(); pb++)
00332         {
00333             CRdrPass &pass= lastLod.RdrPass[pb];
00334             // Sum tri
00335             _LevelDetail.MaxFaceUsed+= pass.PBlock.getNumIndexes ()/3;
00336         }
00337     }
00338 
00339 
00340     // For skinning.
00341     //================================================
00342     if( _Skinned )
00343     {
00344         bkupOriginalSkinVertices();
00345     }
00346     // Inform that the mesh data has changed
00347     dirtMeshDataId();
00348 
00349 
00350     // For AGP SKinning optim, and for Render optim
00351     //================================================
00352     for(i=0;i<_Lods.size();i++)
00353     {
00354         _Lods[i].buildSkinVertexBlocks();
00355         // sort triangles for better cache use.
00356         _Lods[i].optimizeTriangleOrder();
00357     }
00358 
00359     // Copy Blend Shapes
00360     //================================================
00361     _MeshMorpher.BlendShapes = meshBuildMRM.BlendShapes;
00362 
00363 
00364     // Compact bone id and build a bone id names
00365     //================================================
00366 
00367     // Skinned ?
00368     if (_Skinned)
00369     {
00370         // Remap
00371         std::map<uint, uint> remap;
00372 
00373         // Current bone
00374         uint currentBone = 0;
00375 
00376         // Reserve memory
00377         _BonesName.reserve (m.BonesNames.size());
00378 
00379         // For each vertices
00380         uint vert;
00381         for (vert=0; vert<_SkinWeights.size(); vert++)
00382         {
00383             // Found one ?
00384             bool found=false;
00385 
00386             // For each weight
00387             uint weight;
00388             for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
00389             {
00390                 // Active ?
00391                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
00392                 {
00393                     // Look for it
00394                     std::map<uint, uint>::iterator ite = remap.find (_SkinWeights[vert].MatrixId[weight]);
00395 
00396                     // Find ?
00397                     if (ite == remap.end())
00398                     {
00399                         // Insert it
00400                         remap.insert (std::map<uint, uint>::value_type (_SkinWeights[vert].MatrixId[weight], currentBone));
00401 
00402                         // Check the id
00403                         nlassert (_SkinWeights[vert].MatrixId[weight]<m.BonesNames.size());
00404 
00405                         // Set the bone name
00406                         _BonesName.push_back (m.BonesNames[_SkinWeights[vert].MatrixId[weight]]);
00407 
00408                         // Set the local bone id
00409                         _SkinWeights[vert].MatrixId[weight] = currentBone++;
00410                     }
00411                     else
00412                     {
00413                         // Set the local bone id
00414                         _SkinWeights[vert].MatrixId[weight] = ite->second;
00415                     }
00416 
00417                     // Found one
00418                     found = true;
00419                 }
00420             }
00421 
00422             // Found one ?
00423             nlassert (found);
00424         }
00425 
00426         // Remap the vertex influence by lods
00427         uint lod;
00428         for (lod=0; lod<_Lods.size(); lod++)
00429         {
00430             // For each matrix used
00431             uint matrix;
00432             for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
00433             {
00434                 // Remap
00435                 std::map<uint, uint>::iterator ite = remap.find (_Lods[lod].MatrixInfluences[matrix]);
00436 
00437                 // Find ?
00438                 nlassert (ite != remap.end());
00439 
00440                 // Remap
00441                 _Lods[lod].MatrixInfluences[matrix] = ite->second;
00442             }
00443         }
00444     }
00445 
00446     // Misc.
00447     //===================
00448     // Some runtime not serialized compilation
00449     compileRunTime();
00450 
00451 }
00452 
00453 // ***************************************************************************
00454 void    CMeshMRMGeom::applyMaterialRemap(const std::vector<sint> &remap)
00455 {
00456     for(uint lod=0;lod<getNbLod();lod++)
00457     {
00458         for(uint rp=0;rp<getNbRdrPass(lod);rp++)
00459         {
00460             // remap
00461             uint32  &matId= _Lods[lod].RdrPass[rp].MaterialId;
00462             nlassert(remap[matId]>=0);
00463             matId= remap[matId];
00464         }
00465     }
00466 }
00467 
00468 // ***************************************************************************
00469 void    CMeshMRMGeom::applyGeomorph(std::vector<CMRMWedgeGeom>  &geoms, float alphaLod)
00470 {
00471     applyGeomorphWithVBHardPtr(geoms, alphaLod, NULL);
00472 }
00473 
00474 
00475 // ***************************************************************************
00476 void    CMeshMRMGeom::applyGeomorphWithVBHardPtr(std::vector<CMRMWedgeGeom>  &geoms, float alphaLod, uint8 *vertexDestPtr)
00477 {
00478     // no geomorphs? quit.
00479     if(geoms.size()==0)
00480         return;
00481 
00482     clamp(alphaLod, 0.f, 1.f);
00483     float       a= alphaLod;
00484     float       a1= 1 - alphaLod;
00485 
00486 
00487     // info from VBuffer.
00488     CVertexBufferReadWrite vba;
00489     _VBufferFinal.lock (vba);
00490     uint8       *vertexPtr= (uint8*)vba.getVertexCoordPointer();
00491     uint        flags= _VBufferFinal.getVertexFormat();
00492     sint32      vertexSize= _VBufferFinal.getVertexSize();
00493     // because of the unrolled code for 4 first UV, must assert this.
00494     nlassert(CVertexBuffer::MaxStage>=4);
00495     // must have XYZ.
00496     nlassert(flags & CVertexBuffer::PositionFlag);
00497 
00498 
00499     // If VBuffer Hard disabled
00500     if(vertexDestPtr==NULL)
00501     {
00502         // write into vertexPtr.
00503         vertexDestPtr= vertexPtr;
00504     }
00505 
00506 
00507     // if it is a common format
00508     if( flags== (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag) &&
00509         _VBufferFinal.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2 )
00510     {
00511         // use a faster method
00512         applyGeomorphPosNormalUV0(geoms, vertexPtr, vertexDestPtr, vertexSize, a, a1);
00513     }
00514     else
00515     {
00516         // for color interp
00517         uint        i;
00518         uint        ua= (uint)(a*256);
00519         clamp(ua, (uint)0, (uint)256);
00520         uint        ua1= 256 - ua;
00521 
00522         // if an offset is 0, it means that the component is not in the VBuffer.
00523         sint32      normalOff;
00524         sint32      colorOff;
00525         sint32      specularOff;
00526         sint32      uvOff[CVertexBuffer::MaxStage];
00527         bool        has3Coords[CVertexBuffer::MaxStage];
00528 
00529 
00530         // Compute offset of each component of the VB.
00531         if(flags & CVertexBuffer::NormalFlag)
00532             normalOff= _VBufferFinal.getNormalOff();
00533         else
00534             normalOff= 0;
00535         if(flags & CVertexBuffer::PrimaryColorFlag)
00536             colorOff= _VBufferFinal.getColorOff();
00537         else
00538             colorOff= 0;
00539         if(flags & CVertexBuffer::SecondaryColorFlag)
00540             specularOff= _VBufferFinal.getSpecularOff();
00541         else
00542             specularOff= 0;
00543 
00544         for(i= 0; i<CVertexBuffer::MaxStage;i++)
00545         {
00546             if(flags & (CVertexBuffer::TexCoord0Flag<<i))
00547             {
00548                 uvOff[i]= _VBufferFinal.getTexCoordOff(i);
00549                 has3Coords[i] = (_VBufferFinal.getValueType(i + CVertexBuffer::TexCoord0) == CVertexBuffer::Float3);
00550             }
00551             else
00552             {
00553                 uvOff[i]= 0;
00554             }
00555         }
00556 
00557 
00558         // For all geomorphs.
00559         uint            nGeoms= geoms.size();
00560         CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
00561         uint8           *destPtr= vertexDestPtr;
00562         /* NB: optimisation: lot of "if" in this Loop, but because of BTB, they always cost nothing (prediction is good).
00563            NB: this also is why we unroll the 4 1st Uv. The other (if any), are done in the other loop.
00564            NB: optimisation for AGP write cominers: the order of write (vertex, normal, uvs...) is important for good
00565            use of AGP write combiners.
00566            We have 2 version : one that tests for 3 coordinates texture coords, and one that doesn't
00567         */
00568 
00569         if (!has3Coords[0] && !has3Coords[1] && !has3Coords[2] && !has3Coords[3])
00570         {
00571             // there are no texture coordinate of dimension 3
00572             for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
00573             {
00574                 uint8           *startPtr=  vertexPtr + ptrGeom->Start*vertexSize;
00575                 uint8           *endPtr=    vertexPtr + ptrGeom->End*vertexSize;
00576 
00577                 // Vertex.
00578                 {
00579                     CVector     *start= (CVector*)startPtr;
00580                     CVector     *end=   (CVector*)endPtr;
00581                     CVector     *dst=   (CVector*)destPtr;
00582                     *dst= *start * a + *end * a1;
00583                 }
00584 
00585                 // Normal.
00586                 if(normalOff)
00587                 {
00588                     CVector     *start= (CVector*)(startPtr + normalOff);
00589                     CVector     *end=   (CVector*)(endPtr   + normalOff);
00590                     CVector     *dst=   (CVector*)(destPtr  + normalOff);
00591                     *dst= *start * a + *end * a1;
00592                 }
00593 
00594 
00595                 // Uvs.
00596                 // uv[0].
00597                 if(uvOff[0])
00598                 {
00599                     // Uv.
00600                     CUV         *start= (CUV*)(startPtr + uvOff[0]);
00601                     CUV         *end=   (CUV*)(endPtr   + uvOff[0]);
00602                     CUV         *dst=   (CUV*)(destPtr  + uvOff[0]);
00603                     *dst= *start * a + *end * a1;
00604                 }
00605                 // uv[1].
00606                 if(uvOff[1])
00607                 {
00608                     // Uv.
00609                     CUV         *start= (CUV*)(startPtr + uvOff[1]);
00610                     CUV         *end=   (CUV*)(endPtr   + uvOff[1]);
00611                     CUV         *dst=   (CUV*)(destPtr  + uvOff[1]);
00612                     *dst= *start * a + *end * a1;
00613                 }
00614                 // uv[2].
00615                 if(uvOff[2])
00616                 {
00617                     CUV         *start= (CUV*)(startPtr + uvOff[2]);
00618                     CUV         *end=   (CUV*)(endPtr   + uvOff[2]);
00619                     CUV         *dst=   (CUV*)(destPtr  + uvOff[2]);
00620                     *dst= *start * a + *end * a1;
00621                 }
00622                 // uv[3].
00623                 if(uvOff[3])
00624                 {
00625                     // Uv.
00626                     CUV         *start= (CUV*)(startPtr + uvOff[3]);
00627                     CUV         *end=   (CUV*)(endPtr   + uvOff[3]);
00628                     CUV         *dst=   (CUV*)(destPtr  + uvOff[3]);
00629                     *dst= *start * a + *end * a1;
00630                 }
00631             }
00632         }
00633         else // THERE ARE TEXTURE COORDINATES OF DIMENSION 3
00634         {
00635             for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
00636             {
00637                 uint8           *startPtr=  vertexPtr + ptrGeom->Start*vertexSize;
00638                 uint8           *endPtr=    vertexPtr + ptrGeom->End*vertexSize;
00639 
00640                 // Vertex.
00641                 {
00642                     CVector     *start= (CVector*)startPtr;
00643                     CVector     *end=   (CVector*)endPtr;
00644                     CVector     *dst=   (CVector*)destPtr;
00645                     *dst= *start * a + *end * a1;
00646                 }
00647 
00648                 // Normal.
00649                 if(normalOff)
00650                 {
00651                     CVector     *start= (CVector*)(startPtr + normalOff);
00652                     CVector     *end=   (CVector*)(endPtr   + normalOff);
00653                     CVector     *dst=   (CVector*)(destPtr  + normalOff);
00654                     *dst= *start * a + *end * a1;
00655                 }
00656                 // Uvs.
00657                 // uv[0].
00658                 if(uvOff[0])
00659                 {
00660                     if (!has3Coords[0])
00661                     {
00662                         // Uv.
00663                         CUV         *start= (CUV*)(startPtr + uvOff[0]);
00664                         CUV         *end=   (CUV*)(endPtr   + uvOff[0]);
00665                         CUV         *dst=   (CUV*)(destPtr  + uvOff[0]);
00666                         *dst= *start * a + *end * a1;
00667                     }
00668                     else
00669                     {
00670                         // Uv.
00671                         CUVW        *start= (CUVW*)(startPtr + uvOff[0]);
00672                         CUVW        *end=   (CUVW*)(endPtr   + uvOff[0]);
00673                         CUVW        *dst=   (CUVW*)(destPtr  + uvOff[0]);
00674                         *dst= *start * a + *end * a1;
00675                     }
00676                 }
00677                 // uv[1].
00678                 if(uvOff[1])
00679                 {
00680                     if (!has3Coords[1])
00681                     {
00682                         // Uv.
00683                         CUV         *start= (CUV*)(startPtr + uvOff[1]);
00684                         CUV         *end=   (CUV*)(endPtr   + uvOff[1]);
00685                         CUV         *dst=   (CUV*)(destPtr  + uvOff[1]);
00686                         *dst= *start * a + *end * a1;
00687                     }
00688                     else
00689                     {
00690                         // Uv.
00691                         CUVW        *start= (CUVW*)(startPtr + uvOff[1]);
00692                         CUVW        *end=   (CUVW*)(endPtr   + uvOff[1]);
00693                         CUVW        *dst=   (CUVW*)(destPtr  + uvOff[1]);
00694                         *dst= *start * a + *end * a1;
00695                     }
00696                 }
00697                 // uv[2].
00698                 if(uvOff[2])
00699                 {
00700                     if (!has3Coords[2])
00701                     {
00702                         // Uv.
00703                         CUV         *start= (CUV*)(startPtr + uvOff[2]);
00704                         CUV         *end=   (CUV*)(endPtr   + uvOff[2]);
00705                         CUV         *dst=   (CUV*)(destPtr  + uvOff[2]);
00706                         *dst= *start * a + *end * a1;
00707                     }
00708                     else
00709                     {
00710                         // Uv.
00711                         CUVW        *start= (CUVW*)(startPtr + uvOff[2]);
00712                         CUVW        *end=   (CUVW*)(endPtr   + uvOff[2]);
00713                         CUVW        *dst=   (CUVW*)(destPtr  + uvOff[2]);
00714                         *dst= *start * a + *end * a1;
00715                     }
00716                 }
00717                 // uv[3].
00718                 if(uvOff[3])
00719                 {
00720                     if (!has3Coords[3])
00721                     {
00722                         // Uv.
00723                         CUV         *start= (CUV*)(startPtr + uvOff[3]);
00724                         CUV         *end=   (CUV*)(endPtr   + uvOff[3]);
00725                         CUV         *dst=   (CUV*)(destPtr  + uvOff[3]);
00726                         *dst= *start * a + *end * a1;
00727                     }
00728                     else
00729                     {
00730                         // Uv.
00731                         CUVW        *start= (CUVW*)(startPtr + uvOff[3]);
00732                         CUVW        *end=   (CUVW*)(endPtr   + uvOff[3]);
00733                         CUVW        *dst=   (CUVW*)(destPtr  + uvOff[3]);
00734                         *dst= *start * a + *end * a1;
00735                     }
00736                 }
00737                 // color.
00738                 if(colorOff)
00739                 {
00740                     CRGBA       *start= (CRGBA*)(startPtr + colorOff);
00741                     CRGBA       *end=   (CRGBA*)(endPtr   + colorOff);
00742                     CRGBA       *dst=   (CRGBA*)(destPtr  + colorOff);
00743                     dst->blendFromui(*start, *end,  ua1);
00744                 }
00745                 // specular.
00746                 if(specularOff)
00747                 {
00748                     CRGBA       *start= (CRGBA*)(startPtr + specularOff);
00749                     CRGBA       *end=   (CRGBA*)(endPtr   + specularOff);
00750                     CRGBA       *dst=   (CRGBA*)(destPtr  + specularOff);
00751                     dst->blendFromui(*start, *end,  ua1);
00752                 }
00753             }
00754         }
00755 
00756 
00757         // Process extra UVs (maybe never, so don't bother optims :)).
00758         // For all stages after 4.
00759         for(i=4;i<CVertexBuffer::MaxStage;i++)
00760         {
00761             uint            nGeoms= geoms.size();
00762             CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
00763             uint8           *destPtr= vertexDestPtr;
00764 
00765             if(uvOff[i]==0)
00766                 continue;
00767 
00768             // For all geomorphs.
00769             for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
00770             {
00771                 uint8           *startPtr=  vertexPtr + ptrGeom->Start*vertexSize;
00772                 uint8           *endPtr=    vertexPtr + ptrGeom->End*vertexSize;
00773 
00774                 // uv[i].
00775                 // Uv.
00776                 if (!has3Coords[i])
00777                 {
00778                     CUV         *start= (CUV*)(startPtr + uvOff[i]);
00779                     CUV         *end=   (CUV*)(endPtr   + uvOff[i]);
00780                     CUV         *dst=   (CUV*)(destPtr  + uvOff[i]);
00781                     *dst= *start * a + *end * a1;
00782                 }
00783                 else
00784                 {
00785                     CUVW        *start= (CUVW*)(startPtr + uvOff[i]);
00786                     CUVW        *end=   (CUVW*)(endPtr  + uvOff[i]);
00787                     CUVW        *dst=   (CUVW*)(destPtr + uvOff[i]);
00788                     *dst= *start * a + *end * a1;
00789                 }
00790             }
00791         }
00792     }
00793 }
00794 
00795 
00796 // ***************************************************************************
00797 void    CMeshMRMGeom::applyGeomorphPosNormalUV0(std::vector<CMRMWedgeGeom>  &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, float a, float a1)
00798 {
00799     nlassert(vertexSize==32);
00800 
00801 
00802     // For all geomorphs.
00803     uint            nGeoms= geoms.size();
00804     CMRMWedgeGeom   *ptrGeom= &(geoms[0]);
00805     uint8           *destPtr= vertexDestPtr;
00806     for(; nGeoms>0; nGeoms--, ptrGeom++, destPtr+= vertexSize )
00807     {
00808         // Consider the Pos/Normal/UV as an array of 8 float to interpolate.
00809         float           *start= (float*)(vertexPtr + (ptrGeom->Start<<5));
00810         float           *end=   (float*)(vertexPtr + (ptrGeom->End<<5));
00811         float           *dst=   (float*)(destPtr);
00812 
00813         // unrolled
00814         dst[0]= start[0] * a + end[0]* a1;
00815         dst[1]= start[1] * a + end[1]* a1;
00816         dst[2]= start[2] * a + end[2]* a1;
00817         dst[3]= start[3] * a + end[3]* a1;
00818         dst[4]= start[4] * a + end[4]* a1;
00819         dst[5]= start[5] * a + end[5]* a1;
00820         dst[6]= start[6] * a + end[6]* a1;
00821         dst[7]= start[7] * a + end[7]* a1;
00822     }
00823 }
00824 
00825 
00826 // ***************************************************************************
00827 void    CMeshMRMGeom::initInstance(CMeshBaseInstance *mbi)
00828 {
00829     // init the instance with _MeshVertexProgram infos
00830     if(_MeshVertexProgram)
00831         _MeshVertexProgram->initInstance(mbi);
00832 }
00833 
00834 
00835 // ***************************************************************************
00836 bool    CMeshMRMGeom::clip(const std::vector<CPlane>    &pyramid, const CMatrix &worldMatrix)
00837 {
00838     // Speed Clip: clip just the sphere.
00839     CBSphere    localSphere(_BBox.getCenter(), _BBox.getRadius());
00840     CBSphere    worldSphere;
00841 
00842     // transform the sphere in WorldMatrix (with nearly good scale info).
00843     localSphere.applyTransform(worldMatrix, worldSphere);
00844 
00845     // if out of only plane, entirely out.
00846     for(sint i=0;i<(sint)pyramid.size();i++)
00847     {
00848         // We are sure that pyramid has normalized plane normals.
00849         // if SpherMax OUT return false.
00850         float   d= pyramid[i]*worldSphere.Center;
00851         if(d>worldSphere.Radius)
00852             return false;
00853     }
00854 
00855     // test if must do a precise clip, according to mesh size.
00856     if( _PreciseClipping )
00857     {
00858         CPlane  localPlane;
00859 
00860         // if out of only plane, entirely out.
00861         for(sint i=0;i<(sint)pyramid.size();i++)
00862         {
00863             // Transform the pyramid in Object space.
00864             localPlane= pyramid[i]*worldMatrix;
00865             // localPlane must be normalized, because worldMatrix mya have a scale.
00866             localPlane.normalize();
00867             // if the box is not partially inside the plane, quit
00868             if( !_BBox.clipBack(localPlane) )
00869                 return false;
00870         }
00871     }
00872 
00873     return true;
00874 }
00875 
00876 
00877 // ***************************************************************************
00878 inline sint CMeshMRMGeom::chooseLod(float alphaMRM, float &alphaLod)
00879 {
00880     // Choose what Lod to draw.
00881     alphaMRM*= _Lods.size()-1;
00882     sint    numLod= (sint)ceil(alphaMRM);
00883     if(numLod==0)
00884     {
00885         numLod= 0;
00886         alphaLod= 0;
00887     }
00888     else
00889     {
00890         // Lerp beetween lod i-1 and lod i.
00891         alphaLod= alphaMRM-(numLod-1);
00892     }
00893 
00894 
00895     // If lod chosen is not loaded, take the best loaded.
00896     if(numLod>=(sint)_NbLodLoaded)
00897     {
00898         numLod= _NbLodLoaded-1;
00899         alphaLod= 1;
00900     }
00901 
00902     return numLod;
00903 }
00904 
00905 
00906 // ***************************************************************************
00907 void    CMeshMRMGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
00908 {
00909     nlassert(drv);
00910     if(_Lods.size()==0)
00911         return;
00912 
00913 
00914     // get the meshMRM instance.
00915     CMeshBaseInstance   *mi= safe_cast<CMeshBaseInstance*>(trans);
00916     // get a ptr on scene
00917     CScene              *ownerScene= mi->getOwnerScene();
00918     // get a ptr on renderTrav
00919     CRenderTrav         *renderTrav= &ownerScene->getRenderTrav();
00920 
00921 
00922     // get the result of the Load Balancing.
00923     float   alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
00924 
00925     // choose the lod.
00926     float   alphaLod;
00927     sint    numLod= chooseLod(alphaMRM, alphaLod);
00928 
00929 
00930     // Render the choosen Lod.
00931     CLod    &lod= _Lods[numLod];
00932     if(lod.RdrPass.size()==0)
00933         return;
00934 
00935 
00936     // Update the vertexBufferHard (if possible).
00937     // \toto yoyo: TODO_OPTIMIZE: allocate only what is needed for the current Lod (Max of all instances, like
00938     // the loading....) (see loadHeader()).
00939 
00940     // get the skeleton model to which I am binded (else NULL).
00941     CSkeletonModel *skeleton;
00942     skeleton = mi->getSkeletonModel();
00943     // The mesh must not be skinned for render()
00944     nlassert(!(_Skinned && mi->isSkinned() && skeleton));
00945     bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
00946     bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00947 
00948 
00949     // Profiling
00950     //===========
00951     H_AUTO( NL3D_MeshMRMGeom_RenderNormal );
00952 
00953 
00954     // Morphing
00955     // ========
00956     if (bMorphApplied)
00957     {
00958         // If _Skinned (NB: the skin is not applied) and if lod.OriginalSkinRestored, then restoreOriginalSkinPart is
00959         // not called but mush morpher write changed vertices into VBHard so its ok. The unchanged vertices
00960         // are written in the preceding call to restoreOriginalSkinPart.
00961         if (_Skinned)
00962         {
00963             _MeshMorpher.initSkinned(&_VBufferOriginal,
00964                                  &_VBufferFinal,
00965                                  useTangentSpace,
00966                                  &_OriginalSkinVertices,
00967                                  &_OriginalSkinNormals,
00968                                  useTangentSpace ? &_OriginalTGSpace : NULL,
00969                                  false );
00970             _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
00971         }
00972         else // Not even skinned so we have to do all the stuff
00973         {
00974             _MeshMorpher.init(&_VBufferOriginal,
00975                                  &_VBufferFinal,
00976                                  useTangentSpace);
00977             _MeshMorpher.update (mi->getBlendShapeFactors());
00978         }
00979     }
00980 
00981     // Skinning.
00982     //===========
00983     // if mesh is skinned (but here skin not applied), we must copy vertices/normals from original vertices.
00984     if (_Skinned)
00985     {
00986         // do it for this Lod only, and if cache say it is necessary.
00987         if (!lod.OriginalSkinRestored)
00988             restoreOriginalSkinPart(lod);
00989     }
00990 
00991 
00992     // set the instance worldmatrix.
00993     drv->setupModelMatrix(trans->getWorldMatrix());
00994 
00995 
00996     // Geomorph.
00997     //===========
00998     // Geomorph the choosen Lod (if not the coarser mesh).
00999     if(numLod>0)
01000     {
01001         applyGeomorph(lod.Geomorphs, alphaLod);
01002     }
01003 
01004 
01005     // force normalisation of normals..
01006     bool    bkupNorm= drv->isForceNormalize();
01007     drv->forceNormalize(true);
01008 
01009 
01010     // Setup meshVertexProgram
01011     //===========
01012 
01013     // use MeshVertexProgram effect?
01014     bool    useMeshVP= _MeshVertexProgram != NULL;
01015     if( useMeshVP )
01016     {
01017         CMatrix     invertedObjectMatrix;
01018         invertedObjectMatrix = trans->getWorldMatrix().inverted();
01019         // really ok if success to begin VP
01020         useMeshVP= _MeshVertexProgram->begin(drv, mi->getOwnerScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
01021     }
01022 
01023 
01024     // Render the lod.
01025     //===========
01026     // active VB.
01027     drv->activeVertexBuffer(_VBufferFinal);
01028 
01029 
01030     // Global alpha used ?
01031     uint32  globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
01032     uint8   globalAlphaInt=(uint8)NLMISC::OptFastFloor(globalAlpha*255);
01033 
01034     // Render all pass.
01035     if (globalAlphaUsed)
01036     {
01037         bool    gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
01038 
01039         // for all passes
01040         for(uint i=0;i<lod.RdrPass.size();i++)
01041         {
01042             CRdrPass    &rdrPass= lod.RdrPass[i];
01043 
01044             if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
01045                  ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
01046             {
01047                 // CMaterial Ref
01048                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
01049 
01050                 // Use a MeshBlender to modify material and driver.
01051                 CMeshBlender    blender;
01052                 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
01053 
01054                 // Setup VP material
01055                 if (useMeshVP)
01056                 {
01057                     _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
01058                 }
01059 
01060                 // Render
01061                 drv->activeIndexBuffer(rdrPass.PBlock);
01062                 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
01063 
01064                 // Resetup material/driver
01065                 blender.restoreRender(material, drv, gaDisableZWrite);
01066             }
01067         }
01068     }
01069     else
01070     {
01071         for(uint i=0;i<lod.RdrPass.size();i++)
01072         {
01073             CRdrPass    &rdrPass= lod.RdrPass[i];
01074 
01075             if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
01076                  ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
01077             {
01078                 // CMaterial Ref
01079                 CMaterial &material=mi->Materials[rdrPass.MaterialId];
01080 
01081                 // Setup VP material
01082                 if (useMeshVP)
01083                 {
01084                     _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
01085                 }
01086 
01087                 // Render with the Materials of the MeshInstance.
01088                 drv->activeIndexBuffer(rdrPass.PBlock);
01089                 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
01090             }
01091         }
01092     }
01093 
01094 
01095     // End VertexProgram effect
01096     if(useMeshVP)
01097     {
01098         // end it.
01099         _MeshVertexProgram->end(drv);
01100     }
01101 
01102 
01103     // bkup force normalisation.
01104     drv->forceNormalize(bkupNorm);
01105 
01106 }
01107 
01108 
01109 // ***************************************************************************
01110 void    CMeshMRMGeom::renderSkin(CTransformShape *trans, float alphaMRM)
01111 {
01112     H_AUTO( NL3D_MeshMRMGeom_renderSkin );
01113 
01114     if(_Lods.size()==0)
01115         return;
01116 
01117 
01118     // get the meshMRM instance. only CMeshMRMInstance is possible when skinned (not MultiLod)
01119     CMeshMRMInstance    *mi= safe_cast<CMeshMRMInstance*>(trans);
01120     // get a ptr on scene
01121     CScene              *ownerScene= mi->getOwnerScene();
01122     // get a ptr on renderTrav
01123     CRenderTrav         *renderTrav= &ownerScene->getRenderTrav();
01124     // get a ptr on the driver
01125     IDriver             *drv= renderTrav->getDriver();
01126     nlassert(drv);
01127 
01128 
01129     // choose the lod.
01130     float   alphaLod;
01131     sint    numLod= chooseLod(alphaMRM, alphaLod);
01132 
01133 
01134     // Render the choosen Lod.
01135     CLod    &lod= _Lods[numLod];
01136     if(lod.RdrPass.size()==0)
01137         return;
01138 
01139 
01140     /*
01141         YOYO: renderSkin() no more support vertexBufferHard()!!! for AGP Memory optimisation concern.
01142         AGP Skin rendering is made when supportSkinGrouping() is true
01143         Hence if a skin is to be rendered here, because it doesn't have a good vertex format, or it has
01144         MeshVertexProgram etc..., it will be rendered WITHOUT VBHard => slower.
01145     */
01146 
01147 
01148     // get the skeleton model to which I am skinned
01149     CSkeletonModel *skeleton;
01150     skeleton = mi->getSkeletonModel();
01151     // must be skinned for renderSkin()
01152     nlassert(_Skinned && mi->isSkinned() && skeleton);
01153     bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
01154     bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
01155     bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
01156 
01157 
01158     // Profiling
01159     //===========
01160     H_AUTO( NL3D_MeshMRMGeom_renderSkin_go );
01161 
01162 
01163     // Morphing
01164     // ========
01165     if (bMorphApplied)
01166     {
01167         // Since Skinned we must update original skin vertices and normals because skinning use it
01168         _MeshMorpher.initSkinned(&_VBufferOriginal,
01169                              &_VBufferFinal,
01170                              useTangentSpace,
01171                              &_OriginalSkinVertices,
01172                              &_OriginalSkinNormals,
01173                              useTangentSpace ? &_OriginalTGSpace : NULL,
01174                              true );
01175         _MeshMorpher.updateSkinned (mi->getBlendShapeFactors());
01176     }
01177 
01178     // Skinning.
01179     //===========
01180 
01181     // Never use RawSkin. Actually used in skinGrouping.
01182     updateRawSkinNormal(false, mi, numLod);
01183 
01184     // applySkin.
01185     //--------
01186 
01187     // If skin without normal (rare/useful?) always simple (slow) case.
01188     if(!useNormal)
01189     {
01190         // skinning with just position
01191         applySkin (lod, skeleton);
01192     }
01193     else
01194     {
01195         // apply skin for this Lod only.
01196         if (!useTangentSpace)
01197         {
01198             // skinning with normal, but no tangent space
01199             applySkinWithNormal (lod, skeleton);
01200         }
01201         else
01202         {
01203             // Tangent space stored in the last texture coordinate
01204             applySkinWithTangentSpace(lod, skeleton, _VBufferFinal.getNumTexCoordUsed() - 1);
01205         }
01206     }
01207 
01208     // endSkin.
01209     //--------
01210     // dirt this lod part. (NB: this is not optimal, but sufficient :) ).
01211     lod.OriginalSkinRestored= false;
01212 
01213 
01214     // NB: the skeleton matrix has already been setuped by CSkeletonModel
01215     // NB: the normalize flag has already been setuped by CSkeletonModel
01216 
01217 
01218     // Geomorph.
01219     //===========
01220     // Geomorph the choosen Lod (if not the coarser mesh).
01221     if(numLod>0)
01222     {
01223         applyGeomorph(lod.Geomorphs, alphaLod);
01224     }
01225 
01226 
01227     // Setup meshVertexProgram
01228     //===========
01229 
01230     // use MeshVertexProgram effect?
01231     bool    useMeshVP= _MeshVertexProgram != NULL;
01232     if( useMeshVP )
01233     {
01234         CMatrix     invertedObjectMatrix;
01235         invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
01236         // really ok if success to begin VP
01237         useMeshVP= _MeshVertexProgram->begin(drv, mi->getOwnerScene(), mi, invertedObjectMatrix, renderTrav->CamPos);
01238     }
01239 
01240 
01241     // Render the lod.
01242     //===========
01243     // active VB.
01244     drv->activeVertexBuffer(_VBufferFinal);
01245 
01246 
01247     // Render all pass.
01248     for(uint i=0;i<lod.RdrPass.size();i++)
01249     {
01250         CRdrPass    &rdrPass= lod.RdrPass[i];
01251 
01252         // CMaterial Ref
01253         CMaterial &material=mi->Materials[rdrPass.MaterialId];
01254 
01255         // Setup VP material
01256         if (useMeshVP)
01257         {
01258             _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBufferFinal);
01259         }
01260 
01261         // Render with the Materials of the MeshInstance.
01262         drv->activeIndexBuffer(rdrPass.PBlock);
01263         drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
01264     }
01265 
01266     // End VertexProgram effect
01267     if(useMeshVP)
01268     {
01269         // end it.
01270         _MeshVertexProgram->end(drv);
01271     }
01272 }
01273 
01274 
01275 // ***************************************************************************
01276 bool    CMeshMRMGeom::supportSkinGrouping() const
01277 {
01278     return _SupportSkinGrouping;
01279 }
01280 
01281 // ***************************************************************************
01282 sint    CMeshMRMGeom::renderSkinGroupGeom(CMeshMRMInstance  *mi, float alphaMRM, uint remainingVertices, uint8 *vbDest)
01283 {
01284     H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom )
01285 
01286     // NB: not need to test if _Lods.empty(), because already done through supportSkinGrouping()
01287 
01288     // get a ptr on scene
01289     CScene              *ownerScene= mi->getOwnerScene();
01290     // get a ptr on renderTrav
01291     CRenderTrav         *renderTrav= &ownerScene->getRenderTrav();
01292     // get a ptr on the driver
01293     IDriver             *drv= renderTrav->getDriver();
01294     nlassert(drv);
01295 
01296 
01297     // choose the lod.
01298     float   alphaLod;
01299     sint    numLod= chooseLod(alphaMRM, alphaLod);
01300     _LastLodComputed= numLod;
01301 
01302 
01303     // Render the choosen Lod.
01304     CLod    &lod= _Lods[numLod];
01305     if(lod.RdrPass.size()==0)
01306         // return no vertices added
01307         return 0;
01308 
01309     // If the Lod is too big to render in the VBufferHard
01310     if(lod.NWedges>remainingVertices)
01311         // return Failure
01312         return -1;
01313 
01314     // get the skeleton model to which I am skinned
01315     CSkeletonModel *skeleton;
01316     skeleton = mi->getSkeletonModel();
01317     // must be skinned for renderSkin()
01318     nlassert(_Skinned && mi->isSkinned() && skeleton);
01319     bool bMorphApplied = _MeshMorpher.BlendShapes.size() > 0;
01320     bool useNormal= (_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)!=0;
01321     nlassert(useNormal);
01322 
01323 
01324     // Profiling
01325     //===========
01326     H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpGeom_go );
01327 
01328 
01329     // Morphing
01330     // ========
01331 
01332     // Use RawSkin?. compute before morphing, cause of updateRawSkin
01333     updateRawSkinNormal(true, mi, numLod);
01334     nlassert(mi->_RawSkinCache);
01335 
01336     // Apply morph
01337     if (bMorphApplied)
01338     {
01339         // No need to manage lod.OriginalSkinRestored, since in case of SkinGroupGeom, the VBuffer final is not modified.
01340 
01341         // copy directly from the original VB, and apply BlendShapes. Dest is directly the RawSkin
01342         _MeshMorpher.updateRawSkin(&_VBufferFinal,
01343                                     mi->_RawSkinCache->VertexRemap,
01344                                     mi->getBlendShapeFactors());
01345     }
01346 
01347     // Skinning.
01348     //===========
01349 
01350     // NB: the skeleton matrix has already been setuped by CSkeletonModel
01351     // NB: the normalize flag has already been setuped by CSkeletonModel
01352 
01353     // applySkin with RawSkin.
01354     //--------
01355     // always RawSkin now in SkinGrouping, even with MeshMorpher
01356     {
01357         H_AUTO( NL3D_RawSkinning );
01358 
01359         // RawSkin do all the job in optimized way: Skinning, copy to VBHard and Geomorph.
01360 
01361         // skinning with normal, but no tangent space
01362         applyRawSkinWithNormal (lod, *(mi->_RawSkinCache), skeleton, vbDest, alphaLod);
01363 
01364         // Vertices are packed in RawSkin mode (ie no holes due to MRM!)
01365         return  mi->_RawSkinCache->Geomorphs.size() +
01366                 mi->_RawSkinCache->TotalSoftVertices +
01367                 mi->_RawSkinCache->TotalHardVertices;
01368     }
01369 }
01370 
01371 // ***************************************************************************
01372 void    CMeshMRMGeom::renderSkinGroupPrimitives(CMeshMRMInstance    *mi, uint baseVertex, std::vector<CSkinSpecularRdrPass> &specularRdrPasses, uint skinIndex)
01373 {
01374     H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpPrimitives );
01375 
01376     // get a ptr on scene
01377     CScene              *ownerScene= mi->getOwnerScene();
01378     // get a ptr on renderTrav
01379     CRenderTrav         *renderTrav= &ownerScene->getRenderTrav();
01380     // get a ptr on the driver
01381     IDriver             *drv= renderTrav->getDriver();
01382     nlassert(drv);
01383 
01384     // Get the lod choosen in renderSkinGroupGeom()
01385     CLod    &lod= _Lods[_LastLodComputed];
01386 
01387 
01388     // must update primitive cache
01389     updateShiftedTriangleCache(mi, _LastLodComputed, baseVertex);
01390     nlassert(mi->_ShiftedTriangleCache);
01391 
01392 
01393     // Render Triangles with cache
01394     //===========
01395     for(uint i=0;i<lod.RdrPass.size();i++)
01396     {
01397         CRdrPass    &rdrPass= lod.RdrPass[i];
01398 
01399         // CMaterial Ref
01400         CMaterial &material=mi->Materials[rdrPass.MaterialId];
01401 
01402         // TestYoyo. Material Speed Test
01403         /*if( material.getDiffuse()!=CRGBA(250, 251, 252) )
01404         {
01405             material.setDiffuse(CRGBA(250, 251, 252));
01406             // Set all texture the same.
01407             static CSmartPtr<ITexture>  pTexFile= new CTextureFile("fy_hom_visage_c1_fy_e1.tga");
01408             material.setTexture(0, pTexFile );
01409             // Remove Specular.
01410             if(material.getShader()==CMaterial::Specular)
01411             {
01412                 CSmartPtr<ITexture> tex= material.getTexture(0);
01413                 material.setShader(CMaterial::Normal);
01414                 material.setTexture(0, tex );
01415             }
01416             // Remove MakeUp
01417             material.setTexture(1, NULL);
01418         }*/
01419 
01420         // If the material is a specular material, don't render it now!
01421         if(material.getShader()==CMaterial::Specular)
01422         {
01423             // Add it to the rdrPass to sort!
01424             CSkinSpecularRdrPass    specRdrPass;
01425             specRdrPass.SkinIndex= skinIndex;
01426             specRdrPass.RdrPassIndex= i;
01427             // Get the handle of the specular Map as the sort Key
01428             ITexture    *specTex= material.getTexture(1);
01429             if(!specTex)
01430                 specRdrPass.SpecId= 0;
01431             else
01432                 specRdrPass.SpecId= drv->getTextureHandle( *specTex );
01433             // Append it to the list
01434             specularRdrPasses.push_back(specRdrPass);
01435         }
01436         else
01437         {
01438             // Get the shifted triangles.
01439             CShiftedTriangleCache::CRdrPass     &shiftedRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
01440 
01441             // Render with the Materials of the MeshInstance.
01442             drv->activeIndexBuffer(mi->_ShiftedTriangleCache->RawIndices);
01443             drv->renderTriangles(material, shiftedRdrPass.Triangles, shiftedRdrPass.NumTriangles);
01444         }
01445     }
01446 }
01447 
01448 
01449 // ***************************************************************************
01450 void    CMeshMRMGeom::renderSkinGroupSpecularRdrPass(CMeshMRMInstance   *mi, uint rdrPassId)
01451 {
01452     H_AUTO( NL3D_MeshMRMGeom_rdrSkinGrpSpecularRdrPass );
01453 
01454     // get a ptr on scene
01455     CScene              *ownerScene= mi->getOwnerScene();
01456     // get a ptr on renderTrav
01457     CRenderTrav         *renderTrav= &ownerScene->getRenderTrav();
01458     // get a ptr on the driver
01459     IDriver             *drv= renderTrav->getDriver();
01460     nlassert(drv);
01461 
01462     // Get the lod choosen in renderSkinGroupGeom()
01463     CLod    &lod= _Lods[_LastLodComputed];
01464 
01465 
01466     // _ShiftedTriangleCache must have been computed in renderSkinGroupPrimitives
01467     nlassert(mi->_ShiftedTriangleCache);
01468 
01469 
01470     // Render Triangles with cache
01471     //===========
01472     CRdrPass    &rdrPass= lod.RdrPass[rdrPassId];
01473 
01474     // CMaterial Ref
01475     CMaterial &material=mi->Materials[rdrPass.MaterialId];
01476 
01477     // Get the shifted triangles.
01478     CShiftedTriangleCache::CRdrPass     &shiftedRdrPass= mi->_ShiftedTriangleCache->RdrPass[rdrPassId];
01479 
01480     // Render with the Materials of the MeshInstance.
01481     drv->activeIndexBuffer(mi->_ShiftedTriangleCache->RawIndices);
01482     drv->renderTriangles(material, shiftedRdrPass.Triangles, shiftedRdrPass.NumTriangles);
01483 }
01484 
01485 
01486 // ***************************************************************************
01487 void    CMeshMRMGeom::updateShiftedTriangleCache(CMeshMRMInstance *mi, sint curLodId, uint baseVertex)
01488 {
01489     // if the instance has a cache, but not sync to us, delete it.
01490     if( mi->_ShiftedTriangleCache && (
01491         mi->_ShiftedTriangleCache->MeshDataId != _MeshDataId ||
01492         mi->_ShiftedTriangleCache->LodId != curLodId ||
01493         mi->_ShiftedTriangleCache->BaseVertex != baseVertex) )
01494     {
01495         mi->clearShiftedTriangleCache();
01496     }
01497 
01498     // If the instance has not a valid cache, must create it.
01499     if( !mi->_ShiftedTriangleCache )
01500     {
01501         mi->_ShiftedTriangleCache= new CShiftedTriangleCache;
01502         // Fill the cache Key.
01503         mi->_ShiftedTriangleCache->MeshDataId= _MeshDataId;
01504         mi->_ShiftedTriangleCache->LodId= curLodId;
01505         mi->_ShiftedTriangleCache->BaseVertex= baseVertex;
01506 
01507         // Build list of PBlock. From Lod, or from RawSkin cache.
01508         static  vector<CIndexBuffer*>   pbList;
01509         pbList.clear();
01510         if(mi->_RawSkinCache)
01511         {
01512             pbList.resize(mi->_RawSkinCache->RdrPass.size());
01513             for(uint i=0;i<pbList.size();i++)
01514             {
01515                 pbList[i]= &mi->_RawSkinCache->RdrPass[i];
01516             }
01517         }
01518         else
01519         {
01520             CLod    &lod= _Lods[curLodId];
01521             pbList.resize(lod.RdrPass.size());
01522             for(uint i=0;i<pbList.size();i++)
01523             {
01524                 pbList[i]= &lod.RdrPass[i].PBlock;
01525             }
01526         }
01527 
01528         // Build RdrPass
01529         mi->_ShiftedTriangleCache->RdrPass.resize(pbList.size());
01530 
01531         // First pass, count number of triangles, and fill header info
01532         uint    totalTri= 0;
01533         uint    i;
01534         for(i=0;i<pbList.size();i++)
01535         {
01536             mi->_ShiftedTriangleCache->RdrPass[i].NumTriangles= pbList[i]->getNumIndexes()/3;
01537             totalTri+= pbList[i]->getNumIndexes()/3;
01538         }
01539 
01540         // Allocate triangles indices.
01541         mi->_ShiftedTriangleCache->RawIndices.setFormat(NL_MESH_MRM_INDEX_FORMAT);
01542         mi->_ShiftedTriangleCache->RawIndices.setNumIndexes(totalTri*3);
01543 
01544         // Lock the index buffer
01545         CIndexBufferReadWrite ibaWrite;
01546         mi->_ShiftedTriangleCache->RawIndices.lock (ibaWrite);
01547         if (ibaWrite.getFormat() == CIndexBuffer::Indices32)
01548         {
01549             uint32 *dstPtr = (uint32 *) ibaWrite.getPtr();
01550             // Second pass, fill ptrs, and fill Arrays
01551             uint    indexTri= 0;
01552             for(i=0;i<pbList.size();i++)
01553             {
01554                 CShiftedTriangleCache::CRdrPass &dstRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
01555                 dstRdrPass.Triangles= indexTri*3;
01556 
01557                 // Fill the array
01558                 uint    numTris= pbList[i]->getNumIndexes()/3;
01559                 if(numTris)
01560                 {
01561                     uint    nIds= numTris*3;
01562                     // index, and fill
01563                     CIndexBufferRead ibaRead;
01564                     pbList[i]->lock (ibaRead);
01565                     nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
01566                     const uint32    *pSrcTri= (const uint32 *) ibaRead.getPtr();
01567                     uint32  *pDstTri= dstPtr+dstRdrPass.Triangles;
01568                     for(;nIds>0;nIds--,pSrcTri++,pDstTri++)
01569                         *pDstTri= *pSrcTri + baseVertex;
01570                 }
01571 
01572                 // Next
01573                 indexTri+= dstRdrPass.NumTriangles;
01574             }
01575         }
01576         else
01577         {
01578             nlassert(ibaWrite.getFormat() == CIndexBuffer::Indices16);
01579             uint16 *dstPtr = (uint16 *) ibaWrite.getPtr();
01580             // Second pass, fill ptrs, and fill Arrays
01581             uint    indexTri= 0;
01582             for(i=0;i<pbList.size();i++)
01583             {
01584                 CShiftedTriangleCache::CRdrPass &dstRdrPass= mi->_ShiftedTriangleCache->RdrPass[i];
01585                 dstRdrPass.Triangles= indexTri*3;
01586 
01587                 // Fill the array
01588                 uint    numTris= pbList[i]->getNumIndexes()/3;
01589                 if(numTris)
01590                 {
01591                     uint    nIds= numTris*3;
01592                     // index, and fill
01593                     CIndexBufferRead ibaRead;
01594                     pbList[i]->lock (ibaRead);
01595                     nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
01596                     const uint16    *pSrcTri= (const uint16 *) ibaRead.getPtr();
01597                     uint16  *pDstTri= (uint16 *) dstPtr+dstRdrPass.Triangles;
01598                     for(;nIds>0;nIds--,pSrcTri++,pDstTri++)
01599                         *pDstTri= *pSrcTri + baseVertex;
01600                 }
01601 
01602                 // Next
01603                 indexTri+= dstRdrPass.NumTriangles;
01604             }
01605         }
01606     }
01607 }
01608 
01609 
01610 // ***************************************************************************
01611 void    CMeshMRMGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01612 {
01613     // because of complexity, serial is separated in save / load.
01614 
01615     if(f.isReading())
01616         load(f);
01617     else
01618         save(f);
01619 
01620 }
01621 
01622 
01623 
01624 // ***************************************************************************
01625 sint    CMeshMRMGeom::loadHeader(NLMISC::IStream &f) throw(NLMISC::EStream)
01626 {
01627     /*
01628     Version 5:
01629         - Shadow Skinning
01630     Version 4:
01631         - serial SkinWeights per MRM, not per Lod
01632     Version 3:
01633         - Bones names.
01634     Version 2:
01635         - Mesh Vertex Program.
01636     Version 1:
01637         - added blend shapes
01638     Version 0:
01639         - base version.
01640     */
01641     sint    ver= f.serialVersion(5);
01642 
01643 
01644     // if >= version 3, serial boens names
01645     if(ver>=3)
01646     {
01647         f.serialCont (_BonesName);
01648     }
01649 
01650     // Version3-: Bones index are in skeleton model id list
01651     _BoneIdComputed = (ver < 3);
01652     // Must always recompute usage of parents of bones used.
01653     _BoneIdExtended = false;
01654 
01655     // Mesh Vertex Program.
01656     if (ver >= 2)
01657     {
01658         IMeshVertexProgram  *mvp= NULL;
01659         f.serialPolyPtr(mvp);
01660         _MeshVertexProgram= mvp;
01661     }
01662     else
01663     {
01664         // release vp
01665         _MeshVertexProgram= NULL;
01666     }
01667 
01668     // blend shapes
01669     if (ver >= 1)
01670         f.serial (_MeshMorpher);
01671 
01672     // serial Basic info.
01673     // ==================
01674     f.serial(_Skinned);
01675     f.serial(_BBox);
01676     f.serial(_LevelDetail.MaxFaceUsed);
01677     f.serial(_LevelDetail.MinFaceUsed);
01678     f.serial(_LevelDetail.DistanceFinest);
01679     f.serial(_LevelDetail.DistanceMiddle);
01680     f.serial(_LevelDetail.DistanceCoarsest);
01681     f.serial(_LevelDetail.OODistanceDelta);
01682     f.serial(_LevelDetail.DistancePow);
01683     // preload the Lods.
01684     f.serialCont(_LodInfos);
01685 
01686     // read/save number of wedges.
01687     /* NB: prepare memory space too for vertices.
01688         \todo yoyo: TODO_OPTIMIZE. for now there is no Lod memory profit with vertices / skinWeights.
01689         But resizing arrays is a problem because of reallocation...
01690     */
01691     uint32  nWedges;
01692     f.serial(nWedges);
01693     // Prepare the VBuffer.
01694     _VBufferFinal.serialHeader(f);
01695     // If skinned, must allocate skinWeights.
01696     contReset(_SkinWeights);
01697     if(_Skinned)
01698     {
01699         _SkinWeights.resize(nWedges);
01700     }
01701 
01702 
01703     // If new version, serial SkinWeights in header, not in lods.
01704     if(ver >= 4)
01705     {
01706         f.serialCont(_SkinWeights);
01707     }
01708 
01709 
01710     // if >= version 5, serial Shadow Skin Information
01711     if(ver>=5)
01712     {
01713         f.serialCont (_ShadowSkin.Vertices);
01714         f.serialCont (_ShadowSkin.Triangles);
01715     }
01716 
01717 
01718     // Serial lod offsets.
01719     // ==================
01720     // This is the reference pos, to load / save relative offsets.
01721     sint32          startPos = f.getPos();
01722     // Those are the lodOffsets, relative to startPos.
01723     vector<sint32>  lodOffsets;
01724     lodOffsets.resize(_LodInfos.size(), 0);
01725 
01726     // read all relative offsets, and build the absolute offset of LodInfos.
01727     for(uint i=0;i<_LodInfos.size(); i++)
01728     {
01729         f.serial(lodOffsets[i]);
01730         _LodInfos[i].LodOffset= startPos + lodOffsets[i];
01731     }
01732 
01733 
01734     // resest the Lod arrays. NB: each Lod is empty, and ready to receive Lod data.
01735     // ==================
01736     contReset(_Lods);
01737     _Lods.resize(_LodInfos.size());
01738 
01739     // Flag the fact that no lod is loaded for now.
01740     _NbLodLoaded= 0;
01741 
01742     // Inform that the mesh data has changed
01743     dirtMeshDataId();
01744 
01745 
01746     // Some runtime not serialized compilation
01747     compileRunTime();
01748 
01749     // return version of the header
01750     return ver;
01751 }
01752 
01753 
01754 // ***************************************************************************
01755 void    CMeshMRMGeom::load(NLMISC::IStream &f) throw(NLMISC::EStream)
01756 {
01757     // Load the header of the stream.
01758     // ==================
01759     sint    verHeader= loadHeader(f);
01760 
01761     // Read All lod subsets.
01762     // ==================
01763     for(uint i=0;i<_LodInfos.size(); i++)
01764     {
01765         // read the lod face data.
01766         f.serial(_Lods[i]);
01767         // read the lod vertex data.
01768         serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
01769         // if reading, must bkup all original vertices from VB.
01770         // this is done in serialLodVertexData(). by subset
01771     }
01772 
01773     // Now, all lods are loaded.
01774     _NbLodLoaded= _Lods.size();
01775 
01776     // If version doen't have boneNames, must build BoneId now.
01777     if(verHeader <= 2)
01778     {
01779         buildBoneUsageVer2 ();
01780     }
01781 }
01782 
01783 
01784 // ***************************************************************************
01785 void    CMeshMRMGeom::save(NLMISC::IStream &f) throw(NLMISC::EStream)
01786 {
01787     /*
01788     Version 5:
01789         - Shadow Skinning
01790     Version 4:
01791         - serial SkinWeights per MRM, not per Lod
01792     Version 3:
01793         - Bones names.
01794     Version 2:
01795         - Mesh Vertex Program.
01796     Version 1:
01797         - added blend shapes
01798     Version 0:
01799         - base version.
01800     */
01801     sint    ver= f.serialVersion(5);
01802     uint    i;
01803 
01804     // if >= version 3, serial bones names
01805     f.serialCont (_BonesName);
01806 
01807     // Warning, if you have skinned this shape, you can't write it anymore because skinning id have been changed!
01808     nlassert (_BoneIdComputed==false);
01809 
01810     // Mesh Vertex Program.
01811     if (ver >= 2)
01812     {
01813         IMeshVertexProgram  *mvp= NULL;
01814         mvp= _MeshVertexProgram;
01815         f.serialPolyPtr(mvp);
01816     }
01817 
01818     // blend shapes
01819     if (ver >= 1)
01820         f.serial (_MeshMorpher);
01821 
01822     // must have good original Skinned Vertex before writing.
01823     if( _Skinned )
01824     {
01825         restoreOriginalSkinVertices();
01826     }
01827 
01828 
01829     // serial Basic info.
01830     // ==================
01831     f.serial(_Skinned);
01832     f.serial(_BBox);
01833     f.serial(_LevelDetail.MaxFaceUsed);
01834     f.serial(_LevelDetail.MinFaceUsed);
01835     f.serial(_LevelDetail.DistanceFinest);
01836     f.serial(_LevelDetail.DistanceMiddle);
01837     f.serial(_LevelDetail.DistanceCoarsest);
01838     f.serial(_LevelDetail.OODistanceDelta);
01839     f.serial(_LevelDetail.DistancePow);
01840     f.serialCont(_LodInfos);
01841 
01842     // save number of wedges.
01843     uint32  nWedges;
01844     nWedges= _VBufferFinal.getNumVertices();
01845     f.serial(nWedges);
01846     // Save the VBuffer header.
01847     _VBufferFinal.serialHeader(f);
01848 
01849 
01850     // If new version, serial SkinWeights in header, not in lods.
01851     if(ver >= 4)
01852     {
01853         f.serialCont(_SkinWeights);
01854     }
01855 
01856     // if >= version 5, serial Shadow Skin Information
01857     if(ver>=5)
01858     {
01859         f.serialCont (_ShadowSkin.Vertices);
01860         f.serialCont (_ShadowSkin.Triangles);
01861     }
01862 
01863     // Serial lod offsets.
01864     // ==================
01865     // This is the reference pos, to load / save relative offsets.
01866     sint32          startPos = f.getPos();
01867     // Those are the lodOffsets, relative to startPos.
01868     vector<sint32>  lodOffsets;
01869     lodOffsets.resize(_LodInfos.size(), 0);
01870 
01871     // write all dummy offset. For now (since we don't know what to set), compute the offset of
01872     // the sint32 to come back in serial lod parts below.
01873     for(i=0;i<_LodInfos.size(); i++)
01874     {
01875         lodOffsets[i]= f.getPos();
01876         f.serial(lodOffsets[i]);
01877     }
01878 
01879     // Serial lod subsets.
01880     // ==================
01881 
01882     // Save all the lods.
01883     for(i=0;i<_LodInfos.size(); i++)
01884     {
01885         // get current absolute position.
01886         sint32  absCurPos= f.getPos();
01887 
01888         // come back to "relative lodOffset" absolute position in the stream. (temp stored in lodOffset[i]).
01889         f.seek(lodOffsets[i], NLMISC::IStream::begin);
01890 
01891         // write the relative position of the lod to the stream.
01892         sint32  relCurPos= absCurPos - startPos;
01893         f.serial(relCurPos);
01894 
01895         // come back to absCurPos, to save the lod.
01896         f.seek(absCurPos, NLMISC::IStream::begin);
01897 
01898         // And so now, save the lod.
01899         // write the lod face data.
01900         f.serial(_Lods[i]);
01901         // write the lod vertex data.
01902         serialLodVertexData(f, _LodInfos[i].StartAddWedge, _LodInfos[i].EndAddWedges);
01903     }
01904 
01905 
01906 }
01907 
01908 
01909 
01910 // ***************************************************************************
01911 void    CMeshMRMGeom::serialLodVertexData(NLMISC::IStream &f, uint startWedge, uint endWedge)
01912 {
01913     /*
01914     Version 1:
01915         - serial SkinWeights per MRM, not per Lod
01916     */
01917     sint    ver= f.serialVersion(1);
01918 
01919     // VBuffer part.
01920     _VBufferFinal.serialSubset(f, startWedge, endWedge);
01921 
01922     // SkinWeights.
01923     if(_Skinned)
01924     {
01925         // Serialize SkinWeight per lod only for old versions.
01926         if(ver<1)
01927         {
01928             for(uint i= startWedge; i<endWedge; i++)
01929             {
01930                 f.serial(_SkinWeights[i]);
01931             }
01932         }
01933         // if reading, must copy original vertices from VB.
01934         if( f.isReading())
01935         {
01936             bkupOriginalSkinVerticesSubset(startWedge, endWedge);
01937         }
01938     }
01939 }
01940 
01941 
01942 
01943 // ***************************************************************************
01944 void    CMeshMRMGeom::loadFirstLod(NLMISC::IStream &f)
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     // If all is loaded, quit.
01993     if(getNbLodLoaded() == getNbLod())
01994         return;
01995 
01996     // Set pos to good lod.
01997     f.seek(_LodInfos[_NbLodLoaded].LodOffset, NLMISC::IStream::begin);
01998 
01999     // Serial this lod data.
02000     // read the lod face data.
02001     f.serial(_Lods[_NbLodLoaded]);
02002     // read the lod vertex data.
02003     serialLodVertexData(f, _LodInfos[_NbLodLoaded].StartAddWedge, _LodInfos[_NbLodLoaded].EndAddWedges);
02004     // if reading, must bkup all original vertices from VB.
02005     // this is done in serialLodVertexData(). by subset
02006 
02007 
02008     // Inc LodLoaded count.
02009     _NbLodLoaded++;
02010 }
02011 
02012 
02013 // ***************************************************************************
02014 void    CMeshMRMGeom::unloadNextLod(NLMISC::IStream &f)
02015 {
02016     // If just first lod remain (or no lod), quit
02017     if(getNbLodLoaded() <= 1)
02018         return;
02019 
02020     // Reset the entire Lod object. (Free Memory).
02021     contReset(_Lods[_NbLodLoaded-1]);
02022 
02023 
02024     // Dec LodLoaded count.
02025     _NbLodLoaded--;
02026 }
02027 
02028 
02029 // ***************************************************************************
02030 void    CMeshMRMGeom::bkupOriginalSkinVertices()
02031 {
02032     nlassert(_Skinned);
02033 
02034     // bkup the entire array.
02035     bkupOriginalSkinVerticesSubset(0, _VBufferFinal.getNumVertices());
02036 }
02037 
02038 
02039 // ***************************************************************************
02040 void    CMeshMRMGeom::bkupOriginalSkinVerticesSubset(uint wedgeStart, uint wedgeEnd)
02041 {
02042     nlassert(_Skinned);
02043 
02044     CVertexBufferReadWrite vba;
02045     _VBufferFinal.lock (vba);
02046 
02047     // Copy VBuffer content into Original vertices normals.
02048     if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
02049     {
02050         // copy vertices from VBuffer. (NB: unuseful geomorphed vertices are still copied, but doesn't matter).
02051         _OriginalSkinVertices.resize(_VBufferFinal.getNumVertices());
02052         for(uint i=wedgeStart; i<wedgeEnd;i++)
02053         {
02054             _OriginalSkinVertices[i]= *vba.getVertexCoordPointer(i);
02055         }
02056     }
02057     if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
02058     {
02059         // copy normals from VBuffer. (NB: unuseful geomorphed normals are still copied, but doesn't matter).
02060         _OriginalSkinNormals.resize(_VBufferFinal.getNumVertices());
02061         for(uint i=wedgeStart; i<wedgeEnd;i++)
02062         {
02063             _OriginalSkinNormals[i]= *vba.getNormalCoordPointer(i);
02064         }
02065     }
02066 
02067     // is there tangent space added ?
02068     if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
02069     {
02070         // yes, backup it
02071         nlassert(_VBufferFinal.getNumTexCoordUsed() > 0);
02072         uint tgSpaceStage = _VBufferFinal.getNumTexCoordUsed() - 1;
02073         _OriginalTGSpace.resize(_VBufferFinal.getNumVertices());
02074         for(uint i=wedgeStart; i<wedgeEnd;i++)
02075         {
02076             _OriginalTGSpace[i]= *(CVector*)vba.getTexCoordPointer(i, tgSpaceStage);
02077         }
02078     }
02079 }
02080 
02081 
02082 // ***************************************************************************
02083 void    CMeshMRMGeom::restoreOriginalSkinVertices()
02084 {
02085     nlassert(_Skinned);
02086 
02087     CVertexBufferReadWrite vba;
02088     _VBufferFinal.lock (vba);
02089 
02090     // Copy VBuffer content into Original vertices normals.
02091     if(_VBufferFinal.getVertexFormat() & CVertexBuffer::PositionFlag)
02092     {
02093         // copy vertices from VBuffer. (NB: unuseful geomorphed vertices are still copied, but doesn't matter).
02094         for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
02095         {
02096             *vba.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
02097         }
02098     }
02099     if(_VBufferFinal.getVertexFormat() & CVertexBuffer::NormalFlag)
02100     {
02101         // copy normals from VBuffer. (NB: unuseful geomorphed normals are still copied, but doesn't matter).
02102         for(uint i=0; i<_VBufferFinal.getNumVertices();i++)
02103         {
02104             *vba.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
02105         }
02106     }
02107     if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
02108     {
02109         uint numTexCoords = _VBufferFinal.getNumTexCoordUsed();
02110         nlassert(numTexCoords >= 2);
02111         nlassert(_OriginalTGSpace.size() == _VBufferFinal.getNumVertices());
02112         // copy tangent space vectors
02113         for(uint i = 0; i < _VBufferFinal.getNumVertices(); ++i)
02114         {
02115             *(CVector*)vba.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
02116         }
02117     }
02118 }
02119 
02120 
02121 // ***************************************************************************
02122 void    CMeshMRMGeom::restoreOriginalSkinPart(CLod &lod)
02123 {
02124     nlassert(_Skinned);
02125 
02126 
02127     /*
02128         YOYO: _Skinned mrms no more support vertexBufferHard
02129         see note in renderSkin()
02130     */
02131 
02132     // get vertexPtr / normalOff.
02133     //===========================
02134     CVertexBufferReadWrite vba;
02135     _VBufferFinal.lock (vba);
02136     uint8       *destVertexPtr= (uint8*)vba.getVertexCoordPointer();
02137     uint        flags= _VBufferFinal.getVertexFormat();
02138     sint32      vertexSize= _VBufferFinal.getVertexSize();
02139     // must have XYZ.
02140     nlassert(flags & CVertexBuffer::PositionFlag);
02141 
02142     // Compute offset of each component of the VB.
02143     sint32      normalOff;
02144     if(flags & CVertexBuffer::NormalFlag)
02145         normalOff= _VBufferFinal.getNormalOff();
02146     else
02147         normalOff= 0;
02148 
02149 
02150     // compute src array.
02151     CVector             *srcVertexPtr;
02152     CVector             *srcNormalPtr= NULL;
02153     srcVertexPtr= &_OriginalSkinVertices[0];
02154     if(normalOff)
02155         srcNormalPtr= &(_OriginalSkinNormals[0]);
02156 
02157 
02158     // copy skinning.
02159     //===========================
02160     for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
02161     {
02162         uint        nInf= lod.InfluencedVertices[i].size();
02163         if( nInf==0 )
02164             continue;
02165         uint32      *infPtr= &(lod.InfluencedVertices[i][0]);
02166 
02167         //  for all InfluencedVertices only.
02168         for(;nInf>0;nInf--, infPtr++)
02169         {
02170             uint    index= *infPtr;
02171             CVector             *srcVertex= srcVertexPtr + index;
02172             CVector             *srcNormal= srcNormalPtr + index;
02173             uint8               *dstVertexVB= destVertexPtr + index * vertexSize;
02174             CVector             *dstVertex= (CVector*)(dstVertexVB);
02175             CVector             *dstNormal= (CVector*)(dstVertexVB + normalOff);
02176 
02177 
02178             // Vertex.
02179             *dstVertex= *srcVertex;
02180             // Normal.
02181             if(normalOff)
02182                 *dstNormal= *srcNormal;
02183         }
02184     }
02185 
02186 
02187     // clean this lod part. (NB: this is not optimal, but sufficient :) ).
02188     lod.OriginalSkinRestored= true;
02189 }
02190 
02191 // ***************************************************************************
02192 
02193 float CMeshMRMGeom::getNumTriangles (float distance)
02194 {
02195     // NB: this is an approximation, but this is continious.
02196     return _LevelDetail.getNumTriangles(distance);
02197 }
02198 
02199 
02200 
02201 // ***************************************************************************
02202 void    CMeshMRMGeom::computeBonesId (CSkeletonModel *skeleton)
02203 {
02204     // Already computed ?
02205     if (!_BoneIdComputed)
02206     {
02207         // Get a pointer on the skeleton
02208         nlassert (skeleton);
02209         if (skeleton)
02210         {
02211             // **** For each bones, compute remap
02212             std::vector<uint> remap;
02213             skeleton->remapSkinBones(_BonesName, _BonesId, remap);
02214 
02215 
02216             // **** Remap the vertices, and compute Bone Spheres.
02217 
02218             // Find the Geomorph space: to process only real vertices, not geomorphed ones.
02219             uint    nGeomSpace= 0;
02220             uint    lod;
02221             for (lod=0; lod<_Lods.size(); lod++)
02222             {
02223                 nGeomSpace= max(nGeomSpace, (uint)_Lods[lod].Geomorphs.size());
02224             }
02225 
02226             // Prepare Sphere compute
02227             nlassert(_OriginalSkinVertices.size() == _SkinWeights.size());
02228             static std::vector<CAABBox>     boneBBoxes;
02229             static std::vector<bool>        boneBBEmpty;
02230             boneBBoxes.clear();
02231             boneBBEmpty.clear();
02232             boneBBoxes.resize(_BonesId.size());
02233             boneBBEmpty.resize(_BonesId.size(), true);
02234 
02235             // Remap the vertex, and compute the bone spheres. see CTransform::getSkinBoneSphere() doc.
02236             // for true vertices
02237             uint vert;
02238             for (vert=nGeomSpace; vert<_SkinWeights.size(); vert++)
02239             {
02240                 // get the vertex position.
02241                 CVector     vertex= _OriginalSkinVertices[vert];
02242 
02243                 // For each weight
02244                 uint weight;
02245                 for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
02246                 {
02247                     // Active ?
02248                     if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
02249                     {
02250                         // Check id
02251                         uint    srcId= _SkinWeights[vert].MatrixId[weight];
02252                         nlassert (srcId < remap.size());
02253                         // remap
02254                         _SkinWeights[vert].MatrixId[weight] = remap[srcId];
02255 
02256                         // if the boneId is valid (ie found)
02257                         if(_BonesId[srcId]>=0)
02258                         {
02259                             // transform the vertex pos in BoneSpace
02260                             CVector     p= skeleton->Bones[_BonesId[srcId]].getBoneBase().InvBindPos * vertex;
02261                             // extend the bone bbox.
02262                             if(boneBBEmpty[srcId])
02263                             {
02264                                 boneBBoxes[srcId].setCenter(p);
02265                                 boneBBEmpty[srcId]= false;
02266                             }
02267                             else
02268                             {
02269                                 boneBBoxes[srcId].extend(p);
02270                             }
02271                         }
02272                     }
02273                     else
02274                         break;
02275                 }
02276             }
02277 
02278             // Compile spheres
02279             _BonesSphere.resize(_BonesId.size());
02280             for(uint bone=0;bone<_BonesSphere.size();bone++)
02281             {
02282                 // If the bone is empty, mark with -1 in the radius.
02283                 if(boneBBEmpty[bone])
02284                 {
02285                     _BonesSphere[bone].Radius= -1;
02286                 }
02287                 else
02288                 {
02289                     _BonesSphere[bone].Center= boneBBoxes[bone].getCenter();
02290                     _BonesSphere[bone].Radius= boneBBoxes[bone].getRadius();
02291                 }
02292             }
02293 
02294             // **** Remap the vertex influence by lods
02295             for (lod=0; lod<_Lods.size(); lod++)
02296             {
02297                 // For each matrix used
02298                 uint matrix;
02299                 for (matrix=0; matrix<_Lods[lod].MatrixInfluences.size(); matrix++)
02300                 {
02301                     // Check
02302                     nlassert (_Lods[lod].MatrixInfluences[matrix]<remap.size());
02303 
02304                     // Remap
02305                     _Lods[lod].MatrixInfluences[matrix] = remap[_Lods[lod].MatrixInfluences[matrix]];
02306                 }
02307             }
02308 
02309             // **** Remap Shadow Vertices.
02310             for(vert=0;vert<_ShadowSkin.Vertices.size();vert++)
02311             {
02312                 CShadowVertex   &v= _ShadowSkin.Vertices[vert];
02313                 // Check id
02314                 nlassert (v.MatrixId < remap.size());
02315                 v.MatrixId= remap[v.MatrixId];
02316             }
02317 
02318             // Computed
02319             _BoneIdComputed = true;
02320         }
02321     }
02322 
02323     // Already extended ?
02324     if (!_BoneIdExtended)
02325     {
02326         nlassert (skeleton);
02327         if (skeleton)
02328         {
02329             // the total bone Usage of the mesh.
02330             vector<bool>    boneUsage;
02331             boneUsage.resize(skeleton->Bones.size(), false);
02332 
02333             // for all Bones marked as valid.
02334             uint    i;
02335             for(i=0; i<_BonesId.size(); i++)
02336             {
02337                 // if not a valid boneId, skip it.
02338                 if(_BonesId[i]<0)
02339                     continue;
02340 
02341                 // mark him and his father in boneUsage.
02342                 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
02343             }
02344 
02345             // fill _BonesIdExt with bones of _BonesId and their parents.
02346             _BonesIdExt.clear();
02347             for(i=0; i<boneUsage.size();i++)
02348             {
02349                 // if the bone is used by the mesh, add it to BoneIdExt.
02350                 if(boneUsage[i])
02351                     _BonesIdExt.push_back(i);
02352             }
02353 
02354         }
02355 
02356         // Extended
02357         _BoneIdExtended= true;
02358     }
02359 
02360 }
02361 
02362 
02363 // ***************************************************************************
02364 void    CMeshMRMGeom::buildBoneUsageVer2 ()
02365 {
02366     if(_Skinned)
02367     {
02368         // parse all vertices, couting MaxBoneId used.
02369         uint32  maxBoneId= 0;
02370         // for each vertex
02371         uint vert;
02372         for (vert=0; vert<_SkinWeights.size(); vert++)
02373         {
02374             // For each weight
02375             for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
02376             {
02377                 // Active ?
02378                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
02379                 {
02380                     maxBoneId= max(_SkinWeights[vert].MatrixId[weight], maxBoneId);
02381                 }
02382             }
02383         }
02384 
02385         // alloc an array of maxBoneId+1, reset to 0.
02386         std::vector<uint8>      boneUsage;
02387         boneUsage.resize(maxBoneId+1, 0);
02388 
02389         // reparse all vertices, counting usage for each bone.
02390         for (vert=0; vert<_SkinWeights.size(); vert++)
02391         {
02392             // For each weight
02393             for (uint weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
02394             {
02395                 // Active ?
02396                 if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
02397                 {
02398                     // mark this bone as used.
02399                     boneUsage[_SkinWeights[vert].MatrixId[weight]]= 1;
02400                 }
02401             }
02402         }
02403 
02404         // For each bone used
02405         _BonesId.clear();
02406         for(uint i=0; i<boneUsage.size();i++)
02407         {
02408             // if the bone is used by the mesh, add it to BoneId.
02409             if(boneUsage[i])
02410                 _BonesId.push_back(i);
02411         }
02412     }
02413 }
02414 
02415 
02416 // ***************************************************************************
02417 void    CMeshMRMGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
02418 {
02419     // For all Bones used.
02420     for(uint i=0; i<_BonesIdExt.size();i++)
02421     {
02422         uint    boneId= _BonesIdExt[i];
02423         // Some explicit Error.
02424         if(boneId>=sm->Bones.size())
02425             nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
02426         // increment or decrement not Forced, because CMeshGeom use getActiveBoneSkinMatrix().
02427         if(increment)
02428             sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
02429         else
02430             sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
02431     }
02432 }
02433 
02434 
02435 // ***************************************************************************
02436 void    CMeshMRMGeom::compileRunTime()
02437 {
02438     _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
02439 
02440     // Compute if can support SkinGrouping rendering
02441     if(_Lods.size()==0 || !_Skinned)
02442     {
02443         _SupportSkinGrouping= false;
02444         _SupportShadowSkinGrouping= false;
02445     }
02446     else
02447     {
02448         // The Mesh must follow those restrictions, to support group skinning
02449         _SupportSkinGrouping=
02450             _VBufferFinal.getVertexFormat() == NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT &&
02451             _VBufferFinal.getNumVertices() < NL3D_MESH_SKIN_MANAGER_MAXVERTICES &&
02452             !_MeshVertexProgram;
02453 
02454         // Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
02455         _SupportShadowSkinGrouping= !_ShadowSkin.Vertices.empty() &&
02456             NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT==CVertexBuffer::PositionFlag &&
02457             _ShadowSkin.Vertices.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES;
02458     }
02459 
02460     // Support MeshBlockRendering only if not skinned/meshMorphed.
02461     _SupportMeshBlockRendering= !_Skinned && _MeshMorpher.BlendShapes.size()==0;
02462 
02463     // \todo yoyo: support later MeshVertexProgram
02464     _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MeshVertexProgram==NULL;
02465 }
02466 
02467 
02468 // ***************************************************************************
02469 void    CMeshMRMGeom::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags)
02470 {
02471     // if no _Lods, no draw
02472     if(_Lods.empty())
02473         return;
02474 
02475     // get the result of the Load Balancing.
02476     float   alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
02477 
02478     // choose the lod.
02479     float   alphaLod;
02480     sint    numLod= chooseLod(alphaMRM, alphaLod);
02481 
02482     // Render the choosen Lod.
02483     CLod    &lod= _Lods[numLod];
02484 
02485     // get the mesh instance.
02486     CMeshBaseInstance   *mi= safe_cast<CMeshBaseInstance*>(trans);
02487 
02488     // Profile all pass.
02489     uint    triCount= 0;
02490     for (uint i=0;i<lod.RdrPass.size();i++)
02491     {
02492         CRdrPass    &rdrPass= lod.RdrPass[i];
02493         // Profile with the Materials of the MeshInstance.
02494         if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
02495              ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
02496         {
02497             triCount+= rdrPass.PBlock.getNumIndexes()/3;
02498         }
02499     }
02500 
02501     // Profile
02502     if(triCount)
02503     {
02504         // tri per VBFormat
02505         rdrTrav->Scene->incrementProfileTriVBFormat(rdrTrav->Scene->BenchRes.MeshMRMProfileTriVBFormat,
02506             _VBufferFinal.getVertexFormat(), triCount);
02507 
02508         // VBHard
02509         if(_VBufferFinal.getPreferredMemory()!=CVertexBuffer::RAMPreferred)
02510             rdrTrav->Scene->BenchRes.NumMeshMRMVBufferHard++;
02511         else
02512             rdrTrav->Scene->BenchRes.NumMeshMRMVBufferStd++;
02513 
02514         // rendered in BlockRendering, only if not transparent pass (known it if RenderTransparentMaterial is set)
02515         if(supportMeshBlockRendering() && (rdrFlags & IMeshGeom::RenderTransparentMaterial)==0 )
02516         {
02517             if(isMeshInVBHeap())
02518             {
02519                 rdrTrav->Scene->BenchRes.NumMeshMRMRdrBlockWithVBHeap++;
02520                 rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrBlockWithVBHeap+= triCount;
02521             }
02522             else
02523             {
02524                 rdrTrav->Scene->BenchRes.NumMeshMRMRdrBlock++;
02525                 rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrBlock+= triCount;
02526             }
02527         }
02528         else
02529         {
02530             rdrTrav->Scene->BenchRes.NumMeshMRMRdrNormal++;
02531             rdrTrav->Scene->BenchRes.NumMeshMRMTriRdrNormal+= triCount;
02532         }
02533     }
02534 }
02535 
02536 
02537 // ***************************************************************************
02538 bool    CMeshMRMGeom::buildGeometryForLod(uint lodId, std::vector<CVector> &vertices, std::vector<uint32> &triangles) const
02539 {
02540     if(lodId>=_Lods.size())
02541         return false;
02542 
02543     // avoid slow lock
02544     if(_VBufferFinal.isResident())
02545         return false;
02546 
02547     // clear first
02548     vertices.clear();
02549     triangles.clear();
02550 
02551 
02552     // **** First, for the lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
02553     static vector<sint>     vertexRemap;
02554     vertexRemap.clear();
02555     // -1 means "not used"
02556     vertexRemap.resize(_VBufferFinal.getNumVertices(), -1);
02557     // count also total number of indices
02558     uint    numTotalIndices= 0;
02559     // Parse all triangles.
02560     uint    i;
02561     for(i=0;i<getNbRdrPass(lodId);i++)
02562     {
02563         const CIndexBuffer &pb = getRdrPassPrimitiveBlock(lodId, i);
02564         // avoid slow lock
02565         if(pb.isResident())
02566             return false;
02567         CIndexBufferRead iba;
02568         pb.lock (iba);
02569         nlassert(iba.getFormat()==NL_MESH_MRM_INDEX_FORMAT);
02570         TMeshMRMIndexType *src= (TMeshMRMIndexType *) iba.getPtr();
02571         for(uint n= pb.getNumIndexes();n>0;n--, src++)
02572         {
02573             uint    idx= *src;
02574             // Flag the vertex with its own index => used.
02575             vertexRemap[idx]= idx;
02576         }
02577 
02578         // total num indices
02579         numTotalIndices+= pb.getNumIndexes();
02580     }
02581     // Special for Geomorphs: must take The End target vertex.
02582     const std::vector<CMRMWedgeGeom>    &geomorphs= getGeomorphs(lodId);
02583     for(i=0;i<geomorphs.size();i++)
02584     {
02585         uint    trueIdx= geomorphs[i].End;
02586         // map to the Geomorph Target.
02587         vertexRemap[i]= trueIdx;
02588         // mark also the real vertex used as used.
02589         vertexRemap[trueIdx]= trueIdx;
02590     }
02591     // if no index, abort
02592     if(numTotalIndices==0)
02593         return false;
02594 
02595 
02596     // **** count number of vertices really used (skip geomorphs)
02597     uint    numUsedVertices=0;
02598     for(i=geomorphs.size();i<vertexRemap.size();i++)
02599     {
02600         if(vertexRemap[i]>=0)
02601             numUsedVertices++;
02602     }
02603     // if none, abort
02604     if(numUsedVertices==0)
02605         return false;
02606     // Then we have our vertices size
02607     vertices.resize(numUsedVertices);
02608 
02609 
02610     // **** Fill the vertex geometry
02611     {
02612         // Lock input VB
02613         CVertexBufferRead   vba;
02614         _VBufferFinal.lock(vba);
02615 
02616         // get the start vert, beginning at end of geomorphs
02617         const uint8 *pSrcVert= (const uint8*)vba.getVertexCoordPointer(geomorphs.size());
02618         uint32      vertSize= _VBufferFinal.getVertexSize();
02619         CVector     *pDstVert= &vertices[0];
02620         uint        dstIndex= 0;
02621 
02622         // Then run all input vertices (skip geomorphs)
02623         for(i=geomorphs.size();i<vertexRemap.size();i++)
02624         {
02625             // if the vertex is used
02626             if(vertexRemap[i]>=0)
02627             {
02628                 // Final remaping of vertex to final index
02629                 vertexRemap[i]= dstIndex;
02630                 // copy to dest
02631                 *pDstVert= *(CVector*)pSrcVert;
02632 
02633                 // next dest
02634                 pDstVert++;
02635                 dstIndex++;
02636             }
02637 
02638             // next src
02639             pSrcVert+= vertSize;
02640         }
02641 
02642         // should have fill the entire buffer
02643         nlassert(uint(pDstVert-(&vertices[0]))==numUsedVertices);
02644 
02645         // Resolve remapping for geomorphs
02646         for(i=0;i<geomorphs.size();i++)
02647         {
02648             // use the same final index as the EndGeomorph vertex
02649             uint    endGeomIdx= vertexRemap[i];
02650             vertexRemap[i]= vertexRemap[endGeomIdx];
02651         }
02652     }
02653 
02654 
02655     // **** Fill the indices
02656     triangles.resize(numTotalIndices);
02657     uint32  *pDstIndex= &triangles[0];
02658     // for all render pass
02659     for(i=0;i<getNbRdrPass(lodId);i++)
02660     {
02661         const CIndexBuffer &pb = getRdrPassPrimitiveBlock(lodId, i);
02662         CIndexBufferRead iba;
02663         pb.lock (iba);
02664         TMeshMRMIndexType *src= (TMeshMRMIndexType *) iba.getPtr();
02665         for(uint n= pb.getNumIndexes();n>0;n--, src++)
02666         {
02667             // resolve any geomorph, and final remapping
02668             uint    remapedIdx= vertexRemap[*src];
02669             nlassert(remapedIdx<vertices.size());
02670             *pDstIndex= remapedIdx;
02671             pDstIndex++;
02672         }
02673     }
02674     // should have filled the entire buffer
02675     nlassert(uint(pDstIndex-(&triangles[0]))==numTotalIndices);
02676 
02677 
02678     return true;
02679 }
02680 
02681 
02682 
02683 // ***************************************************************************
02684 // ***************************************************************************
02685 // Mesh Block Render Interface
02686 // ***************************************************************************
02687 // ***************************************************************************
02688 
02689 
02690 // ***************************************************************************
02691 bool    CMeshMRMGeom::supportMeshBlockRendering () const
02692 {
02693     /*
02694         Yoyo: Don't Support It for MRM because too Slow!!
02695         The problem is that lock() unlock() on each instance, on the same VBHeap IS AS SLOWER AS
02696         VB switching.
02697 
02698         TODO_OPTIMIZE: find a way to optimize MRM.
02699     */
02700     return false;
02701     //return _SupportMeshBlockRendering;
02702 }
02703 
02704 // ***************************************************************************
02705 bool    CMeshMRMGeom::sortPerMaterial() const
02706 {
02707     // Can't do it per material since 2 lods may not have the same number of RdrPass!!
02708     return false;
02709 }
02710 // ***************************************************************************
02711 uint    CMeshMRMGeom::getNumRdrPassesForMesh() const
02712 {
02713     // not used...
02714     return 0;
02715 
02716 }
02717 // ***************************************************************************
02718 uint    CMeshMRMGeom::getNumRdrPassesForInstance(CMeshBaseInstance *inst) const
02719 {
02720     return _Lods[_MBRCurrentLodId].RdrPass.size();
02721 }
02722 // ***************************************************************************
02723 void    CMeshMRMGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
02724 {
02725     if(_Lods.empty())
02726         return;
02727 
02728     IDriver *drv= rdrCtx.Driver;
02729 
02730     if(rdrCtx.RenderThroughVBHeap)
02731     {
02732         // Don't setup VB in this case, since use the VBHeap setuped one.
02733     }
02734     else
02735     {
02736         drv->activeVertexBuffer(_VBufferFinal);
02737     }
02738 
02739 
02740     // force normalisation of normals..
02741     _MBRBkupNormalize= drv->isForceNormalize();
02742     drv->forceNormalize(true);
02743 
02744 }
02745 // ***************************************************************************
02746 void    CMeshMRMGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst)
02747 {
02748     H_AUTO( NL3D_MeshMRMGeom_RenderNormal );
02749 
02750     if(_Lods.empty())
02751         return;
02752 
02753     // get the result of the Load Balancing.
02754     float   alphaMRM= _LevelDetail.getLevelDetailFromPolyCount(polygonCount);
02755 
02756     // choose the lod.
02757     float   alphaLod;
02758     _MBRCurrentLodId= chooseLod(alphaMRM, alphaLod);
02759 
02760     // Geomorph the choosen Lod (if not the coarser mesh).
02761     if(_MBRCurrentLodId>0)
02762     {
02763         if(rdrCtx.RenderThroughVBHeap)
02764             applyGeomorphWithVBHardPtr(_Lods[_MBRCurrentLodId].Geomorphs, alphaLod, (uint8*)vbDst);
02765         else
02766             applyGeomorph(_Lods[_MBRCurrentLodId].Geomorphs, alphaLod);
02767     }
02768 
02769     // set the instance worldmatrix.
02770     rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
02771 
02772     // setupLighting.
02773     inst->changeLightSetup(rdrCtx.RenderTrav);
02774 }
02775 // ***************************************************************************
02776 void    CMeshMRMGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
02777 {
02778     if(_Lods.empty())
02779         return;
02780 
02781     CLod        &lod= _Lods[_MBRCurrentLodId];
02782     CRdrPass    &rdrPass= lod.RdrPass[rdrPassId];
02783 
02784     if ( mi->Materials[rdrPass.MaterialId].getBlend() == false )
02785     {
02786         // CMaterial Ref
02787         CMaterial &material=mi->Materials[rdrPass.MaterialId];
02788 
02789         // Render with the Materials of the MeshInstance.
02790         if(rdrCtx.RenderThroughVBHeap)
02791         {
02792             // render shifted primitives
02793             rdrCtx.Driver->activeIndexBuffer(rdrPass.VBHeapPBlock);
02794             rdrCtx.Driver->renderTriangles(material, 0, rdrPass.VBHeapPBlock.getNumIndexes()/3);
02795         }
02796         else
02797         {
02798             rdrCtx.Driver->activeIndexBuffer(rdrPass.PBlock);
02799             rdrCtx.Driver->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
02800         }
02801     }
02802 }
02803 
02804 // ***************************************************************************
02805 void    CMeshMRMGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
02806 {
02807     if(_Lods.empty())
02808         return;
02809 
02810     // bkup force normalisation.
02811     rdrCtx.Driver->forceNormalize(_MBRBkupNormalize);
02812 }
02813 
02814 
02815 // ***************************************************************************
02816 bool    CMeshMRMGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
02817 {
02818     // CMeshMRMGeom support VBHeap rendering, assuming _SupportMeshBlockRendering is true
02819     vertexFormat= _VBufferFinal.getVertexFormat();
02820     numVertices= _VBufferFinal.getNumVertices();
02821     return _SupportMeshBlockRendering;
02822 }
02823 
02824 // ***************************************************************************
02825 void    CMeshMRMGeom::computeMeshVBHeap(void *dst, uint indexStart)
02826 {
02827     // Fill dst with Buffer content.
02828     CVertexBufferRead vba;
02829     _VBufferFinal.lock (vba);
02830     memcpy(dst, vba.getVertexCoordPointer(), _VBufferFinal.getNumVertices()*_VBufferFinal.getVertexSize() );
02831 
02832     // For All Lods
02833     for(uint lodId=0; lodId<_Lods.size();lodId++)
02834     {
02835         CLod    &lod= _Lods[lodId];
02836 
02837         // For all rdrPass.
02838         for(uint i=0;i<lod.RdrPass.size();i++)
02839         {
02840             // shift the PB
02841             CIndexBuffer    &srcPb= lod.RdrPass[i].PBlock;
02842             CIndexBuffer    &dstPb= lod.RdrPass[i].VBHeapPBlock;
02843             uint j;
02844 
02845             // Tris.
02846             CIndexBufferRead ibaRead;
02847             srcPb.lock (ibaRead);
02848             CIndexBufferReadWrite ibaWrite;
02849             srcPb.lock (ibaWrite);
02850             dstPb.setNumIndexes(srcPb.getNumIndexes());
02851             // nico : apparently not used, so don't manage 16 bit index here
02852             nlassert(ibaRead.getIndexNumBytes() == sizeof(uint32));
02853             nlassert(ibaWrite.getIndexNumBytes() == sizeof(uint32));
02854             nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32); // nico : apparently not called for now
02855             const uint32    *srcTriPtr= (const uint32 *) ibaRead.getPtr();
02856             uint32          *dstTriPtr= (uint32 *) ibaWrite.getPtr();
02857             for(j=0; j<dstPb.getNumIndexes();j++)
02858             {
02859                 dstTriPtr[j]= srcTriPtr[j]+indexStart;
02860             }
02861         }
02862     }
02863 }
02864 
02865 // ***************************************************************************
02866 bool    CMeshMRMGeom::isActiveInstanceNeedVBFill() const
02867 {
02868     // Yes, need it for geomorph
02869     return true;
02870 }
02871 
02872 
02873 // ***************************************************************************
02874 // ***************************************************************************
02875 // CMeshMRM.
02876 // ***************************************************************************
02877 // ***************************************************************************
02878 
02879 
02880 
02881 // ***************************************************************************
02882 CMeshMRM::CMeshMRM()
02883 {
02884 }
02885 // ***************************************************************************
02886 void            CMeshMRM::build (CMeshBase::CMeshBaseBuild &mBase, CMesh::CMeshBuild &m,
02887                                  std::vector<CMesh::CMeshBuild*> &listBS,
02888                                  const CMRMParameters &params)
02889 {
02891     CMeshBase::buildMeshBase (mBase);
02892 
02893     // Then build the geom.
02894     _MeshMRMGeom.build (m, listBS, mBase.Materials.size(), params);
02895 }
02896 // ***************************************************************************
02897 void            CMeshMRM::build (CMeshBase::CMeshBaseBuild &m, const CMeshMRMGeom &mgeom)
02898 {
02900     CMeshBase::buildMeshBase(m);
02901 
02902     // Then copy the geom.
02903     _MeshMRMGeom= mgeom;
02904 }
02905 
02906 
02907 // ***************************************************************************
02908 void            CMeshMRM::optimizeMaterialUsage(std::vector<sint> &remap)
02909 {
02910     // For each material, count usage.
02911     vector<bool>    materialUsed;
02912     materialUsed.resize(CMeshBase::_Materials.size(), false);
02913     for(uint lod=0;lod<getNbLod();lod++)
02914     {
02915         for(uint rp=0;rp<getNbRdrPass(lod);rp++)
02916         {
02917             uint    matId= getRdrPassMaterial(lod, rp);
02918             // flag as used.
02919             materialUsed[matId]= true;
02920         }
02921     }
02922 
02923     // Apply it to meshBase
02924     CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
02925 
02926     // Apply lut to meshGeom.
02927     _MeshMRMGeom.applyMaterialRemap(remap);
02928 }
02929 
02930 
02931 // ***************************************************************************
02932 CTransformShape     *CMeshMRM::createInstance(CScene &scene)
02933 {
02934     // Create a CMeshMRMInstance, an instance of a mesh.
02935     //===============================================
02936     CMeshMRMInstance        *mi= (CMeshMRMInstance*)scene.createModel(NL3D::MeshMRMInstanceId);
02937     mi->Shape= this;
02938 
02939     // instanciate the material part of the MeshMRM, ie the CMeshBase.
02940     CMeshBase::instanciateMeshBase(mi, &scene);
02941 
02942 
02943     // do some instance init for MeshGeom
02944     _MeshMRMGeom.initInstance(mi);
02945 
02946     // init the FilterType
02947     mi->initRenderFilterType();
02948 
02949     return mi;
02950 }
02951 
02952 
02953 // ***************************************************************************
02954 bool    CMeshMRM::clip(const std::vector<CPlane>    &pyramid, const CMatrix &worldMatrix)
02955 {
02956     return _MeshMRMGeom.clip(pyramid, worldMatrix);
02957 }
02958 
02959 
02960 // ***************************************************************************
02961 void    CMeshMRM::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
02962 {
02963     // 0 or 0xFFFFFFFF
02964     uint32  mask= (0-(uint32)passOpaque);
02965     uint32  rdrFlags;
02966     // select rdrFlags, without ifs.
02967     rdrFlags=   mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02968     rdrFlags|=  ~mask & (IMeshGeom::RenderTransparentMaterial);
02969     // render the mesh
02970     _MeshMRMGeom.render(drv, trans, trans->getNumTrianglesAfterLoadBalancing(), rdrFlags, 1);
02971 }
02972 
02973 
02974 // ***************************************************************************
02975 void    CMeshMRM::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02976 {
02977     /*
02978     Version 0:
02979         - base version.
02980     */
02981     (void)f.serialVersion(0);
02982 
02983     // serial Materials infos contained in CMeshBase.
02984     CMeshBase::serialMeshBase(f);
02985 
02986 
02987     // serial the geometry.
02988     _MeshMRMGeom.serial(f);
02989 }
02990 
02991 
02992 // ***************************************************************************
02993 float   CMeshMRM::getNumTriangles (float distance)
02994 {
02995     return _MeshMRMGeom.getNumTriangles (distance);
02996 }
02997 
02998 
02999 // ***************************************************************************
03000 const CMeshMRMGeom& CMeshMRM::getMeshGeom () const
03001 {
03002     return _MeshMRMGeom;
03003 }
03004 
03005 
03006 // ***************************************************************************
03007 void    CMeshMRM::computeBonesId (CSkeletonModel *skeleton)
03008 {
03009     _MeshMRMGeom.computeBonesId (skeleton);
03010 }
03011 
03012 // ***************************************************************************
03013 void    CMeshMRM::updateSkeletonUsage (CSkeletonModel *skeleton, bool increment)
03014 {
03015     _MeshMRMGeom.updateSkeletonUsage(skeleton, increment);
03016 }
03017 
03018 // ***************************************************************************
03019 void    CMeshMRM::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
03020 {
03021     _MeshMRMGeom.changeMRMDistanceSetup(distanceFinest, distanceMiddle, distanceCoarsest);
03022 }
03023 
03024 // ***************************************************************************
03025 IMeshGeom   *CMeshMRM::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
03026 {
03027     // Ok if meshGeom is ok.
03028     if(_MeshMRMGeom.supportMeshBlockRendering())
03029     {
03030         polygonCount= trans->getNumTrianglesAfterLoadBalancing();
03031         return (IMeshGeom*)&_MeshMRMGeom;
03032     }
03033     else
03034         return NULL;
03035 }
03036 
03037 // ***************************************************************************
03038 void    CMeshMRM::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
03039 {
03040     // 0 or 0xFFFFFFFF
03041     uint32  mask= (0-(uint32)passOpaque);
03042     uint32  rdrFlags;
03043     // select rdrFlags, without ifs.
03044     rdrFlags=   mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
03045     rdrFlags|=  ~mask & (IMeshGeom::RenderTransparentMaterial);
03046     // profile the mesh
03047     _MeshMRMGeom.profileSceneRender(rdrTrav, trans, trans->getNumTrianglesAfterLoadBalancing(), rdrFlags);
03048 }
03049 
03050 // ***************************************************************************
03051 void    CMeshMRM::buildSystemGeometry()
03052 {
03053     // clear any
03054     _SystemGeometry.clear();
03055 
03056     // don't build a system copy if skinned. In this case, ray intersection is done through CSkeletonModel
03057     // and intersectSkin() scheme
03058     if(_MeshMRMGeom.isSkinned())
03059         return;
03060 
03061     // Choose the best Lod available for system geometry
03062     if(_MeshMRMGeom.getNbLodLoaded()==0)
03063         return;
03064     uint    lodId= _MeshMRMGeom.getNbLodLoaded()-1;
03065 
03066     // retrieve geometry (if VB/IB not resident)
03067     if( !_MeshMRMGeom.buildGeometryForLod(lodId, _SystemGeometry.Vertices, _SystemGeometry.Triangles) )
03068     {
03069         _SystemGeometry.clear();
03070     }
03071 
03072     // TestYoyo
03073     /*static uint32 totalMem= 0;
03074     totalMem+= _SystemGeometry.Vertices.size()*sizeof(CVector);
03075     totalMem+= _SystemGeometry.Triangles.size()*sizeof(uint32);
03076     nlinfo("CMeshMRM: TotalMem: %d", totalMem);*/
03077 }
03078 
03079 
03080 // ***************************************************************************
03081 // ***************************************************************************
03082 // CMeshMRMGeom RawSkin optimisation
03083 // ***************************************************************************
03084 // ***************************************************************************
03085 
03086 
03087 // ***************************************************************************
03088 void        CMeshMRMGeom::dirtMeshDataId()
03089 {
03090     // see updateRawSkinNormal()
03091     _MeshDataId++;
03092 }
03093 
03094 
03095 // ***************************************************************************
03096 void        CMeshMRMGeom::updateRawSkinNormal(bool enabled, CMeshMRMInstance *mi, sint curLodId)
03097 {
03098     if(!enabled)
03099     {
03100         // if the instance cache is not cleared, must clear.
03101         if(mi->_RawSkinCache)
03102             mi->clearRawSkinCache();
03103     }
03104     else
03105     {
03106         // If the instance has no RawSkin, or has a too old RawSkin cache, must delete it, and recreate
03107         if( !mi->_RawSkinCache || mi->_RawSkinCache->MeshDataId!=_MeshDataId)
03108         {
03109             // first delete if too old.
03110             if(mi->_RawSkinCache)
03111                 mi->clearRawSkinCache();
03112             // Then recreate, and use _MeshDataId to verify that the instance works with same data.
03113             mi->_RawSkinCache= new CRawSkinNormalCache;
03114             mi->_RawSkinCache->MeshDataId= _MeshDataId;
03115             mi->_RawSkinCache->LodId= -1;
03116         }
03117 
03118 
03119         /* If the instance rawSkin has a different Lod (or if -1), then must recreate it.
03120             NB: The lod may change each frame per instance, but suppose not so many change, so we can cache those data.
03121         */
03122         if( mi->_RawSkinCache->LodId != curLodId )
03123         {
03124             H_AUTO( NL3D_CMeshMRMGeom_updateRawSkinNormal );
03125 
03126             CVertexBufferRead vba;
03127             _VBufferFinal.lock (vba);
03128 
03129             CRawSkinNormalCache &skinLod= *mi->_RawSkinCache;
03130             CLod                &lod= _Lods[curLodId];
03131             uint                i;
03132             sint                rawIdx;
03133 
03134             // Clear the raw skin mesh.
03135             skinLod.clearArrays();
03136 
03137             // Cache this lod
03138             mi->_RawSkinCache->LodId= curLodId;
03139 
03140             // For each matrix influence.
03141             nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
03142 
03143             // For each vertex, acknowledge if it is a src for geomorph.
03144             static  vector<uint8>   softVertices;
03145             softVertices.clear();
03146             softVertices.resize( _VBufferFinal.getNumVertices(), 0 );
03147             for(i=0;i<lod.Geomorphs.size();i++)
03148             {
03149                 softVertices[lod.Geomorphs[i].Start]= 1;
03150                 softVertices[lod.Geomorphs[i].End]= 1;
03151             }
03152 
03153             // The remap from old index in _VBufferFinal to RawSkin vertices (without Geomorphs).
03154             static  vector<TMeshMRMIndexType>   vertexRemap;
03155             vertexRemap.resize( _VBufferFinal.getNumVertices() );
03156             sint    softSize[4];
03157             sint    hardSize[4];
03158             sint    softStart[4];
03159             sint    hardStart[4];
03160             // count vertices
03161             skinLod.TotalSoftVertices= 0;
03162             skinLod.TotalHardVertices= 0;
03163             for(i=0;i<4;i++)
03164             {
03165                 softSize[i]= 0;
03166                 hardSize[i]= 0;
03167                 // Count.
03168                 for(uint j=0;j<lod.InfluencedVertices[i].size();j++)
03169                 {
03170                     uint    vid= lod.InfluencedVertices[i][j];
03171                     if(softVertices[vid])
03172                         softSize[i]++;
03173                     else
03174                         hardSize[i]++;
03175                 }
03176                 skinLod.TotalSoftVertices+= softSize[i];
03177                 skinLod.TotalHardVertices+= hardSize[i];
03178                 skinLod.SoftVertices[i]= softSize[i];
03179                 skinLod.HardVertices[i]= hardSize[i];
03180             }
03181             // compute offsets
03182             softStart[0]= 0;
03183             hardStart[0]= skinLod.TotalSoftVertices;
03184             for(i=1;i<4;i++)
03185             {
03186                 softStart[i]= softStart[i-1]+softSize[i-1];
03187                 hardStart[i]= hardStart[i-1]+hardSize[i-1];
03188             }
03189             // compute remap
03190             for(i=0;i<4;i++)
03191             {
03192                 uint    softIdx= softStart[i];
03193                 uint    hardIdx= hardStart[i];
03194                 for(uint j=0;j<lod.InfluencedVertices[i].size();j++)
03195                 {
03196                     uint    vid= lod.InfluencedVertices[i][j];
03197                     if(softVertices[vid])
03198                         vertexRemap[vid]= softIdx++;
03199                     else
03200                         vertexRemap[vid]= hardIdx++;
03201                 }
03202             }
03203 
03204 
03205             // Resize the dest array.
03206             skinLod.Vertices1.resize(lod.InfluencedVertices[0].size());
03207             skinLod.Vertices2.resize(lod.InfluencedVertices[1].size());
03208             skinLod.Vertices3.resize(lod.InfluencedVertices[2].size());
03209             skinLod.Vertices4.resize(lod.InfluencedVertices[3].size());
03210 
03211             // Remap for BlendShape. Lasts 2 bits tells what RawSkin Array to seek (1 to 4),
03212             // low Bits indicate the number in them. 0xFFFFFFFF is a special value indicating "NotUsed in this lod"
03213             static  vector<uint32>  vertexFinalRemap;
03214             vertexFinalRemap.clear();
03215             vertexFinalRemap.resize(vertexRemap.size(), 0xFFFFFFFF);
03216 
03217             // 1 Matrix skinning.
03218             //========
03219             for(i=0;i<skinLod.Vertices1.size();i++)
03220             {
03221                 // get the dest vertex.
03222                 uint    vid= lod.InfluencedVertices[0][i];
03223                 // where to store?
03224                 rawIdx= vertexRemap[vid];
03225                 if(softVertices[vid])
03226                     rawIdx-= softStart[0];
03227                 else
03228                     rawIdx+= softSize[0]-hardStart[0];
03229                 // for BlendShapes remapping
03230                 vertexFinalRemap[vid]= (0<<30) + rawIdx;
03231                 // fill raw struct
03232                 skinLod.Vertices1[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
03233                 skinLod.Vertices1[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
03234                 skinLod.Vertices1[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
03235                 skinLod.Vertices1[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
03236             }
03237 
03238             // 2 Matrix skinning.
03239             //========
03240             for(i=0;i<skinLod.Vertices2.size();i++)
03241             {
03242                 // get the dest vertex.
03243                 uint    vid= lod.InfluencedVertices[1][i];
03244                 // where to store?
03245                 rawIdx= vertexRemap[vid];
03246                 if(softVertices[vid])
03247                     rawIdx-= softStart[1];
03248                 else
03249                     rawIdx+= softSize[1]-hardStart[1];
03250                 // for BlendShapes remapping
03251                 vertexFinalRemap[vid]= (1<<30) + rawIdx;
03252                 // fill raw struct
03253                 skinLod.Vertices2[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
03254                 skinLod.Vertices2[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
03255                 skinLod.Vertices2[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
03256                 skinLod.Vertices2[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
03257                 skinLod.Vertices2[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
03258                 skinLod.Vertices2[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
03259                 skinLod.Vertices2[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
03260             }
03261 
03262             // 3 Matrix skinning.
03263             //========
03264             for(i=0;i<skinLod.Vertices3.size();i++)
03265             {
03266                 // get the dest vertex.
03267                 uint    vid= lod.InfluencedVertices[2][i];
03268                 // where to store?
03269                 rawIdx= vertexRemap[vid];
03270                 if(softVertices[vid])
03271                     rawIdx-= softStart[2];
03272                 else
03273                     rawIdx+= softSize[2]-hardStart[2];
03274                 // for BlendShapes remapping
03275                 vertexFinalRemap[vid]= (2<<30) + rawIdx;
03276                 // fill raw struct
03277                 skinLod.Vertices3[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
03278                 skinLod.Vertices3[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
03279                 skinLod.Vertices3[rawIdx].MatrixId[2]= _SkinWeights[vid].MatrixId[2];
03280                 skinLod.Vertices3[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
03281                 skinLod.Vertices3[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
03282                 skinLod.Vertices3[rawIdx].Weights[2]= _SkinWeights[vid].Weights[2];
03283                 skinLod.Vertices3[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
03284                 skinLod.Vertices3[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
03285                 skinLod.Vertices3[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
03286             }
03287 
03288             // 4 Matrix skinning.
03289             //========
03290             for(i=0;i<skinLod.Vertices4.size();i++)
03291             {
03292                 // get the dest vertex.
03293                 uint    vid= lod.InfluencedVertices[3][i];
03294                 // where to store?
03295                 rawIdx= vertexRemap[vid];
03296                 if(softVertices[vid])
03297                     rawIdx-= softStart[3];
03298                 else
03299                     rawIdx+= softSize[3]-hardStart[3];
03300                 // for BlendShapes remapping
03301                 vertexFinalRemap[vid]= (3<<30) + rawIdx;
03302                 // fill raw struct
03303                 skinLod.Vertices4[rawIdx].MatrixId[0]= _SkinWeights[vid].MatrixId[0];
03304                 skinLod.Vertices4[rawIdx].MatrixId[1]= _SkinWeights[vid].MatrixId[1];
03305                 skinLod.Vertices4[rawIdx].MatrixId[2]= _SkinWeights[vid].MatrixId[2];
03306                 skinLod.Vertices4[rawIdx].MatrixId[3]= _SkinWeights[vid].MatrixId[3];
03307                 skinLod.Vertices4[rawIdx].Weights[0]= _SkinWeights[vid].Weights[0];
03308                 skinLod.Vertices4[rawIdx].Weights[1]= _SkinWeights[vid].Weights[1];
03309                 skinLod.Vertices4[rawIdx].Weights[2]= _SkinWeights[vid].Weights[2];
03310                 skinLod.Vertices4[rawIdx].Weights[3]= _SkinWeights[vid].Weights[3];
03311                 skinLod.Vertices4[rawIdx].Vertex.Pos= _OriginalSkinVertices[vid];
03312                 skinLod.Vertices4[rawIdx].Vertex.Normal= _OriginalSkinNormals[vid];
03313                 skinLod.Vertices4[rawIdx].Vertex.UV= *vba.getTexCoordPointer(vid);
03314             }
03315 
03316             // Remap Geomorphs.
03317             //========
03318             uint    numGeoms= lod.Geomorphs.size();
03319             skinLod.Geomorphs.resize( numGeoms );
03320             for(i=0;i<numGeoms;i++)
03321             {
03322                 // NB: don't add "numGeoms" to the index because RawSkin look in a TempArray in RAM, wich start at 0...
03323                 skinLod.Geomorphs[i].Start= vertexRemap[lod.Geomorphs[i].Start];
03324                 skinLod.Geomorphs[i].End= vertexRemap[lod.Geomorphs[i].End];
03325             }
03326 
03327             // Remap RdrPass.
03328             //========
03329             skinLod.RdrPass.resize(lod.RdrPass.size());
03330             for(i=0;i<skinLod.RdrPass.size();i++)
03331             {
03332                 // NB: since RawSkin is possible only with SkinGrouping, and since SkniGrouping is
03333                 // possible only with no Quads/Lines, we should have only Tris here.
03334                 // remap tris.
03335                 skinLod.RdrPass[i].setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
03336                 skinLod.RdrPass[i].setNumIndexes(lod.RdrPass[i].PBlock.getNumIndexes());
03337                 CIndexBufferRead ibaRead;
03338                 lod.RdrPass[i].PBlock.lock (ibaRead);
03339                 CIndexBufferReadWrite ibaWrite;
03340                 skinLod.RdrPass[i].lock (ibaWrite);
03341                 if (skinLod.RdrPass[i].getFormat() == CIndexBuffer::Indices32)
03342                 {
03343                     nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
03344                     const uint32    *srcTriPtr= (const uint32 *) ibaRead.getPtr();
03345                     uint32  *dstTriPtr= (uint32 *) ibaWrite.getPtr();
03346                     uint32  numIndices= lod.RdrPass[i].PBlock.getNumIndexes();
03347                     for(uint j=0;j<numIndices;j++, srcTriPtr++, dstTriPtr++)
03348                     {
03349                         uint    vid= *srcTriPtr;
03350                         // If this index refers to a Geomorphed vertex, don't modify!
03351                         if(vid<numGeoms)
03352                             *dstTriPtr= vid;
03353                         else
03354                             *dstTriPtr= vertexRemap[vid] + numGeoms;
03355                     }
03356                 }
03357                 else
03358                 {
03359                     nlassert(ibaRead.getFormat() == CIndexBuffer::Indices16);
03360                     const uint16    *srcTriPtr= (const uint16 *) ibaRead.getPtr();
03361                     uint16  *dstTriPtr= (uint16 *) ibaWrite.getPtr();
03362                     uint32  numIndices= lod.RdrPass[i].PBlock.getNumIndexes();
03363                     for(uint j=0;j<numIndices;j++, srcTriPtr++, dstTriPtr++)
03364                     {
03365                         uint    vid= *srcTriPtr;
03366                         // If this index refers to a Geomorphed vertex, don't modify!
03367                         if(vid<numGeoms)
03368                             *dstTriPtr= vid;
03369                         else
03370                             *dstTriPtr= vertexRemap[vid] + numGeoms;
03371                     }
03372                 }
03373             }
03374 
03375             // Case of MeshMorpher
03376             //========
03377             if(_MeshMorpher.BlendShapes.size()>0)
03378             {
03379                 skinLod.VertexRemap.resize(vertexFinalRemap.size());
03380 
03381                 for(i=0;i<vertexFinalRemap.size();i++)
03382                 {
03383                     uint    vfr= vertexFinalRemap[i];
03384                     if(vfr!=0xFFFFFFFF)
03385                     {
03386                         uint    rsArrayId= vfr >> 30;
03387                         uint    rsIndex= vfr & ((1<<30)-1);
03388                         switch(rsArrayId)
03389                         {
03390                         case 0:
03391                             skinLod.VertexRemap[i]= &skinLod.Vertices1[rsIndex].Vertex;
03392                             break;
03393                         case 1:
03394                             skinLod.VertexRemap[i]= &skinLod.Vertices2[rsIndex].Vertex;
03395                             break;
03396                         case 2:
03397                             skinLod.VertexRemap[i]= &skinLod.Vertices3[rsIndex].Vertex;
03398                             break;
03399                         case 3:
03400                             skinLod.VertexRemap[i]= &skinLod.Vertices4[rsIndex].Vertex;
03401                             break;
03402                         };
03403                     }
03404                     else
03405                         skinLod.VertexRemap[i]= NULL;
03406                 }
03407             }
03408         }
03409     }
03410 }
03411 
03412 
03413 // ***************************************************************************
03414 // ***************************************************************************
03415 // CMeshMRMGeom Shadow Skin Rendering
03416 // ***************************************************************************
03417 // ***************************************************************************
03418 
03419 
03420 // ***************************************************************************
03421 void            CMeshMRMGeom::setShadowMesh(const std::vector<CShadowVertex> &shadowVertices, const std::vector<uint32> &triangles)
03422 {
03423     _ShadowSkin.Vertices= shadowVertices;
03424     _ShadowSkin.Triangles= triangles;
03425     // update flag. Support Shadow SkinGrouping if Shadow setuped, and if not too many vertices.
03426     _SupportShadowSkinGrouping= !_ShadowSkin.Vertices.empty() &&
03427         NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT==CVertexBuffer::PositionFlag &&
03428         _ShadowSkin.Vertices.size() <= NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES;
03429 }
03430 
03431 // ***************************************************************************
03432 uint            CMeshMRMGeom::getNumShadowSkinVertices() const
03433 {
03434     return _ShadowSkin.Vertices.size();
03435 }
03436 
03437 // ***************************************************************************
03438 sint            CMeshMRMGeom::renderShadowSkinGeom(CMeshMRMInstance *mi, uint remainingVertices, uint8 *vbDest)
03439 {
03440     uint    numVerts= _ShadowSkin.Vertices.size();
03441 
03442     // if no verts, no draw
03443     if(numVerts==0)
03444         return 0;
03445 
03446     // if no lods, there should be no verts, but still ensure no bug in skinning
03447     if(_Lods.empty())
03448         return 0;
03449 
03450     // If the Lod is too big to render in the VBufferHard
03451     if(numVerts>remainingVertices)
03452         // return Failure
03453         return -1;
03454 
03455     // get the skeleton model to which I am skinned
03456     CSkeletonModel *skeleton;
03457     skeleton = mi->getSkeletonModel();
03458     // must be skinned for renderSkin()
03459     nlassert(skeleton);
03460 
03461 
03462     // Profiling
03463     //===========
03464     H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow );
03465 
03466 
03467     // Skinning.
03468     //===========
03469 
03470     // skinning with normal, but no tangent space
03471     // For all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
03472     // NB: take the best lod since the lower lods cannot use other Matrix than the higher one.
03473     static  vector<CMatrix3x4>      boneMat3x4;
03474     CLod    &lod= _Lods[_Lods.size()-1];
03475     computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton);
03476 
03477     _ShadowSkin.applySkin((CVector*)vbDest, boneMat3x4);
03478 
03479 
03480     // How many vertices are added to the VBuffer ???
03481     return numVerts;
03482 }
03483 
03484 
03485 // ***************************************************************************
03486 void            CMeshMRMGeom::renderShadowSkinPrimitives(CMeshMRMInstance   *mi, CMaterial &castMat, IDriver *drv, uint baseVertex)
03487 {
03488     nlassert(drv);
03489 
03490     if(_ShadowSkin.Triangles.empty())
03491         return;
03492 
03493     // Profiling
03494     //===========
03495     H_AUTO_USE( NL3D_MeshMRMGeom_RenderShadow );
03496 
03497     // NB: the skeleton matrix has already been setuped by CSkeletonModel
03498     // NB: the normalize flag has already been setuped by CSkeletonModel
03499 
03500     // TODO_SHADOW: optim: Special triangle cache for shadow!
03501     static  CIndexBuffer shiftedTris;
03502     NL_SET_IB_NAME(shiftedTris, "CMeshMRMGeom::renderShadowSkinPrimitives::shiftedTris");
03503     if(shiftedTris.getNumIndexes()<_ShadowSkin.Triangles.size())
03504     {
03505         shiftedTris.setFormat(NL_MESH_MRM_INDEX_FORMAT);
03506         shiftedTris.setNumIndexes(_ShadowSkin.Triangles.size());
03507     }
03508     shiftedTris.setPreferredMemory(CIndexBuffer::RAMVolatile, false);
03509     {
03510         CIndexBufferReadWrite iba;
03511         shiftedTris.lock(iba);
03512         const uint32    *src= &_ShadowSkin.Triangles[0];
03513         TMeshMRMIndexType *dst= (TMeshMRMIndexType *) iba.getPtr();
03514         for(uint n= _ShadowSkin.Triangles.size();n>0;n--, src++, dst++)
03515         {
03516             *dst= (TMeshMRMIndexType)(*src + baseVertex);
03517         }
03518     }
03519 
03520     // Render Triangles with cache
03521     //===========
03522 
03523     uint    numTris= _ShadowSkin.Triangles.size()/3;
03524 
03525     // Render with the Materials of the MeshInstance.
03526     drv->activeIndexBuffer(shiftedTris);
03527     drv->renderTriangles(castMat, 0, numTris);
03528 }
03529 
03530 
03531 // ***************************************************************************
03532 bool        CMeshMRMGeom::getSkinBoneBBox(CSkeletonModel *skeleton, NLMISC::CAABBox &bbox, uint boneId) const
03533 {
03534     bbox.setCenter(CVector::Null);
03535     bbox.setHalfSize(CVector::Null);
03536 
03537     if(!skeleton)
03538         return false;
03539 
03540     // get the bindpos of the wanted bone
03541     nlassert(boneId<skeleton->Bones.size());
03542     const CMatrix       &invBindPos= skeleton->Bones[boneId].getBoneBase().InvBindPos;
03543 
03544 
03545     // Find the Geomorph space: to process only real vertices, not geomorphed ones.
03546     uint    nGeomSpace= 0;
03547     uint    lod;
03548     for (lod=0; lod<_Lods.size(); lod++)
03549     {
03550         nGeomSpace= max(nGeomSpace, (uint)_Lods[lod].Geomorphs.size());
03551     }
03552 
03553     // Prepare Sphere compute
03554     nlassert(_OriginalSkinVertices.size() == _SkinWeights.size());
03555     bool    bbEmpty= true;
03556 
03557     // Remap the vertex, and compute the wanted bone bbox
03558     // for true vertices
03559     for (uint vert=nGeomSpace; vert<_SkinWeights.size(); vert++)
03560     {
03561         // get the vertex position.
03562         CVector     vertex= _OriginalSkinVertices[vert];
03563 
03564         // For each weight
03565         uint weight;
03566         for (weight=0; weight<NL3D_MESH_SKINNING_MAX_MATRIX; weight++)
03567         {
03568             // Active ?
03569             if ((_SkinWeights[vert].Weights[weight]>0)||(weight==0))
03570             {
03571                 // Check id is the wanted one
03572                 if(_SkinWeights[vert].MatrixId[weight]==boneId)
03573                 {
03574                     // transform the vertex pos in BoneSpace
03575                     CVector     p= invBindPos * vertex;
03576                     // extend the bone bbox.
03577                     if(bbEmpty)
03578                     {
03579                         bbox.setCenter(p);
03580                         bbEmpty= false;
03581                     }
03582                     else
03583                     {
03584                         bbox.extend(p);
03585                     }
03586                 }
03587             }
03588             else
03589                 break;
03590         }
03591     }
03592 
03593     // return true if some influence found
03594     return !bbEmpty;
03595 }
03596 
03597 
03598 // ***************************************************************************
03599 bool        CMeshMRMGeom::intersectSkin(CMeshMRMInstance    *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
03600 {
03601     // for MeshMRM, Use the Shadow Skinning (simple and light version).
03602 
03603     // no inst/verts/lod => no intersection
03604     if(!mi || _ShadowSkin.Vertices.empty() || _Lods.empty())
03605         return false;
03606     CSkeletonModel  *skeleton= mi->getSkeletonModel();
03607     if(!skeleton)
03608         return false;
03609 
03610     // Compute skinning with all matrix this Mesh use. (the shadow geometry cannot use other Matrix than the mesh use).
03611     // NB: take the best lod (_Lods.back()) since the lower lods cannot use other Matrix than the higher one.
03612     return _ShadowSkin.getRayIntersection(toRaySpace, *skeleton, _Lods.back().MatrixInfluences, dist2D, distZ, computeDist2D);
03613 }
03614 
03615 
03616 } // NL3D
03617 

Generated on Thu Jan 7 08:26:27 2010 for NeL by  doxygen 1.6.1