00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026 #include "nel/3d/mesh.h"
00027 #include "nel/3d/mesh_instance.h"
00028 #include "nel/3d/scene.h"
00029 #include "nel/3d/skeleton_model.h"
00030 #include "nel/3d/mesh_morpher.h"
00031 #include "nel/misc/bsphere.h"
00032 #include "nel/3d/stripifier.h"
00033 #include "nel/misc/fast_floor.h"
00034 #include "nel/misc/hierarchical_timer.h"
00035 #include "nel/3d/mesh_blender.h"
00036 #include "nel/3d/matrix_3x4.h"
00037 #include "nel/3d/render_trav.h"
00038 #include "nel/3d/visual_collision_mesh.h"
00039 #include "nel/3d/meshvp_wind_tree.h"
00040
00041 using namespace std;
00042 using namespace NLMISC;
00043
00044
00045
00046
00047 namespace NL3D
00048 {
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 static NLMISC::CAABBoxExt makeBBox(const std::vector<CVector> &Vertices)
00060 {
00061 NLMISC::CAABBox ret;
00062 nlassert(Vertices.size());
00063 ret.setCenter(Vertices[0]);
00064 for(sint i=0;i<(sint)Vertices.size();i++)
00065 {
00066 ret.extend(Vertices[i]);
00067 }
00068
00069 return ret;
00070 }
00071
00072
00073
00074 sint CMeshGeom::CCornerTmp::Flags=0;
00075
00076
00077
00078 bool CMeshGeom::CCornerTmp::operator<(const CCornerTmp &c) const
00079 {
00080 sint i;
00081
00082
00083 if(Vertex!=c.Vertex)
00084 return Vertex<c.Vertex;
00085
00086
00087 if((CCornerTmp::Flags & CVertexBuffer::NormalFlag) && Normal!=c.Normal)
00088 return Normal<c.Normal;
00089 for(i=0; i<CVertexBuffer::MaxStage; i++)
00090 {
00091 if((CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i)) && Uvws[i]!=c.Uvws[i])
00092 return Uvws[i]<c.Uvws[i];
00093 }
00094 if((CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag) && Color!=c.Color)
00095 return Color<c.Color;
00096 if((CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag) && Specular!=c.Specular)
00097 return Specular<c.Specular;
00098
00099 if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
00100 {
00101 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00102 {
00103 if(Palette.MatrixId[i] != c.Palette.MatrixId[i])
00104 return Palette.MatrixId[i] < c.Palette.MatrixId[i];
00105 if(Weights[i] != c.Weights[i])
00106 return Weights[i] < c.Weights[i];
00107 }
00108 }
00109
00110
00111
00112 return false;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 CMeshGeom::CMeshGeom()
00125 {
00126
00127
00128
00129
00130
00131 _Skinned= false;
00132 _OriginalSkinRestored= true;
00133 _MeshMorpher = new CMeshMorpher;
00134 _BoneIdComputed = false;
00135 _BoneIdExtended= false;
00136 _PreciseClipping= false;
00137 }
00138
00139
00140
00141 CMeshGeom::~CMeshGeom()
00142 {
00143
00144
00145
00146
00147
00148 delete _MeshMorpher;
00149 }
00150
00151
00152
00153 void CMeshGeom::optimizeTriangleOrder()
00154 {
00155 CStripifier stripifier;
00156
00157
00158 for(uint mb= 0;mb<_MatrixBlocks.size();mb++)
00159 {
00160 for(uint rp=0; rp<_MatrixBlocks[mb].RdrPass.size(); rp++ )
00161 {
00162
00163 CRdrPass &pass= _MatrixBlocks[mb].RdrPass[rp];
00164 stripifier.optimizeTriangles(pass.PBlock, pass.PBlock);
00165 }
00166 }
00167
00168 }
00169
00170
00171
00172 void CMeshGeom::build (CMesh::CMeshBuild &m, uint numMaxMaterial)
00173 {
00174 sint i;
00175
00176
00177 if(m.Vertices.size()==0 || m.Faces.size()==0)
00178 {
00179 _VBuffer.setNumVertices(0);
00180 _VBuffer.setName("CMeshGeom");
00181 _VBuffer.reserve(0);
00182 _MatrixBlocks.clear();
00183 _BBox.setCenter(CVector::Null);
00184 _BBox.setSize(CVector::Null);
00185 return;
00186 }
00187 nlassert(numMaxMaterial>0);
00188
00189
00190 for (i=0; i<CVertexBuffer::MaxStage; i++)
00191 _VBuffer.setUVRouting (i, m.UVRouting[i]);
00192
00194
00195 _BBox= makeBBox(m.Vertices);
00196
00197
00199
00200
00201
00202 vector<CFaceTmp> tmpFaces;
00203 tmpFaces.resize(m.Faces.size());
00204 for(i=0;i<(sint)tmpFaces.size();i++)
00205 tmpFaces[i]= m.Faces[i];
00206
00207 _Skinned= ((m.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
00208
00209 _Skinned= _Skinned && (m.Vertices.size()==m.SkinWeights.size());
00210
00211
00212 uint vbFlags= m.VertexFlags;
00213 if(!_Skinned)
00214 vbFlags&= ~CVertexBuffer::PaletteSkinFlag;
00215
00216 vbFlags|= CVertexBuffer::PositionFlag;
00217
00218
00219
00220 if(!_Skinned)
00221 {
00222 _MatrixBlocks.resize(1);
00223
00224 for(i=0;i<(sint)tmpFaces.size();i++)
00225 tmpFaces[i].MatrixBlockId= 0;
00226 }
00227
00228 else
00229 {
00230
00231 _MatrixBlocks.clear();
00232
00233 buildSkin(m, tmpFaces);
00234 }
00235
00237
00238
00239 _VBuffer.setNumVertices(0);
00240 _VBuffer.reserve(0);
00241
00242 bool useFormatExt = false;
00246 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
00247 {
00248 if (
00249 (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
00250 && m.NumCoords[k] != 2)
00251 {
00252 useFormatExt = true;
00253 break;
00254 }
00255 }
00256
00257 if (!useFormatExt)
00258 {
00259
00260 _VBuffer.setVertexFormat(vbFlags);
00261 }
00262 else
00263 {
00264 _VBuffer.clearValueEx();
00265 if (vbFlags & CVertexBuffer::PositionFlag) _VBuffer.addValueEx(CVertexBuffer::Position, CVertexBuffer::Float3);
00266 if (vbFlags & CVertexBuffer::NormalFlag) _VBuffer.addValueEx(CVertexBuffer::Normal, CVertexBuffer::Float3);
00267 if (vbFlags & CVertexBuffer::PrimaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::PrimaryColor, CVertexBuffer::UChar4);
00268 if (vbFlags & CVertexBuffer::SecondaryColorFlag) _VBuffer.addValueEx(CVertexBuffer::SecondaryColor, CVertexBuffer::UChar4);
00269 if (vbFlags & CVertexBuffer::WeightFlag) _VBuffer.addValueEx(CVertexBuffer::Weight, CVertexBuffer::Float4);
00270 if (vbFlags & CVertexBuffer::PaletteSkinFlag) _VBuffer.addValueEx(CVertexBuffer::PaletteSkin, CVertexBuffer::UChar4);
00271 if (vbFlags & CVertexBuffer::FogFlag) _VBuffer.addValueEx(CVertexBuffer::Fog, CVertexBuffer::Float1);
00272
00273 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
00274 {
00275 if (vbFlags & (CVertexBuffer::TexCoord0Flag << k))
00276 {
00277 switch(m.NumCoords[k])
00278 {
00279 case 2:
00280 _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float2);
00281 break;
00282 case 3:
00283 _VBuffer.addValueEx((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + k), CVertexBuffer::Float3);
00284 break;
00285 default:
00286 nlassert(0);
00287 break;
00288 }
00289 }
00290 }
00291 _VBuffer.initEx();
00292 }
00293
00294
00295 CCornerTmp::Flags= vbFlags;
00296
00297 TCornerSet corners;
00298 const CFaceTmp *pFace= &(*tmpFaces.begin());
00299 uint32 nFaceMB = 0;
00300 sint N= tmpFaces.size();
00301 sint currentVBIndex=0;
00302
00303 m.VertLink.clear ();
00304
00305
00306 for(;N>0;N--, pFace++)
00307 {
00308 sint v0= pFace->Corner[0].Vertex;
00309 sint v1= pFace->Corner[1].Vertex;
00310 sint v2= pFace->Corner[2].Vertex;
00311 findVBId(corners, &pFace->Corner[0], currentVBIndex, m.Vertices[v0], m);
00312 findVBId(corners, &pFace->Corner[1], currentVBIndex, m.Vertices[v1], m);
00313 findVBId(corners, &pFace->Corner[2], currentVBIndex, m.Vertices[v2], m);
00314 CMesh::CVertLink vl1(nFaceMB, 0, pFace->Corner[0].VBId);
00315 CMesh::CVertLink vl2(nFaceMB, 1, pFace->Corner[1].VBId);
00316 CMesh::CVertLink vl3(nFaceMB, 2, pFace->Corner[2].VBId);
00317 m.VertLink.push_back(vl1);
00318 m.VertLink.push_back(vl2);
00319 m.VertLink.push_back(vl3);
00320 ++nFaceMB;
00321 }
00322
00323
00325
00326 uint mb;
00327
00328
00329 for(mb= 0;mb<_MatrixBlocks.size();mb++)
00330 {
00331
00332 _MatrixBlocks[mb].RdrPass.resize (numMaxMaterial);
00333
00334 for(i=0;i<(sint)_MatrixBlocks[mb].RdrPass.size(); i++)
00335 {
00336 _MatrixBlocks[mb].RdrPass[i].MaterialId= i;
00337
00338 _MatrixBlocks[mb].RdrPass[i].PBlock.setFormat(CIndexBuffer::Indices32);
00339 }
00340 }
00341
00342
00344
00345 pFace= &(*tmpFaces.begin());
00346 N= tmpFaces.size();
00347 for(;N>0;N--, pFace++)
00348 {
00349 sint mbId= pFace->MatrixBlockId;
00350 nlassert(mbId>=0 && mbId<(sint)_MatrixBlocks.size());
00351
00352 CIndexBuffer &ib = _MatrixBlocks[mbId].RdrPass[pFace->MaterialId].PBlock;
00353 uint index = ib.getNumIndexes();
00354 ib.setNumIndexes (index+3);
00355 CIndexBufferReadWrite iba;
00356 ib.lock (iba);
00357 iba.setTri(index, pFace->Corner[0].VBId, pFace->Corner[1].VBId, pFace->Corner[2].VBId);
00358 }
00359
00360
00362
00363 for(mb= 0;mb<_MatrixBlocks.size();mb++)
00364 {
00365
00366 vector<CRdrPass>::iterator itPass;
00367 for( itPass=_MatrixBlocks[mb].RdrPass.begin(); itPass!=_MatrixBlocks[mb].RdrPass.end(); )
00368 {
00369
00370 if( itPass->PBlock.getNumIndexes()==0 )
00371 itPass= _MatrixBlocks[mb].RdrPass.erase(itPass);
00372 else
00373 itPass++;
00374 }
00375 }
00376
00378
00379
00380 this->_MeshMorpher->BlendShapes = m.BlendShapes;
00381
00382
00383 optimizeTriangleOrder();
00384
00385
00386 this->_MeshVertexProgram= m.MeshVertexProgram;
00387
00389
00390
00391
00392 if(_Skinned)
00393 {
00394
00395 _BonesName.reserve (m.BonesNames.size ());
00396
00397
00398 uint currentBone = 0;
00399
00400
00401 uint matrixBlock;
00402 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
00403 {
00404
00405 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
00406
00407
00408 std::map<uint, uint> remap;
00409
00410
00411 uint matrix;
00412 for (matrix=0; matrix<mb.NumMatrix; matrix++)
00413 {
00414
00415 std::map<uint, uint>::iterator ite = remap.find (mb.MatrixId[matrix]);
00416
00417
00418 if (ite == remap.end())
00419 {
00420
00421 remap.insert (std::map<uint, uint>::value_type (mb.MatrixId[matrix], currentBone));
00422
00423
00424 nlassert (mb.MatrixId[matrix] < m.BonesNames.size());
00425
00426
00427 _BonesName.push_back (m.BonesNames[mb.MatrixId[matrix]]);
00428
00429
00430 mb.MatrixId[matrix] = currentBone++;
00431 }
00432 else
00433 {
00434
00435 mb.MatrixId[matrix] = ite->second;
00436 }
00437 }
00438 }
00439
00440
00441 _BoneIdComputed = false;
00442 _BoneIdExtended = false;
00443 }
00444
00445
00446 bool avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 );
00447 _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
00448
00449
00450
00451 compileRunTime();
00452 }
00453
00454
00455 void CMeshGeom::setBlendShapes(std::vector<CBlendShape>&bs)
00456 {
00457 _MeshMorpher->BlendShapes = bs;
00458
00459 compileRunTime();
00460 }
00461
00462
00463
00464 void CMeshGeom::applyMaterialRemap(const std::vector<sint> &remap)
00465 {
00466 for(uint mb=0;mb<getNbMatrixBlock();mb++)
00467 {
00468 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
00469 {
00470
00471 uint32 &matId= _MatrixBlocks[mb].RdrPass[rp].MaterialId;
00472 nlassert(remap[matId]>=0);
00473 matId= remap[matId];
00474 }
00475 }
00476 }
00477
00478
00479
00480 void CMeshGeom::initInstance(CMeshBaseInstance *mbi)
00481 {
00482
00483 if(_MeshVertexProgram)
00484 _MeshVertexProgram->initInstance(mbi);
00485 }
00486
00487
00488 bool CMeshGeom::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
00489 {
00490
00491 CBSphere localSphere(_BBox.getCenter(), _BBox.getRadius());
00492 CBSphere worldSphere;
00493
00494
00495 localSphere.applyTransform(worldMatrix, worldSphere);
00496
00497
00498 for(sint i=0;i<(sint)pyramid.size();i++)
00499 {
00500
00501
00502 float d= pyramid[i]*worldSphere.Center;
00503 if(d>worldSphere.Radius)
00504 return false;
00505 }
00506
00507
00508 if( _PreciseClipping )
00509 {
00510 CPlane localPlane;
00511
00512
00513 for(sint i=0;i<(sint)pyramid.size();i++)
00514 {
00515
00516 localPlane= pyramid[i]*worldMatrix;
00517
00518 localPlane.normalize();
00519
00520 if( !_BBox.clipBack(localPlane) )
00521 return false;
00522 }
00523 }
00524
00525 return true;
00526 }
00527
00528
00529 void CMeshGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
00530 {
00531 nlassert(drv);
00532
00533 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
00534
00535 CScene *ownerScene= mi->getOwnerScene();
00536
00537 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
00538
00539
00540 if (drv->slowUnlockVertexBufferHard())
00541 _VBuffer.setPreferredMemory (CVertexBuffer::RAMPreferred, false);
00542
00543
00544 CSkeletonModel *skeleton;
00545 skeleton= mi->getSkeletonModel();
00546
00547 nlassert(!(_Skinned && mi->isSkinned() && skeleton));
00548 bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00549 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00550
00551
00552
00553
00554 H_AUTO( NL3D_MeshGeom_RenderNormal );
00555
00556
00557
00558
00559 if (bMorphApplied)
00560 {
00561
00562
00563
00564 if (_Skinned)
00565 {
00566 _MeshMorpher->initSkinned(&_VBufferOri,
00567 &_VBuffer,
00568 useTangentSpace,
00569 &_OriginalSkinVertices,
00570 &_OriginalSkinNormals,
00571 useTangentSpace ? &_OriginalTGSpace : NULL,
00572 false );
00573 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00574 }
00575 else
00576 {
00577 _MeshMorpher->init(&_VBufferOri,
00578 &_VBuffer,
00579 useTangentSpace);
00580 _MeshMorpher->update (mi->getBlendShapeFactors());
00581 }
00582 }
00583
00584
00585
00586
00587
00588
00589 drv->setupModelMatrix(trans->getWorldMatrix());
00590
00591
00592
00593 if (_Skinned)
00594 {
00595
00596 if (!_OriginalSkinRestored)
00597 restoreOriginalSkinVertices();
00598 }
00599
00600
00601
00602
00603
00604
00605 bool useMeshVP= _MeshVertexProgram != NULL;
00606 if( useMeshVP )
00607 {
00608 CMatrix invertedObjectMatrix;
00609 invertedObjectMatrix = trans->getWorldMatrix().inverted();
00610
00611 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00612 if (!useMeshVP && !mi->_VPWindTreeFixed)
00613 {
00614 if (dynamic_cast<CMeshVPWindTree *>(&(*_MeshVertexProgram)))
00615 {
00616
00617 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00618 {
00619 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00620 for(uint i=0;i<mBlock.RdrPass.size();i++)
00621 {
00622 CMaterial &mat=mi->Materials[mBlock.RdrPass[i].MaterialId];
00623 mat.setLighting(true, mat.getEmissive(), mat.getAmbient(), mat.getDiffuse(), mat.getSpecular());
00624 }
00625 }
00626 }
00627 mi->_VPWindTreeFixed = true;
00628 }
00629 }
00630
00631
00632
00633
00634
00635
00636 drv->activeVertexBuffer(_VBuffer);
00637
00638
00639
00640 uint32 globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
00641 uint8 globalAlphaInt=(uint8)NLMISC::OptFastFloor(globalAlpha*255);
00642
00643
00644
00645 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00646 {
00647 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00648 if(mBlock.RdrPass.size()==0)
00649 continue;
00650
00651
00652 if (globalAlphaUsed)
00653 {
00654 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
00655
00656
00657 for (uint i=0;i<mBlock.RdrPass.size();i++)
00658 {
00659 CRdrPass &rdrPass= mBlock.RdrPass[i];
00660
00661 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00662 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
00663 {
00664
00665 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00666
00667
00668 CMeshBlender blender;
00669 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
00670
00671
00672 if (useMeshVP)
00673 {
00674 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00675 }
00676
00677
00678 drv->activeIndexBuffer(rdrPass.PBlock);
00679 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00680
00681
00682 blender.restoreRender(material, drv, gaDisableZWrite);
00683 }
00684 }
00685 }
00686 else
00687 {
00688
00689 for(uint i=0;i<mBlock.RdrPass.size();i++)
00690 {
00691 CRdrPass &rdrPass= mBlock.RdrPass[i];
00692
00693 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00694 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
00695 {
00696
00697 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00698
00699
00700 if (useMeshVP)
00701 {
00702 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00703 }
00704
00705
00706 drv->activeIndexBuffer(rdrPass.PBlock);
00707 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00708 }
00709 }
00710 }
00711 }
00712
00713
00714 if(useMeshVP)
00715 {
00716
00717 _MeshVertexProgram->end(drv);
00718 }
00719 }
00720
00721
00722
00723 void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM)
00724 {
00725
00726 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
00727
00728 CScene *ownerScene= mi->getOwnerScene();
00729
00730 CRenderTrav *renderTrav= &ownerScene->getRenderTrav();
00731
00732 IDriver *drv= renderTrav->getDriver();
00733 nlassert(drv);
00734
00735
00736 CSkeletonModel *skeleton;
00737 skeleton= mi->getSkeletonModel();
00738
00739 nlassert(_Skinned && mi->isSkinned() && skeleton);
00740 bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00741 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00742
00743
00744
00745
00746 H_AUTO( NL3D_MeshGeom_RenderSkinned );
00747
00748
00749
00750
00751 if (bMorphApplied)
00752 {
00753
00754 _MeshMorpher->initSkinned(&_VBufferOri,
00755 &_VBuffer,
00756 useTangentSpace,
00757 &_OriginalSkinVertices,
00758 &_OriginalSkinNormals,
00759 useTangentSpace ? &_OriginalTGSpace : NULL,
00760 true );
00761 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00762 }
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773 applySkin(skeleton);
00774
00775
00776
00777
00778
00779
00780 bool useMeshVP= _MeshVertexProgram != NULL;
00781 if( useMeshVP )
00782 {
00783 CMatrix invertedObjectMatrix;
00784 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
00785
00786 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00787 }
00788
00789
00790
00791
00792
00793 drv->activeVertexBuffer(_VBuffer);
00794
00795
00796
00797 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00798 {
00799 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00800 if(mBlock.RdrPass.size()==0)
00801 continue;
00802
00803
00804 for(uint i=0;i<mBlock.RdrPass.size();i++)
00805 {
00806 CRdrPass &rdrPass= mBlock.RdrPass[i];
00807
00808
00809 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00810
00811
00812 if (useMeshVP)
00813 {
00814 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00815 }
00816
00817
00818 drv->activeIndexBuffer(rdrPass.PBlock);
00819 drv->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
00820 }
00821 }
00822
00823
00824 if(useMeshVP)
00825 {
00826
00827 _MeshVertexProgram->end(drv);
00828 }
00829
00830 }
00831
00832
00833
00834 void CMeshGeom::renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat)
00835 {
00836 H_AUTO( NL3D_MeshGeom_RenderSimpleWithMaterial );
00837
00838 nlassert(drv);
00839
00840
00841 drv->setupModelMatrix(worldMatrix);
00842
00843
00844 drv->activeVertexBuffer(_VBuffer);
00845
00846
00847 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00848 {
00849 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00850 if(mBlock.RdrPass.size()==0)
00851 continue;
00852
00853
00854 for(uint i=0;i<mBlock.RdrPass.size();i++)
00855 {
00856 CRdrPass &rdrPass= mBlock.RdrPass[i];
00857
00858
00859 drv->activeIndexBuffer(rdrPass.PBlock);
00860 drv->renderTriangles(mat, 0, rdrPass.PBlock.getNumIndexes()/3);
00861 }
00862 }
00863
00864 }
00865
00866
00867
00868 void CMeshGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00869 {
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889 sint ver = f.serialVersion (4);
00890
00891
00892
00893 if( !f.isReading() && _Skinned && !_OriginalSkinRestored )
00894 {
00895 restoreOriginalSkinVertices();
00896 }
00897
00898
00899
00900 if (ver >= 4)
00901 {
00902 f.serialCont (_BonesName);
00903 }
00904
00905 if (f.isReading())
00906 {
00907
00908 _BoneIdComputed = (ver < 4);
00909
00910 _BoneIdExtended= false;
00911 }
00912 else
00913 {
00914
00915 nlassert (_BoneIdComputed==false);
00916 }
00917
00918
00919 if (ver >= 3)
00920 {
00921 IMeshVertexProgram *mvp= NULL;
00922 if(f.isReading())
00923 {
00924 f.serialPolyPtr(mvp);
00925 _MeshVertexProgram= mvp;
00926 }
00927 else
00928 {
00929 mvp= _MeshVertexProgram;
00930 f.serialPolyPtr(mvp);
00931 }
00932 }
00933 else if(f.isReading())
00934 {
00935
00936 _MeshVertexProgram= NULL;
00937 }
00938
00939
00940
00941
00942
00943 if (ver >= 1)
00944 f.serial (*_MeshMorpher);
00945
00946
00947 f.serial (_VBuffer);
00948
00949 f.serialCont (_MatrixBlocks);
00950 f.serial (_BBox);
00951 f.serial (_Skinned);
00952
00953
00954
00955 if(f.isReading())
00956 {
00957
00958 if(ver < 2 )
00959 {
00960 optimizeTriangleOrder();
00961 }
00962 }
00963
00964
00965
00966 if(ver < 4)
00967 buildBoneUsageVer3();
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982 if(f.isReading())
00983 compileRunTime();
00984 }
00985
00986
00987
00988 void CMeshGeom::compileRunTime()
00989 {
00990
00991
00992
00993
00994
00995
00996 if(_Skinned)
00997 {
00998
00999 bkupOriginalSkinVertices();
01000
01001 buildShadowSkin();
01002 }
01003
01004
01005 _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
01006
01007
01008 bool supportMeshBlockRendering= !_Skinned && _MeshMorpher->BlendShapes.size()==0;
01009
01010
01011 supportMeshBlockRendering= supportMeshBlockRendering && _MatrixBlocks.size()==1 && _MatrixBlocks[0].RdrPass.size()>0;
01012 if (supportMeshBlockRendering && _MeshVertexProgram)
01013 {
01014 supportMeshBlockRendering = supportMeshBlockRendering && _MeshVertexProgram->supportMeshBlockRendering();
01015 }
01016
01017
01018
01019
01020
01021 bool supportMBRPerMaterial= supportMeshBlockRendering && _MeshVertexProgram==NULL;
01022
01023
01024
01025 _SupportMBRFlags= 0;
01026 if(supportMeshBlockRendering)
01027 _SupportMBRFlags|= MBROk;
01028 if(supportMBRPerMaterial)
01029 _SupportMBRFlags|= MBRSortPerMaterial;
01030
01031 bool avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 );
01032 _VBuffer.setPreferredMemory (avoidVBHard?CVertexBuffer::RAMPreferred:CVertexBuffer::StaticPreferred, false);
01033 }
01034
01035
01036 bool CMeshGeom::retrieveVertices(std::vector<NLMISC::CVector> &vertices) const
01037 {
01038
01039
01040
01041
01042
01043 uint i;
01044
01045
01046 const CVertexBuffer &vb= getVertexBuffer();
01047 if(vb.isResident())
01048 return false;
01049
01050 vertices.clear();
01051 vertices.resize(vb.getNumVertices());
01052 {
01053 CVertexBufferRead vba;
01054 vb.lock (vba);
01055 const uint8 *pVert= (const uint8*)vba.getVertexCoordPointer(0);
01056 uint vSize= vb.getVertexSize();
01057 for(i=0;i<vertices.size();i++)
01058 {
01059 vertices[i]= *(const CVector*)pVert;
01060 pVert+= vSize;
01061 }
01062 }
01063
01064 return true;
01065 }
01066
01067
01068 bool CMeshGeom::retrieveTriangles(std::vector<uint32> &indices) const
01069 {
01070
01071
01072
01073
01074
01075 uint i;
01076
01077 indices.clear();
01078
01079
01080 uint numTris= 0;
01081 for(i=0;i<getNbMatrixBlock();i++)
01082 {
01083 for(uint rp=0;rp<getNbRdrPass(i);rp++)
01084 {
01085
01086 const CIndexBuffer &pb= getRdrPassPrimitiveBlock(i, rp);
01087 if(pb.isResident())
01088 return false;
01089 numTris+= getRdrPassPrimitiveBlock(i, rp).getNumIndexes()/3;
01090 }
01091 }
01092 indices.resize(numTris*3);
01093
01094
01095 uint triIdx= 0;
01096 for(i=0;i<getNbMatrixBlock();i++)
01097 {
01098 for(uint rp=0;rp<getNbRdrPass(i);rp++)
01099 {
01100 const CIndexBuffer &pb= getRdrPassPrimitiveBlock(i, rp);
01101 CIndexBufferRead iba;
01102 pb.lock (iba);
01103
01104 if (pb.getFormat() == CIndexBuffer::Indices32)
01105 {
01106 memcpy(&indices[triIdx*3], iba.getPtr(), pb.getNumIndexes()*sizeof(uint32));
01107 }
01108 else
01109 {
01110
01111 std::copy((uint16 *) iba.getPtr(), ((uint16 *) iba.getPtr()) + pb.getNumIndexes(), &indices[triIdx*3]);
01112 }
01113
01114 triIdx+= pb.getNumIndexes()/3;
01115 }
01116 }
01117
01118 return true;
01119 }
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130 void CMeshGeom::buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp> &tmpFaces)
01131 {
01132 sint i,j,k;
01133 TBoneMap remainingBones;
01134 list<uint> remainingFaces;
01135
01136
01137
01138
01139 for(i=0;i<(sint)m.SkinWeights.size();i++)
01140 {
01141 CMesh::CSkinWeight &sw= m.SkinWeights[i];
01142
01143
01144 nlassert(sw.Weights[0]!=0);
01145
01146
01147 for(j=1;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01148 {
01149
01150 if(sw.Weights[j]==0)
01151 {
01152
01153 sw.MatrixId[j]= sw.MatrixId[0];
01154 }
01155 }
01156 }
01157
01158
01159
01160
01161 for(i=0;i<(sint)tmpFaces.size();i++)
01162 {
01163 CFaceTmp &face= tmpFaces[i];
01164
01165 for(j=0;j<3;j++)
01166 {
01167 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
01168 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01169 {
01170
01171
01172 remainingBones[sw.MatrixId[k]].RefCount++;
01173 }
01174 }
01175 }
01176
01177
01178
01179
01180 for(i=0;i<(sint)tmpFaces.size();i++)
01181 {
01182 remainingFaces.push_back(i);
01183 }
01184
01185
01186
01187
01188
01189
01190 vector<uint> boneUse;
01191 boneUse.reserve(NL3D_MESH_SKINNING_MAX_MATRIX*3);
01192
01193
01194 while(!remainingFaces.empty())
01195 {
01196
01197 _MatrixBlocks.push_back(CMatrixBlock());
01198 CMatrixBlock &matrixBlock= _MatrixBlocks[_MatrixBlocks.size()-1];
01199 matrixBlock.NumMatrix=0;
01200
01201
01202
01203 ItBoneMap itBone;
01204 for(itBone= remainingBones.begin();itBone!=remainingBones.end();itBone++)
01205 {
01206 itBone->second.Inserted= false;
01207 }
01208
01209
01210
01211
01212 while(!remainingBones.empty())
01213 {
01214
01215 uint currentBoneId= remainingBones.begin()->first;
01216
01217
01218 if(remainingBones.begin()->second.RefCount==0)
01219 {
01220 remainingBones.erase(remainingBones.begin());
01221 continue;
01222 }
01223
01224
01225 bool faceAdded= false;
01226
01227
01228 list<uint>::iterator itFace;
01229 for(itFace= remainingFaces.begin(); itFace!=remainingFaces.end();)
01230 {
01231 bool useCurrentBoneId;
01232 uint newBoneAdded;
01233
01234
01235
01236
01237
01238 tmpFaces[*itFace].buildBoneUse(boneUse, m.SkinWeights);
01239
01240
01241 useCurrentBoneId= false;
01242 for(i=0;i<(sint)boneUse.size();i++)
01243 {
01244
01245 if(boneUse[i]==currentBoneId)
01246 {
01247 useCurrentBoneId= true;
01248 break;
01249 }
01250 }
01251
01252 newBoneAdded=0;
01253 for(i=0;i<(sint)boneUse.size();i++)
01254 {
01255
01256 if(!remainingBones[boneUse[i]].Inserted)
01257 newBoneAdded++;
01258 }
01259
01260
01261
01262
01263
01264
01265
01266 if( newBoneAdded==0 ||
01267 (useCurrentBoneId && newBoneAdded+matrixBlock.NumMatrix < IDriver::MaxModelMatrix) )
01268 {
01269
01270
01271 CFaceTmp &face= tmpFaces[*itFace];
01272
01273
01274 for(j=0;j<3;j++)
01275 {
01276 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
01277
01278
01279 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01280 {
01281
01282 uint boneId= sw.MatrixId[k];
01283
01284 CBoneTmp &bone= remainingBones[boneId];
01285
01286
01287 bone.RefCount--;
01288
01289
01290 if( !bone.Inserted )
01291 {
01292
01293 bone.Inserted= true;
01294
01295 bone.MatrixIdInMB= matrixBlock.NumMatrix;
01296
01297
01298 matrixBlock.MatrixId[matrixBlock.NumMatrix]= boneId;
01299
01300 matrixBlock.NumMatrix++;
01301 }
01302
01303
01304
01305 face.Corner[j].Palette.MatrixId[k]= bone.MatrixIdInMB;
01306
01307 face.Corner[j].Weights[k]= sw.Weights[k];
01308 }
01309 }
01310
01311
01312 face.MatrixBlockId= _MatrixBlocks.size()-1;
01313
01314
01315 itFace= remainingFaces.erase(itFace);
01316
01317
01318 faceAdded= true;
01319 }
01320 else
01321 {
01322
01323 itFace++;
01324 }
01325 }
01326
01327
01328
01329 if(!faceAdded)
01330 break;
01331 }
01332
01333 }
01334
01335
01336
01337
01338
01339
01340 vector<CMatrixBlockRemap> blockRemaps;
01341 blockRemaps.resize(_MatrixBlocks.size());
01342
01343
01344
01345 for(i=1;i<(sint)_MatrixBlocks.size();i++)
01346 {
01347 CMatrixBlock &mBlock= _MatrixBlocks[i];
01348 CMatrixBlock &mPrevBlock= _MatrixBlocks[i-1];
01349 CMatrixBlockRemap &remap= blockRemaps[i];
01350
01351
01352 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01353 {
01354 remap.Remap[j]= mBlock.MatrixId[j];
01355 }
01356
01357
01358 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01359 {
01360
01361 sint idLoc= mPrevBlock.getMatrixIdLocation(mBlock.MatrixId[j]);
01362
01363
01364 if(idLoc==-1 || idLoc>=(sint)mBlock.NumMatrix || idLoc==j)
01365 {
01366
01367 j++;
01368 }
01369 else
01370 {
01371
01372 swap(mBlock.MatrixId[j], mBlock.MatrixId[idLoc]);
01373
01374 }
01375 }
01376
01377
01378 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01379 {
01380
01381 uint boneId= remap.Remap[j];
01382
01383 remap.Remap[j]= mBlock.getMatrixIdLocation(boneId);
01384 }
01385
01386
01387 }
01388
01389
01390
01391 for(i=0;i<(sint)tmpFaces.size();i++)
01392 {
01393 CFaceTmp &face= tmpFaces[i];
01394
01395 if(face.MatrixBlockId!=0)
01396 {
01397 CMatrixBlockRemap &remap= blockRemaps[face.MatrixBlockId];
01398
01399 for(j=0;j<3;j++)
01400 {
01401 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01402 {
01403 uint oldId= face.Corner[j].Palette.MatrixId[k];
01404 face.Corner[j].Palette.MatrixId[k]= (uint8)remap.Remap[oldId];
01405 }
01406 }
01407 }
01408 }
01409
01410 }
01411
01412
01413
01414 void CMeshGeom::CFaceTmp::buildBoneUse(vector<uint> &boneUse, vector<CMesh::CSkinWeight> &skinWeights)
01415 {
01416 boneUse.clear();
01417
01418
01419 for(sint i=0;i<3;i++)
01420 {
01421
01422 CMesh::CSkinWeight &sw= skinWeights[Corner[i].Vertex];
01423
01424
01425 for(sint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01426 {
01427 uint boneId= sw.MatrixId[j];
01428
01429 if( find(boneUse.begin(), boneUse.end(), boneId)==boneUse.end() )
01430 boneUse.push_back(boneId);
01431 }
01432 }
01433
01434
01435 }
01436
01437
01438
01439
01440 sint CMeshGeom::CMatrixBlock::getMatrixIdLocation(uint32 boneId) const
01441 {
01442 for(uint i=0;i<NumMatrix;i++)
01443 {
01444 if(MatrixId[i]==boneId)
01445 return i;
01446 }
01447
01448
01449 return -1;
01450 }
01451
01452
01453
01454 float CMeshGeom::getNumTriangles (float distance)
01455 {
01456
01457 uint32 triCount=0;
01458
01459
01460 uint mbCount=_MatrixBlocks.size();
01461 for (uint mb=0; mb<mbCount; mb++)
01462 {
01463 CMatrixBlock &block=_MatrixBlocks[mb];
01464
01465
01466 uint pCount=block.RdrPass.size();
01467 for (uint pb=0; pb<pCount; pb++)
01468 {
01469
01470 CRdrPass &pass=block.RdrPass[pb];
01471
01472
01473 triCount+=pass.PBlock.getNumIndexes ()/3;
01474 }
01475 }
01476 return (float)triCount;
01477 }
01478
01479
01480
01481 void CMeshGeom::computeBonesId (CSkeletonModel *skeleton)
01482 {
01483
01484 if (!_BoneIdComputed)
01485 {
01486
01487 nlassert (skeleton);
01488 if (skeleton)
01489 {
01490
01491 std::vector<uint> remap;
01492 skeleton->remapSkinBones(_BonesName, _BonesId, remap);
01493
01494
01495
01496 for (uint matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01497 {
01498
01499 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01500
01501
01502 uint matrix;
01503 for (matrix=0; matrix<mb.NumMatrix; matrix++)
01504 {
01505
01506 nlassert (mb.MatrixId[matrix]<remap.size());
01507 mb.MatrixId[matrix] = remap[mb.MatrixId[matrix]];
01508 }
01509 }
01510
01511
01512
01513 static std::vector<CAABBox> boneBBoxes;
01514 static std::vector<bool> boneBBEmpty;
01515 boneBBoxes.clear();
01516 boneBBEmpty.clear();
01517 boneBBoxes.resize(_BonesId.size());
01518 boneBBEmpty.resize(_BonesId.size(), true);
01519
01520
01521 for(uint vert=0;vert<_ShadowSkin.Vertices.size();vert++)
01522 {
01523 CShadowVertex &v= _ShadowSkin.Vertices[vert];
01524
01525 uint srcId= v.MatrixId;
01526 nlassert ( srcId < remap.size());
01527
01528 v.MatrixId= remap[srcId];
01529
01530
01531 if(_BonesId[srcId]>=0)
01532 {
01533
01534 CVector p= skeleton->Bones[_BonesId[srcId]].getBoneBase().InvBindPos * v.Vertex;
01535
01536 if(boneBBEmpty[srcId])
01537 {
01538 boneBBoxes[srcId].setCenter(p);
01539 boneBBEmpty[srcId]= false;
01540 }
01541 else
01542 {
01543 boneBBoxes[srcId].extend(p);
01544 }
01545 }
01546 }
01547
01548
01549 _BonesSphere.resize(_BonesId.size());
01550 for(uint bone=0;bone<_BonesSphere.size();bone++)
01551 {
01552
01553 if(boneBBEmpty[bone])
01554 {
01555 _BonesSphere[bone].Radius= -1;
01556 }
01557 else
01558 {
01559 _BonesSphere[bone].Center= boneBBoxes[bone].getCenter();
01560 _BonesSphere[bone].Radius= boneBBoxes[bone].getRadius();
01561 }
01562 }
01563
01564
01565
01566 _BoneIdComputed = true;
01567 }
01568 }
01569
01570
01571 if (!_BoneIdExtended)
01572 {
01573 nlassert (skeleton);
01574 if (skeleton)
01575 {
01576
01577 vector<bool> boneUsage;
01578 boneUsage.resize(skeleton->Bones.size(), false);
01579
01580
01581 uint i;
01582 for(i=0; i<_BonesId.size(); i++)
01583 {
01584
01585 if(_BonesId[i]<0)
01586 continue;
01587
01588
01589 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
01590 }
01591
01592
01593 _BonesIdExt.clear();
01594 for(i=0; i<boneUsage.size();i++)
01595 {
01596
01597 if(boneUsage[i])
01598 _BonesIdExt.push_back(i);
01599 }
01600
01601 }
01602
01603
01604 _BoneIdExtended= true;
01605 }
01606
01607 }
01608
01609
01610
01611 void CMeshGeom::buildBoneUsageVer3 ()
01612 {
01613 if(_Skinned)
01614 {
01615
01616 uint32 maxBoneId= 0;
01617
01618 uint matrixBlock;
01619 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01620 {
01621 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01622
01623 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01624 {
01625 maxBoneId= max(mb.MatrixId[matrix], maxBoneId);
01626 }
01627 }
01628
01629
01630 std::vector<uint8> boneUsage;
01631 boneUsage.resize(maxBoneId+1, 0);
01632
01633
01634 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01635 {
01636 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01637
01638 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01639 {
01640
01641 boneUsage[mb.MatrixId[matrix]]= 1;
01642 }
01643 }
01644
01645
01646 _BonesId.clear();
01647 for(uint i=0; i<boneUsage.size();i++)
01648 {
01649
01650 if(boneUsage[i])
01651 _BonesId.push_back(i);
01652 }
01653
01654
01655
01656 CBSphere sphere(CVector::Null, 0.f);
01657 _BonesSphere.clear();
01658 _BonesSphere.resize(_BonesId.size(), sphere);
01659
01660 }
01661 }
01662
01663
01664
01665 void CMeshGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
01666 {
01667
01668 for(uint i=0; i<_BonesIdExt.size();i++)
01669 {
01670 uint boneId= _BonesIdExt[i];
01671
01672 if(boneId>=sm->Bones.size())
01673 nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
01674
01675 if(increment)
01676 sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
01677 else
01678 sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
01679 }
01680 }
01681
01682
01683
01684 void CMeshGeom::bkupOriginalSkinVertices()
01685 {
01686 nlassert(_Skinned);
01687
01688
01689 contReset(_OriginalSkinVertices);
01690 contReset(_OriginalSkinNormals);
01691 contReset(_OriginalTGSpace);
01692
01693
01694 uint numVertices= _VBuffer.getNumVertices();
01695
01696 CVertexBufferRead vba;
01697 _VBuffer.lock (vba);
01698
01699
01700 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01701 {
01702
01703 _OriginalSkinVertices.resize(numVertices);
01704 for(uint i=0; i<numVertices;i++)
01705 {
01706 _OriginalSkinVertices[i]= *vba.getVertexCoordPointer(i);
01707 }
01708 }
01709 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01710 {
01711
01712 _OriginalSkinNormals.resize(numVertices);
01713 for(uint i=0; i<numVertices;i++)
01714 {
01715 _OriginalSkinNormals[i]= *vba.getNormalCoordPointer(i);
01716 }
01717 }
01718
01719
01720 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01721 {
01722
01723 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01724 uint tgSpaceStage = _VBuffer.getNumTexCoordUsed() - 1;
01725 _OriginalTGSpace.resize(numVertices);
01726 for(uint i=0; i<numVertices;i++)
01727 {
01728 _OriginalTGSpace[i]= *(CVector*)vba.getTexCoordPointer(i, tgSpaceStage);
01729 }
01730 }
01731 }
01732
01733
01734
01735 void CMeshGeom::restoreOriginalSkinVertices()
01736 {
01737 nlassert(_Skinned);
01738
01739
01740 uint numVertices= _VBuffer.getNumVertices();
01741
01742 CVertexBufferReadWrite vba;
01743 _VBuffer.lock (vba);
01744
01745
01746 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01747 {
01748
01749 for(uint i=0; i<numVertices;i++)
01750 {
01751 *vba.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
01752 }
01753 }
01754 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01755 {
01756
01757 for(uint i=0; i<numVertices;i++)
01758 {
01759 *vba.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
01760 }
01761 }
01762 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01763 {
01764 uint numTexCoords = _VBuffer.getNumTexCoordUsed();
01765 nlassert(numTexCoords >= 2);
01766 nlassert(_OriginalTGSpace.size() == numVertices);
01767
01768 for(uint i = 0; i < numVertices; ++i)
01769 {
01770 *(CVector*)vba.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
01771 }
01772 }
01773
01774
01775 _OriginalSkinRestored= true;
01776 }
01777
01778
01779
01780
01781 #define NL3D_SOFTSKIN_VNEEDCOMPUTE 3
01782 #define NL3D_SOFTSKIN_VMUSTCOMPUTE 1
01783 #define NL3D_SOFTSKIN_VCOMPUTED 0
01784
01785
01786
01787
01788
01789
01790 void CMeshGeom::applySkin(CSkeletonModel *skeleton)
01791 {
01792
01793
01794 if(_OriginalSkinVertices.empty())
01795 return;
01796
01797
01798 TSkinType skinType;
01799 if( _OriginalSkinNormals.empty() )
01800 skinType= SkinPosOnly;
01801 else if( _OriginalTGSpace.empty() )
01802 skinType= SkinWithNormal;
01803 else
01804 skinType= SkinWithTgSpace;
01805
01806
01807 uint numVertices= _OriginalSkinVertices.size();
01808 uint dstStride= _VBuffer.getVertexSize();
01809
01810 uint tgSpaceStage = 0;
01811 if( skinType>= SkinWithTgSpace)
01812 {
01813 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01814 tgSpaceStage= _VBuffer.getNumTexCoordUsed() - 1;
01815 }
01816
01817
01818 static vector<uint8> skinFlags;
01819 skinFlags.resize(numVertices);
01820
01821 memset(&skinFlags[0], NL3D_SOFTSKIN_VNEEDCOMPUTE, numVertices );
01822
01823 CVertexBufferRead vba;
01824 _VBuffer.lock (vba);
01825
01826
01827
01828 for(uint mb= 0; mb<_MatrixBlocks.size();mb++)
01829 {
01830
01831 static CMatrix3x4 matrixes[IDriver::MaxModelMatrix];
01832 computeSkinMatrixes(skeleton, matrixes, mb==0?NULL:&_MatrixBlocks[mb-1], _MatrixBlocks[mb]);
01833
01834
01835 flagSkinVerticesForMatrixBlock(&skinFlags[0], _MatrixBlocks[mb]);
01836
01837
01838 uint8 *pFlag= &skinFlags[0];
01839 CVector *srcVector= &_OriginalSkinVertices[0];
01840 uint8 *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
01841 uint8 *srcWgt= (uint8*)vba.getWeightPointer(0);
01842 uint8 *dstVector= (uint8*)vba.getVertexCoordPointer(0);
01843
01844 CVector *srcNormal= NULL;
01845 uint8 *dstNormal= NULL;
01846 if(skinType>=SkinWithNormal)
01847 {
01848 srcNormal= &_OriginalSkinNormals[0];
01849 dstNormal= (uint8*)vba.getNormalCoordPointer(0);
01850 }
01851
01852 CVector *srcTgSpace= NULL;
01853 uint8 *dstTgSpace= NULL;
01854 if(skinType>=SkinWithTgSpace)
01855 {
01856 srcTgSpace= &_OriginalTGSpace[0];
01857 dstTgSpace= (uint8*)vba.getTexCoordPointer(0, tgSpaceStage);
01858 }
01859
01860
01861
01862 uint size= numVertices;
01863 for(;size>0;size--)
01864 {
01865
01866 if(*pFlag==NL3D_SOFTSKIN_VMUSTCOMPUTE)
01867 {
01868
01869 *pFlag=NL3D_SOFTSKIN_VCOMPUTED;
01870
01871 CPaletteSkin *psPal= (CPaletteSkin*)srcPal;
01872
01873
01874 nlassert(psPal->MatrixId[0]<IDriver::MaxModelMatrix);
01875 nlassert(psPal->MatrixId[1]<IDriver::MaxModelMatrix);
01876 nlassert(psPal->MatrixId[2]<IDriver::MaxModelMatrix);
01877 nlassert(psPal->MatrixId[3]<IDriver::MaxModelMatrix);
01878
01879
01880 computeSoftwarePointSkinning(matrixes, srcVector, psPal, (float*)srcWgt, (CVector*)dstVector);
01881
01882
01883 if(skinType>=SkinWithNormal)
01884 computeSoftwareVectorSkinning(matrixes, srcNormal, psPal, (float*)srcWgt, (CVector*)dstNormal);
01885
01886
01887 if(skinType>=SkinWithTgSpace)
01888 computeSoftwareVectorSkinning(matrixes, srcTgSpace, psPal, (float*)srcWgt, (CVector*)dstTgSpace);
01889 }
01890
01891
01892 pFlag++;
01893
01894 srcVector++;
01895 srcNormal++;
01896 srcTgSpace++;
01897
01898 srcPal+= dstStride;
01899 srcWgt+= dstStride;
01900 dstVector+= dstStride;
01901 dstNormal+= dstStride;
01902 dstTgSpace+= dstStride;
01903 }
01904 }
01905
01906
01907
01908 _OriginalSkinRestored= false;
01909 }
01910
01911
01912
01913 void CMeshGeom::flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb)
01914 {
01915 for(uint i=0; i<mb.RdrPass.size(); i++)
01916 {
01917 CIndexBuffer &PB= mb.RdrPass[i].PBlock;
01918
01919 uint nIndex;
01920
01921
01922
01923
01924
01925
01926
01927
01928 CIndexBufferRead iba;
01929 PB.lock (iba);
01930 nIndex= PB.getNumIndexes();
01931 if (iba.getFormat() == CIndexBuffer::Indices32)
01932 {
01933 uint32 *pIndex= (uint32*)iba.getPtr();
01934 for(;nIndex>0;nIndex--, pIndex++)
01935 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01936 }
01937 else
01938 {
01939 uint16 *pIndex= (uint16*)iba.getPtr();
01940 for(;nIndex>0;nIndex--, pIndex++)
01941 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01942 }
01943 }
01944 }
01945
01946
01947
01948 void CMeshGeom::computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01949 {
01950 CMatrix3x4 *pMat;
01951
01952
01953 pMat= matrixes + srcPal->MatrixId[0];
01954 pMat->mulSetPoint(*srcVec, srcWgt[0], *pDst);
01955
01956 pMat= matrixes + srcPal->MatrixId[1];
01957 pMat->mulAddPoint(*srcVec, srcWgt[1], *pDst);
01958
01959 pMat= matrixes + srcPal->MatrixId[2];
01960 pMat->mulAddPoint(*srcVec, srcWgt[2], *pDst);
01961
01962 pMat= matrixes + srcPal->MatrixId[3];
01963 pMat->mulAddPoint(*srcVec, srcWgt[3], *pDst);
01964 }
01965
01966
01967
01968 void CMeshGeom::computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01969 {
01970 CMatrix3x4 *pMat;
01971
01972
01973 pMat= matrixes + srcPal->MatrixId[0];
01974 pMat->mulSetVector(*srcVec, srcWgt[0], *pDst);
01975
01976 pMat= matrixes + srcPal->MatrixId[1];
01977 pMat->mulAddVector(*srcVec, srcWgt[1], *pDst);
01978
01979 pMat= matrixes + srcPal->MatrixId[2];
01980 pMat->mulAddVector(*srcVec, srcWgt[2], *pDst);
01981
01982 pMat= matrixes + srcPal->MatrixId[3];
01983 pMat->mulAddVector(*srcVec, srcWgt[3], *pDst);
01984 }
01985
01986
01987
01988 void CMeshGeom::computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock *prevBlock, CMatrixBlock &mBlock)
01989 {
01990
01991 for(uint idMat=0;idMat<mBlock.NumMatrix;idMat++)
01992 {
01993 uint curBoneId= mBlock.MatrixId[idMat];
01994
01995
01996 if(prevBlock && idMat<prevBlock->NumMatrix && prevBlock->MatrixId[idMat]== curBoneId)
01997 continue;
01998
01999
02000 matrixes[idMat].set(skeleton->getActiveBoneSkinMatrix(curBoneId));
02001 }
02002 }
02003
02004
02005
02006 void CMeshGeom::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags)
02007 {
02008
02009 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
02010
02011
02012 uint triCount= 0;
02013 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
02014 {
02015 CMatrixBlock &mBlock= _MatrixBlocks[mb];
02016
02017
02018 for (uint i=0;i<mBlock.RdrPass.size();i++)
02019 {
02020 CRdrPass &rdrPass= mBlock.RdrPass[i];
02021
02022 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
02023 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
02024 {
02025 triCount+= rdrPass.PBlock.getNumIndexes()/3;
02026 }
02027 }
02028 }
02029
02030
02031 if(triCount)
02032 {
02033
02034 rdrTrav->Scene->incrementProfileTriVBFormat(rdrTrav->Scene->BenchRes.MeshProfileTriVBFormat,
02035 _VBuffer.getVertexFormat(), triCount);
02036
02037
02038 if(_VBuffer.getPreferredMemory()!=CVertexBuffer::RAMPreferred)
02039 rdrTrav->Scene->BenchRes.NumMeshVBufferHard++;
02040 else
02041 rdrTrav->Scene->BenchRes.NumMeshVBufferStd++;
02042
02043
02044 if(supportMeshBlockRendering() && (rdrFlags & IMeshGeom::RenderTransparentMaterial)==0 )
02045 {
02046 if(isMeshInVBHeap())
02047 {
02048 rdrTrav->Scene->BenchRes.NumMeshRdrBlockWithVBHeap++;
02049 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlockWithVBHeap+= triCount;
02050 }
02051 else
02052 {
02053 rdrTrav->Scene->BenchRes.NumMeshRdrBlock++;
02054 rdrTrav->Scene->BenchRes.NumMeshTriRdrBlock+= triCount;
02055 }
02056 }
02057 else
02058 {
02059 rdrTrav->Scene->BenchRes.NumMeshRdrNormal++;
02060 rdrTrav->Scene->BenchRes.NumMeshTriRdrNormal+= triCount;
02061 }
02062 }
02063 }
02064
02065
02066 bool CMeshGeom::intersectSkin(CTransformShape *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
02067 {
02068
02069
02070
02071 if(!mi || _OriginalSkinVertices.empty())
02072 return false;
02073 CSkeletonModel *skeleton= mi->getSkeletonModel();
02074 if(!skeleton)
02075 return false;
02076
02077
02078 static std::vector<uint32> matInfs;
02079 matInfs.resize(_BonesId.size());
02080 for(uint i=0;i<matInfs.size();i++)
02081 {
02082
02083 matInfs[i]= max(_BonesId[i], (sint32)0);
02084 }
02085 return _ShadowSkin.getRayIntersection(toRaySpace, *skeleton, matInfs, dist2D, distZ, computeDist2D);
02086 }
02087
02088
02089 void CMeshGeom::buildShadowSkin()
02090 {
02091
02092
02093
02094
02095
02096
02097 contReset(_ShadowSkin.Vertices);
02098 contReset(_ShadowSkin.Triangles);
02099
02100 nlassert(_Skinned && (_VBuffer.getVertexFormat() & CVertexBuffer::PaletteSkinFlag)
02101 && (_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag) );
02102
02103
02104
02105 {
02106
02107 uint numVertices= _VBuffer.getNumVertices();
02108
02109
02110 CVertexBufferRead vba;
02111 _VBuffer.lock (vba);
02112 uint8 *srcPal= (uint8*)vba.getPaletteSkinPointer(0);
02113 uint8 *srcVert= (uint8*)vba.getVertexCoordPointer(0);
02114 uint32 srcVertSize= _VBuffer.getVertexSize();
02115
02116
02117 _ShadowSkin.Vertices.resize(numVertices);
02118 for(uint i=0; i<numVertices;i++)
02119 {
02120
02121 _ShadowSkin.Vertices[i].Vertex= *((CVector*)srcVert);
02122
02123
02124 _ShadowSkin.Vertices[i].MatrixId= ((CPaletteSkin*)srcPal)->MatrixId[0];
02125
02126
02127 srcVert+= srcVertSize;
02128 srcPal+= srcVertSize;
02129 }
02130 }
02131
02132
02133
02134
02135
02136 uint numIndices= 0;
02137 uint mb;
02138
02139 vector<pair<uint32,uint32> > mbIndexRange;
02140 mbIndexRange.resize(_MatrixBlocks.size());
02141 for(mb=0;mb<_MatrixBlocks.size();mb++)
02142 {
02143
02144 mbIndexRange[mb].first= numIndices;
02145
02146
02147 const CMatrixBlock &mBlock= _MatrixBlocks[mb];
02148 for(uint rp=0;rp<mBlock.RdrPass.size();rp++)
02149 {
02150 const CRdrPass &rPass= mBlock.RdrPass[rp];
02151 numIndices+= rPass.PBlock.getNumIndexes();
02152 }
02153
02154
02155 mbIndexRange[mb].second= numIndices;
02156 }
02157
02158
02159
02160 nlverify(retrieveTriangles(_ShadowSkin.Triangles));
02161 nlassert(numIndices==_ShadowSkin.Triangles.size());
02162
02163
02164
02165
02166 vector<bool> vertReIndexed;
02167 vertReIndexed.resize(_ShadowSkin.Vertices.size(), false);
02168
02169 for(mb=0;mb<mbIndexRange.size();mb++)
02170 {
02171 const CMatrixBlock &mBlock= _MatrixBlocks[mb];
02172
02173 uint iStart= mbIndexRange[mb].first;
02174 uint iEnd= mbIndexRange[mb].second;
02175 nlassert(iStart <= iEnd && iEnd<=_ShadowSkin.Triangles.size());
02176
02177
02178 uint32 *pIndex= &_ShadowSkin.Triangles[iStart];
02179 uint nbIndex= iEnd - iStart;
02180 for(;nbIndex>0;--nbIndex, pIndex++)
02181 {
02182 uint index= *pIndex;
02183
02184 if(!vertReIndexed[index])
02185 {
02186 vertReIndexed[index]= true;
02187
02188 uint matId= _ShadowSkin.Vertices[index].MatrixId;
02189 nlassert(matId<mBlock.NumMatrix);
02190 _ShadowSkin.Vertices[index].MatrixId= mBlock.MatrixId[matId];
02191 }
02192 }
02193 }
02194 }
02195
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205 bool CMeshGeom::supportMeshBlockRendering () const
02206 {
02207 return _SupportMBRFlags!=0;
02208 }
02209
02210
02211 bool CMeshGeom::sortPerMaterial() const
02212 {
02213 return (_SupportMBRFlags & MBRSortPerMaterial)!=0;
02214 }
02215
02216 uint CMeshGeom::getNumRdrPassesForMesh() const
02217 {
02218 return _MatrixBlocks[0].RdrPass.size();
02219 }
02220
02221 uint CMeshGeom::getNumRdrPassesForInstance(CMeshBaseInstance *inst) const
02222 {
02223 return _MatrixBlocks[0].RdrPass.size();
02224 }
02225
02226 void CMeshGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
02227 {
02228 if(rdrCtx.RenderThroughVBHeap)
02229 {
02230
02231
02232 nlassert( (_SupportMBRFlags & MBRCurrentUseVP)==0 );
02233 }
02234 else
02235 {
02236
02237 if( _MeshVertexProgram != NULL && _MeshVertexProgram->isMBRVpOk(rdrCtx.Driver) )
02238 {
02239
02240 _SupportMBRFlags|= MBRCurrentUseVP;
02241
02242 _MeshVertexProgram->beginMBRMesh(rdrCtx.Driver, rdrCtx.Scene );
02243 }
02244
02245
02246 rdrCtx.Driver->activeVertexBuffer(_VBuffer);
02247 }
02248 }
02249
02250 void CMeshGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst)
02251 {
02252
02253 rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
02254
02255
02256 inst->changeLightSetup(rdrCtx.RenderTrav);
02257
02258
02259 if( _SupportMBRFlags & MBRCurrentUseVP )
02260 {
02261 CMatrix invertedObjectMatrix;
02262 invertedObjectMatrix = inst->getWorldMatrix().inverted();
02263 _MeshVertexProgram->beginMBRInstance(rdrCtx.Driver, rdrCtx.Scene, inst, invertedObjectMatrix);
02264 }
02265 }
02266
02267 void CMeshGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
02268 {
02269 CMatrixBlock &mBlock= _MatrixBlocks[0];
02270
02271 CRdrPass &rdrPass= mBlock.RdrPass[rdrPassId];
02272
02273 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) ) )
02274 {
02275 CMaterial &material= mi->Materials[rdrPass.MaterialId];
02276
02277
02278 if( _SupportMBRFlags & MBRCurrentUseVP )
02279 {
02280 rdrCtx.RenderTrav->changeVPLightSetupMaterial(material, false);
02281 }
02282
02283 if(rdrCtx.RenderThroughVBHeap)
02284 {
02285
02286 rdrCtx.Driver->activeIndexBuffer(rdrPass.VBHeapPBlock);
02287 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.VBHeapPBlock.getNumIndexes()/3);
02288 }
02289 else
02290 {
02291
02292 rdrCtx.Driver->activeIndexBuffer(rdrPass.PBlock);
02293 rdrCtx.Driver->renderTriangles(material, 0, rdrPass.PBlock.getNumIndexes()/3);
02294 }
02295 }
02296 }
02297
02298 void CMeshGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
02299 {
02300
02301 if( _SupportMBRFlags & MBRCurrentUseVP )
02302 {
02303
02304 _MeshVertexProgram->endMBRMesh( rdrCtx.Driver );
02305
02306
02307 _SupportMBRFlags&= ~MBRCurrentUseVP;
02308 }
02309 }
02310
02311
02312 bool CMeshGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
02313 {
02314
02315 if( _SupportMBRFlags )
02316
02317
02318
02319
02320 if( _MeshVertexProgram==NULL )
02321 {
02322 vertexFormat= _VBuffer.getVertexFormat();
02323 numVertices= _VBuffer.getNumVertices();
02324 return true;
02325 }
02326
02327 return false;
02328 }
02329
02330
02331 void CMeshGeom::computeMeshVBHeap(void *dst, uint indexStart)
02332 {
02333
02334 CVertexBufferRead vba;
02335 _VBuffer.lock (vba);
02336 memcpy(dst, vba.getVertexCoordPointer(), _VBuffer.getNumVertices()*_VBuffer.getVertexSize() );
02337
02338
02339 nlassert(_MatrixBlocks.size()==1);
02340 CMatrixBlock &mBlock= _MatrixBlocks[0];
02341
02342 for(uint i=0;i<mBlock.RdrPass.size();i++)
02343 {
02344
02345 CIndexBuffer &srcPb= mBlock.RdrPass[i].PBlock;
02346 CIndexBuffer &dstPb= mBlock.RdrPass[i].VBHeapPBlock;
02347 uint j;
02348
02349
02350 dstPb.setNumIndexes(srcPb.getNumIndexes());
02351 CIndexBufferRead ibaRead;
02352 srcPb.lock (ibaRead);
02353 CIndexBufferReadWrite ibaWrite;
02354 dstPb.lock (ibaWrite);
02355
02356 nlassert(ibaRead.getFormat() == CIndexBuffer::Indices32);
02357 nlassert(ibaWrite.getFormat() == CIndexBuffer::Indices32);
02358 const uint32 *srcTriPtr= (const uint32 *) ibaRead.getPtr();
02359 uint32 *dstTriPtr= (uint32 *) ibaWrite.getPtr();
02360 for(j=0; j<dstPb.getNumIndexes();j++)
02361 {
02362 dstTriPtr[j]= srcTriPtr[j]+indexStart;
02363 }
02364 }
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377 CMesh::CCorner::CCorner()
02378 {
02379 sint i;
02380 Vertex= 0;
02381 Normal= CVector::Null;
02382 for(i=0;i<CVertexBuffer::MaxStage;i++)
02383 {
02384 Uvws[i]= CUVW(0, 0, 0);
02385 }
02386 Color.set(255,255,255,255);
02387 Specular.set(0,0,0,0);
02388 }
02389
02390
02391
02392 void CMesh::CCorner::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02393 {
02394 nlassert(0);
02395 f.serial(Vertex);
02396 f.serial(Normal);
02397 for(int i=0;i<CVertexBuffer::MaxStage;++i) f.serial(Uvws[i]);
02398 f.serial(Color);
02399 f.serial(Specular);
02400 }
02401
02402
02403 void CMesh::CFace::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02404 {
02405 for(int i=0;i<3;++i)
02406 f.serial(Corner[i]);
02407 f.serial(MaterialId);
02408 f.serial(SmoothGroup);
02409 }
02410
02411
02412 void CMesh::CSkinWeight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02413 {
02414 for(int i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;++i)
02415 {
02416 f.serial(MatrixId[i]);
02417 f.serial(Weights[i]);
02418 }
02419 }
02420
02421
02422
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440 CMesh::CMeshBuild::CMeshBuild()
02441 {
02442 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
02443 {
02444 NumCoords[k] = 2;
02445 UVRouting[k] = k;
02446 }
02447 }
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459 CMesh::CMesh()
02460 {
02461
02462
02463
02464
02465
02466
02467 _MeshGeom= new CMeshGeom;
02468 }
02469
02470 CMesh::~CMesh()
02471 {
02472
02473
02474
02475
02476
02477
02478 delete _MeshGeom;
02479 }
02480
02481
02482
02483 CMesh::CMesh(const CMesh &mesh) : CMeshBase()
02484 {
02485
02486 _MeshGeom= new CMeshGeom(*mesh._MeshGeom);
02487 }
02488
02489
02490
02491 CMesh &CMesh::operator=(const CMesh &mesh)
02492 {
02493
02494 (CMeshBase&)*this= (CMeshBase&)mesh;
02495
02496
02497 *_MeshGeom= *mesh._MeshGeom;
02498
02499
02500 return *this;
02501 }
02502
02503
02504
02505
02506 void CMesh::build (CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &m)
02507 {
02509 CMeshBase::buildMeshBase (mbase);
02510
02511
02512 _MeshGeom->build (m, mbase.Materials.size());
02513
02514
02515 compileRunTime();
02516 }
02517
02518
02519
02520 void CMesh::optimizeMaterialUsage(std::vector<sint> &remap)
02521 {
02522
02523 vector<bool> materialUsed;
02524 materialUsed.resize(CMeshBase::_Materials.size(), false);
02525 for(uint mb=0;mb<getNbMatrixBlock();mb++)
02526 {
02527 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
02528 {
02529 uint matId= getRdrPassMaterial(mb, rp);
02530
02531 materialUsed[matId]= true;
02532 }
02533 }
02534
02535
02536 CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
02537
02538
02539 _MeshGeom->applyMaterialRemap(remap);
02540 }
02541
02542
02543
02544 void CMesh::setBlendShapes(std::vector<CBlendShape>&bs)
02545 {
02546 _MeshGeom->setBlendShapes (bs);
02547 }
02548
02549
02550 void CMesh::build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom)
02551 {
02553 CMeshBase::buildMeshBase(mbuild);
02554
02555
02556 *_MeshGeom= meshGeom;
02557
02558
02559 compileRunTime();
02560 }
02561
02562
02563
02564 CTransformShape *CMesh::createInstance(CScene &scene)
02565 {
02566
02567
02568 CMeshInstance *mi= (CMeshInstance*)scene.createModel(NL3D::MeshInstanceId);
02569 mi->Shape= this;
02570
02571
02572 CMeshBase::instanciateMeshBase(mi, &scene);
02573
02574
02575
02576 _MeshGeom->initInstance(mi);
02577
02578
02579 mi->initRenderFilterType();
02580
02581 return mi;
02582 }
02583
02584
02585
02586 bool CMesh::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
02587 {
02588 return _MeshGeom->clip(pyramid, worldMatrix);
02589 }
02590
02591
02592
02593 void CMesh::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
02594 {
02595
02596 uint32 mask= (0-(uint32)passOpaque);
02597 uint32 rdrFlags;
02598
02599 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02600 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
02601
02602 _MeshGeom->render(drv, trans, 0, rdrFlags, 1);
02603 }
02604
02605
02606
02607 void CMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02608 {
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621 sint ver= f.serialVersion(6);
02622
02623
02624 if(ver<6)
02625 throw NLMISC::EStream(f, "Mesh in Stream is too old (Mesh version < 6)");
02626
02627
02628
02629 CMeshBase::serialMeshBase(f);
02630
02631
02632
02633 _MeshGeom->serial(f);
02634
02635
02636 if(f.isReading())
02637 compileRunTime();
02638 }
02639
02640
02641
02642 const NLMISC::CAABBoxExt& CMesh::getBoundingBox() const
02643 {
02644 return _MeshGeom->getBoundingBox();
02645 }
02646
02647 const CVertexBuffer &CMesh::getVertexBuffer() const
02648 {
02649 return _MeshGeom->getVertexBuffer() ;
02650 }
02651
02652 uint CMesh::getNbMatrixBlock() const
02653 {
02654 return _MeshGeom->getNbMatrixBlock();
02655 }
02656
02657 uint CMesh::getNbRdrPass(uint matrixBlockIndex) const
02658 {
02659 return _MeshGeom->getNbRdrPass(matrixBlockIndex) ;
02660 }
02661
02662 const CIndexBuffer &CMesh::getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
02663 {
02664 return _MeshGeom->getRdrPassPrimitiveBlock(matrixBlockIndex, renderingPassIndex) ;
02665 }
02666
02667 uint32 CMesh::getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
02668 {
02669 return _MeshGeom->getRdrPassMaterial(matrixBlockIndex, renderingPassIndex) ;
02670 }
02671
02672 float CMesh::getNumTriangles (float distance)
02673 {
02674
02675 return 0;
02676 }
02677
02678 const CMeshGeom& CMesh::getMeshGeom () const
02679 {
02680 return *_MeshGeom;
02681 }
02682
02683 void CMesh::computeBonesId (CSkeletonModel *skeleton)
02684 {
02685 nlassert (_MeshGeom);
02686 _MeshGeom->computeBonesId (skeleton);
02687 }
02688
02689
02690
02691 void CMesh::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
02692 {
02693 nlassert (_MeshGeom);
02694 _MeshGeom->updateSkeletonUsage(sm, increment);
02695 }
02696
02697
02698 IMeshGeom *CMesh::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
02699 {
02700
02701 if(_MeshGeom->supportMeshBlockRendering())
02702 {
02703 polygonCount= 0;
02704 return _MeshGeom;
02705 }
02706 else
02707 return NULL;
02708 }
02709
02710
02711
02712 void CMesh::profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool passOpaque)
02713 {
02714
02715 uint32 mask= (0-(uint32)passOpaque);
02716 uint32 rdrFlags;
02717
02718 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02719 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
02720
02721 _MeshGeom->profileSceneRender(rdrTrav, trans, 0, rdrFlags);
02722 }
02723
02724
02725 void CMesh::compileRunTime()
02726 {
02727
02728
02729
02730
02731
02732
02733
02734 if(_VisualCollisionMesh)
02735 {
02736 delete _VisualCollisionMesh;
02737 _VisualCollisionMesh= NULL;
02738 }
02739
02740 if( (_CollisionMeshGeneration==AutoCameraCol && !_LightInfos.empty()) ||
02741 _CollisionMeshGeneration==ForceCameraCol )
02742 {
02743
02744 vector<CVector> vertices;
02745 vector<uint32> indices;
02746 if(_MeshGeom->retrieveVertices(vertices) && _MeshGeom->retrieveTriangles(indices))
02747 {
02748
02749 _VisualCollisionMesh= new CVisualCollisionMesh;
02750
02751 if( !_VisualCollisionMesh->build(vertices, indices,const_cast<CVertexBuffer&>(_MeshGeom->getVertexBuffer())) )
02752 {
02753
02754 delete _VisualCollisionMesh;
02755 _VisualCollisionMesh= NULL;
02756 }
02757 }
02758 }
02759 }
02760
02761
02762 void CMesh::buildSystemGeometry()
02763 {
02764
02765 _SystemGeometry.clear();
02766
02767
02768
02769 if(_MeshGeom->isSkinned())
02770 return;
02771
02772
02773 if( !_MeshGeom->retrieveVertices(_SystemGeometry.Vertices) ||
02774 !_MeshGeom->retrieveTriangles(_SystemGeometry.Triangles))
02775 {
02776 _SystemGeometry.clear();
02777 }
02778
02779
02780
02781
02782
02783
02784 }
02785
02786
02787 }
02788
02789
02790