# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

mesh_mrm.cpp

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