00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/mesh.h"
00029 #include "3d/mesh_instance.h"
00030 #include "3d/scene.h"
00031 #include "3d/skeleton_model.h"
00032 #include "3d/mesh_morpher.h"
00033 #include "nel/misc/bsphere.h"
00034 #include "3d/stripifier.h"
00035 #include "3d/fast_floor.h"
00036 #include "nel/misc/hierarchical_timer.h"
00037 #include "3d/mesh_blender.h"
00038 #include "3d/matrix_3x4.h"
00039 #include "3d/render_trav.h"
00040
00041
00042 using namespace std;
00043 using namespace NLMISC;
00044
00045
00046 namespace NL3D
00047 {
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 static NLMISC::CAABBoxExt makeBBox(const std::vector<CVector> &Vertices)
00059 {
00060 NLMISC::CAABBox ret;
00061 nlassert(Vertices.size());
00062 ret.setCenter(Vertices[0]);
00063 for(sint i=0;i<(sint)Vertices.size();i++)
00064 {
00065 ret.extend(Vertices[i]);
00066 }
00067
00068 return ret;
00069 }
00070
00071
00072
00073 sint CMeshGeom::CCornerTmp::Flags=0;
00074
00075
00076
00077 bool CMeshGeom::CCornerTmp::operator<(const CCornerTmp &c) const
00078 {
00079 sint i;
00080
00081
00082 if(Vertex!=c.Vertex)
00083 return Vertex<c.Vertex;
00084
00085
00086 if((CCornerTmp::Flags & CVertexBuffer::NormalFlag) && Normal!=c.Normal)
00087 return Normal<c.Normal;
00088 for(i=0; i<CVertexBuffer::MaxStage; i++)
00089 {
00090 if((CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i)) && Uvws[i]!=c.Uvws[i])
00091 return Uvws[i]<c.Uvws[i];
00092 }
00093 if((CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag) && Color!=c.Color)
00094 return Color<c.Color;
00095 if((CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag) && Specular!=c.Specular)
00096 return Specular<c.Specular;
00097
00098 if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
00099 {
00100 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00101 {
00102 if(Palette.MatrixId[i] != c.Palette.MatrixId[i])
00103 return Palette.MatrixId[i] < c.Palette.MatrixId[i];
00104 if(Weights[i] != c.Weights[i])
00105 return Weights[i] < c.Weights[i];
00106 }
00107 }
00108
00109
00110
00111 return false;
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 CMeshGeom::CMeshGeom()
00124 {
00125 _Skinned= false;
00126 _OriginalSkinRestored= true;
00127 _VertexBufferHardDirty= true;
00128 _MeshMorpher = new CMeshMorpher;
00129 _BoneIdComputed = false;
00130 _BoneIdExtended= false;
00131 _PreciseClipping= false;
00132 }
00133
00134
00135
00136 CMeshGeom::~CMeshGeom()
00137 {
00138
00139 if(_VertexBufferHard!=NULL)
00140 {
00141
00142 nlassert(_Driver!=NULL);
00143
00144
00145 _Driver->deleteVertexBufferHard(_VertexBufferHard);
00146 _VertexBufferHard= NULL;
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 _VertexBufferHardDirty= true;
00178
00179
00180 if(m.Vertices.size()==0 || m.Faces.size()==0)
00181 {
00182 _VBuffer.setNumVertices(0);
00183 _VBuffer.reserve(0);
00184 _MatrixBlocks.clear();
00185 _BBox.setCenter(CVector::Null);
00186 _BBox.setSize(CVector::Null);
00187 return;
00188 }
00189 nlassert(numMaxMaterial>0);
00190
00191
00193
00194 _BBox= makeBBox(m.Vertices);
00195
00196
00198
00199
00200
00201 vector<CFaceTmp> tmpFaces;
00202 tmpFaces.resize(m.Faces.size());
00203 for(i=0;i<(sint)tmpFaces.size();i++)
00204 tmpFaces[i]= m.Faces[i];
00205
00206 _Skinned= ((m.VertexFlags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag);
00207
00208 _Skinned= _Skinned && (m.Vertices.size()==m.SkinWeights.size());
00209
00210
00211 uint vbFlags= m.VertexFlags;
00212 if(!_Skinned)
00213 vbFlags&= ~CVertexBuffer::PaletteSkinFlag;
00214
00215 vbFlags|= CVertexBuffer::PositionFlag;
00216
00217
00218
00219 if(!_Skinned)
00220 {
00221 _MatrixBlocks.resize(1);
00222
00223 for(i=0;i<(sint)tmpFaces.size();i++)
00224 tmpFaces[i].MatrixBlockId= 0;
00225 }
00226
00227 else
00228 {
00229
00230 _MatrixBlocks.clear();
00231
00232 buildSkin(m, tmpFaces);
00233 }
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
00335 for(i=0;i<(sint)_MatrixBlocks[mb].RdrPass.size(); i++)
00336 {
00337 _MatrixBlocks[mb].RdrPass[i].MaterialId= i;
00338 }
00339 }
00340
00341
00343
00344 pFace= &(*tmpFaces.begin());
00345 N= tmpFaces.size();
00346 for(;N>0;N--, pFace++)
00347 {
00348 sint mbId= pFace->MatrixBlockId;
00349 nlassert(mbId>=0 && mbId<(sint)_MatrixBlocks.size());
00350
00351 _MatrixBlocks[mbId].RdrPass[pFace->MaterialId].PBlock.addTri(pFace->Corner[0].VBId, pFace->Corner[1].VBId, pFace->Corner[2].VBId);
00352 }
00353
00354
00356
00357 for(mb= 0;mb<_MatrixBlocks.size();mb++)
00358 {
00359
00360 vector<CRdrPass>::iterator itPass;
00361 for( itPass=_MatrixBlocks[mb].RdrPass.begin(); itPass!=_MatrixBlocks[mb].RdrPass.end(); )
00362 {
00363
00364 if( itPass->PBlock.getNumTri()==0 )
00365 itPass= _MatrixBlocks[mb].RdrPass.erase(itPass);
00366 else
00367 itPass++;
00368 }
00369 }
00370
00372
00373
00374 this->_MeshMorpher->BlendShapes = m.BlendShapes;
00375
00376
00377 optimizeTriangleOrder();
00378
00379
00380 this->_MeshVertexProgram= m.MeshVertexProgram;
00381
00383
00384
00385
00386 if(_Skinned)
00387 {
00388
00389 _BonesName.reserve (m.BonesNames.size ());
00390
00391
00392 uint currentBone = 0;
00393
00394
00395 uint matrixBlock;
00396 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
00397 {
00398
00399 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
00400
00401
00402 std::map<uint, uint> remap;
00403
00404
00405 uint matrix;
00406 for (matrix=0; matrix<mb.NumMatrix; matrix++)
00407 {
00408
00409 std::map<uint, uint>::iterator ite = remap.find (mb.MatrixId[matrix]);
00410
00411
00412 if (ite == remap.end())
00413 {
00414
00415 remap.insert (std::map<uint, uint>::value_type (mb.MatrixId[matrix], currentBone));
00416
00417
00418 nlassert (mb.MatrixId[matrix] < m.BonesNames.size());
00419
00420
00421 _BonesName.push_back (m.BonesNames[mb.MatrixId[matrix]]);
00422
00423
00424 mb.MatrixId[matrix] = currentBone++;
00425 }
00426 else
00427 {
00428
00429 mb.MatrixId[matrix] = ite->second;
00430 }
00431 }
00432 }
00433
00434
00435 _BoneIdComputed = false;
00436 _BoneIdExtended = false;
00437 }
00438
00439
00440
00441
00442 compileRunTime();
00443 }
00444
00445
00446 void CMeshGeom::setBlendShapes(std::vector<CBlendShape>&bs)
00447 {
00448 _MeshMorpher->BlendShapes = bs;
00449
00450 compileRunTime();
00451 }
00452
00453
00454
00455 void CMeshGeom::applyMaterialRemap(const std::vector<sint> &remap)
00456 {
00457 for(uint mb=0;mb<getNbMatrixBlock();mb++)
00458 {
00459 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
00460 {
00461
00462 uint32 &matId= _MatrixBlocks[mb].RdrPass[rp].MaterialId;
00463 nlassert(remap[matId]>=0);
00464 matId= remap[matId];
00465 }
00466 }
00467 }
00468
00469
00470
00471 void CMeshGeom::initInstance(CMeshBaseInstance *mbi)
00472 {
00473
00474 if(_MeshVertexProgram)
00475 _MeshVertexProgram->initInstance(mbi);
00476 }
00477
00478
00479 bool CMeshGeom::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
00480 {
00481
00482 CBSphere localSphere(_BBox.getCenter(), _BBox.getRadius());
00483 CBSphere worldSphere;
00484
00485
00486 localSphere.applyTransform(worldMatrix, worldSphere);
00487
00488
00489 for(sint i=0;i<(sint)pyramid.size();i++)
00490 {
00491
00492
00493 float d= pyramid[i]*worldSphere.Center;
00494 if(d>worldSphere.Radius)
00495 return false;
00496 }
00497
00498
00499 if( _PreciseClipping )
00500 {
00501 CPlane localPlane;
00502
00503
00504 for(sint i=0;i<(sint)pyramid.size();i++)
00505 {
00506
00507 localPlane= pyramid[i]*worldMatrix;
00508
00509 localPlane.normalize();
00510
00511 if( !_BBox.clipBack(localPlane) )
00512 return false;
00513 }
00514 }
00515
00516 return true;
00517 }
00518
00519
00520 void CMeshGeom::updateVertexBufferHard(IDriver *drv)
00521 {
00522 if(!drv->supportVertexBufferHard())
00523 return;
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 bool avoidVBHard;
00534 avoidVBHard= _Skinned || ( _MeshMorpher && _MeshMorpher->BlendShapes.size()>0 && drv->slowUnlockVertexBufferHard() );
00535 if( _VertexBufferHardDirty && avoidVBHard )
00536 {
00537
00538 if(_VertexBufferHard!=NULL)
00539 {
00540
00541 nlassert(_Driver!=NULL);
00542 _Driver->deleteVertexBufferHard(_VertexBufferHard);
00543 }
00544 return;
00545 }
00546
00547
00548 if(_VertexBufferHardDirty || _VertexBufferHard==NULL)
00549 {
00550 _VertexBufferHardDirty= false;
00551
00552
00553 if(_VertexBufferHard!=NULL)
00554 {
00555
00556 nlassert(_Driver!=NULL);
00557 _Driver->deleteVertexBufferHard(_VertexBufferHard);
00558 }
00559
00560
00561 _Driver= drv;
00562
00563 _VertexBufferHard= _Driver->createVertexBufferHard(_VBuffer.getVertexFormat(), _VBuffer.getValueTypePointer (), _VBuffer.getNumVertices(), IDriver::VBHardAGP);
00564
00565
00566 if(_VertexBufferHard==NULL)
00567 return;
00568
00569 else
00570 {
00571 void *vertexPtr= _VertexBufferHard->lock();
00572
00573 nlassert(_VBuffer.getVertexFormat() == _VertexBufferHard->getVertexFormat());
00574 nlassert(_VBuffer.getNumVertices() == _VertexBufferHard->getNumVertices());
00575 nlassert(_VBuffer.getVertexSize() == _VertexBufferHard->getVertexSize());
00576
00577
00578
00579 memcpy(vertexPtr, _VBuffer.getVertexCoordPointer(), _VBuffer.getNumVertices() * _VBuffer.getVertexSize() );
00580
00581 _VertexBufferHard->unlock();
00582 }
00583
00584 }
00585 }
00586
00587
00588
00589 void CMeshGeom::render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha)
00590 {
00591 nlassert(drv);
00592
00593 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
00594
00595 CScene *ownerScene= mi->getScene();
00596
00597 CRenderTrav *renderTrav= ownerScene->getRenderTrav();
00598
00599
00600
00601 updateVertexBufferHard (drv);
00602
00603
00604
00605
00606 IVertexBufferHard *currentVBHard= _VertexBufferHard;
00607
00608
00609
00610 CSkeletonModel *skeleton;
00611 skeleton= mi->getSkeletonModel();
00612
00613 nlassert(!(_Skinned && mi->isSkinned() && skeleton));
00614 bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00615 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00616
00617
00618
00619
00620 H_AUTO( NL3D_MeshGeom_RenderNormal );
00621
00622
00623
00624
00625 if (bMorphApplied)
00626 {
00627
00628
00629
00630 if (_Skinned)
00631 {
00632 _MeshMorpher->initSkinned(&_VBufferOri,
00633 &_VBuffer,
00634 currentVBHard,
00635 useTangentSpace,
00636 &_OriginalSkinVertices,
00637 &_OriginalSkinNormals,
00638 useTangentSpace ? &_OriginalTGSpace : NULL,
00639 false );
00640 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00641 }
00642 else
00643 {
00644 _MeshMorpher->init(&_VBufferOri,
00645 &_VBuffer,
00646 currentVBHard,
00647 useTangentSpace);
00648 _MeshMorpher->update (mi->getBlendShapeFactors());
00649 }
00650 }
00651
00652
00653
00654
00655
00656
00657 drv->setupModelMatrix(trans->getWorldMatrix());
00658
00659
00660
00661 if (_Skinned)
00662 {
00663
00664 if (!_OriginalSkinRestored)
00665 restoreOriginalSkinVertices();
00666 }
00667
00668
00669
00670
00671
00672
00673 bool useMeshVP= _MeshVertexProgram != NULL;
00674 if( useMeshVP )
00675 {
00676 CMatrix invertedObjectMatrix;
00677 invertedObjectMatrix = trans->getWorldMatrix().inverted();
00678
00679 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00680 }
00681
00682
00683
00684
00685
00686 if(currentVBHard != NULL)
00687 drv->activeVertexBufferHard(currentVBHard);
00688 else
00689 drv->activeVertexBuffer(_VBuffer);
00690
00691
00692
00693 uint32 globalAlphaUsed= rdrFlags & IMeshGeom::RenderGlobalAlpha;
00694 uint8 globalAlphaInt=(uint8)OptFastFloor(globalAlpha*255);
00695
00696
00697
00698 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00699 {
00700 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00701 if(mBlock.RdrPass.size()==0)
00702 continue;
00703
00704
00705 if (globalAlphaUsed)
00706 {
00707 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
00708
00709
00710 for (uint i=0;i<mBlock.RdrPass.size();i++)
00711 {
00712 CRdrPass &rdrPass= mBlock.RdrPass[i];
00713
00714 if ( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00715 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
00716 {
00717
00718 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00719
00720
00721 CMeshBlender blender;
00722 blender.prepareRenderForGlobalAlpha(material, drv, globalAlpha, globalAlphaInt, gaDisableZWrite);
00723
00724
00725 if (useMeshVP)
00726 {
00727 if(currentVBHard)
00728 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
00729 else
00730 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00731 }
00732
00733
00734 drv->render(rdrPass.PBlock, material);
00735
00736
00737 blender.restoreRender(material, drv, gaDisableZWrite);
00738 }
00739 }
00740 }
00741 else
00742 {
00743
00744 for(uint i=0;i<mBlock.RdrPass.size();i++)
00745 {
00746 CRdrPass &rdrPass= mBlock.RdrPass[i];
00747
00748 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) ) ||
00749 ( (mi->Materials[rdrPass.MaterialId].getBlend() == true) && (rdrFlags & IMeshGeom::RenderTransparentMaterial) ) )
00750 {
00751
00752 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00753
00754
00755 if (useMeshVP)
00756 {
00757 if(currentVBHard)
00758 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
00759 else
00760 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00761 }
00762
00763
00764 drv->render(rdrPass.PBlock, material);
00765 }
00766 }
00767 }
00768 }
00769
00770
00771 if(useMeshVP)
00772 {
00773
00774 _MeshVertexProgram->end(drv);
00775 }
00776 }
00777
00778
00779
00780 void CMeshGeom::renderSkin(CTransformShape *trans, float alphaMRM)
00781 {
00782
00783 CMeshBaseInstance *mi= safe_cast<CMeshBaseInstance*>(trans);
00784
00785 CScene *ownerScene= mi->getScene();
00786
00787 CRenderTrav *renderTrav= ownerScene->getRenderTrav();
00788
00789 IDriver *drv= renderTrav->getDriver();
00790 nlassert(drv);
00791
00792
00793
00794 updateVertexBufferHard (drv);
00795
00796
00797
00798
00799 IVertexBufferHard *currentVBHard= _VertexBufferHard;
00800
00801
00802
00803 CSkeletonModel *skeleton;
00804 skeleton= mi->getSkeletonModel();
00805
00806 nlassert(_Skinned && mi->isSkinned() && skeleton);
00807 bool bMorphApplied = _MeshMorpher->BlendShapes.size() > 0;
00808 bool useTangentSpace = _MeshVertexProgram && _MeshVertexProgram->needTangentSpace();
00809
00810
00811
00812
00813 H_AUTO( NL3D_MeshGeom_RenderSkinned );
00814
00815
00816
00817
00818 if (bMorphApplied)
00819 {
00820
00821 _MeshMorpher->initSkinned(&_VBufferOri,
00822 &_VBuffer,
00823 currentVBHard,
00824 useTangentSpace,
00825 &_OriginalSkinVertices,
00826 &_OriginalSkinNormals,
00827 useTangentSpace ? &_OriginalTGSpace : NULL,
00828 true );
00829 _MeshMorpher->updateSkinned (mi->getBlendShapeFactors());
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 applySkin(skeleton);
00842
00843
00844
00845
00846
00847
00848 bool useMeshVP= _MeshVertexProgram != NULL;
00849 if( useMeshVP )
00850 {
00851 CMatrix invertedObjectMatrix;
00852 invertedObjectMatrix = skeleton->getWorldMatrix().inverted();
00853
00854 useMeshVP= _MeshVertexProgram->begin(drv, ownerScene, mi, invertedObjectMatrix, renderTrav->CamPos);
00855 }
00856
00857
00858
00859
00860
00861 if(currentVBHard != NULL)
00862 drv->activeVertexBufferHard(currentVBHard);
00863 else
00864 drv->activeVertexBuffer(_VBuffer);
00865
00866
00867
00868 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00869 {
00870 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00871 if(mBlock.RdrPass.size()==0)
00872 continue;
00873
00874
00875 for(uint i=0;i<mBlock.RdrPass.size();i++)
00876 {
00877 CRdrPass &rdrPass= mBlock.RdrPass[i];
00878
00879
00880 CMaterial &material=mi->Materials[rdrPass.MaterialId];
00881
00882
00883 if (useMeshVP)
00884 {
00885 if(currentVBHard)
00886 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, currentVBHard);
00887 else
00888 _MeshVertexProgram->setupForMaterial(material, drv, ownerScene, &_VBuffer);
00889 }
00890
00891
00892 drv->render(rdrPass.PBlock, material);
00893 }
00894 }
00895
00896
00897 if(useMeshVP)
00898 {
00899
00900 _MeshVertexProgram->end(drv);
00901 }
00902
00903 }
00904
00905
00906
00907 void CMeshGeom::renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat)
00908 {
00909 nlassert(drv);
00910
00911
00912 drv->setupModelMatrix(worldMatrix);
00913
00914
00915 drv->activeVertexBuffer(_VBuffer);
00916
00917
00918 for(uint mb=0;mb<_MatrixBlocks.size();mb++)
00919 {
00920 CMatrixBlock &mBlock= _MatrixBlocks[mb];
00921 if(mBlock.RdrPass.size()==0)
00922 continue;
00923
00924
00925 for(uint i=0;i<mBlock.RdrPass.size();i++)
00926 {
00927 CRdrPass &rdrPass= mBlock.RdrPass[i];
00928
00929
00930 drv->render(rdrPass.PBlock, mat);
00931 }
00932 }
00933
00934 }
00935
00936
00937
00938 void CMeshGeom::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00939 {
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 sint ver = f.serialVersion (4);
00953
00954
00955
00956 if( !f.isReading() && _Skinned && !_OriginalSkinRestored )
00957 {
00958 restoreOriginalSkinVertices();
00959 }
00960
00961
00962
00963 if (ver >= 4)
00964 {
00965 f.serialCont (_BonesName);
00966 }
00967
00968 if (f.isReading())
00969 {
00970
00971 _BoneIdComputed = (ver < 4);
00972
00973 _BoneIdExtended= false;
00974 }
00975 else
00976 {
00977
00978 nlassert (_BoneIdComputed==false);
00979 }
00980
00981
00982 if (ver >= 3)
00983 {
00984 IMeshVertexProgram *mvp= NULL;
00985 if(f.isReading())
00986 {
00987 f.serialPolyPtr(mvp);
00988 _MeshVertexProgram= mvp;
00989 }
00990 else
00991 {
00992 mvp= _MeshVertexProgram;
00993 f.serialPolyPtr(mvp);
00994 }
00995 }
00996 else if(f.isReading())
00997 {
00998
00999 _MeshVertexProgram= NULL;
01000 }
01001
01002
01003 if (ver >= 1)
01004 f.serial (*_MeshMorpher);
01005
01006
01007 f.serial (_VBuffer);
01008 f.serialCont (_MatrixBlocks);
01009 f.serial (_BBox);
01010 f.serial (_Skinned);
01011
01012
01013
01014 if(f.isReading())
01015 {
01016 _VertexBufferHardDirty = true;
01017
01018
01019 if(ver < 2 )
01020 {
01021 optimizeTriangleOrder();
01022 }
01023 }
01024
01025
01026
01027 if(ver < 4)
01028 buildBoneUsageVer3();
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043 if(f.isReading())
01044 compileRunTime();
01045 }
01046
01047
01048
01049 void CMeshGeom::compileRunTime()
01050 {
01051
01052 if(_Skinned)
01053 bkupOriginalSkinVertices();
01054
01055
01056 _PreciseClipping= _BBox.getRadius() >= NL3D_MESH_PRECISE_CLIP_THRESHOLD;
01057
01058
01059 _SupportMeshBlockRendering= !_Skinned && _MeshMorpher->BlendShapes.size()==0;
01060
01061
01062 _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MatrixBlocks.size()==1 && _MatrixBlocks[0].RdrPass.size()>0;
01063
01064
01065 _SupportMeshBlockRendering= _SupportMeshBlockRendering && _MeshVertexProgram==NULL;
01066
01067
01068
01069 }
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080 void CMeshGeom::buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp> &tmpFaces)
01081 {
01082 sint i,j,k;
01083 TBoneMap remainingBones;
01084 list<uint> remainingFaces;
01085
01086
01087
01088
01089 for(i=0;i<(sint)m.SkinWeights.size();i++)
01090 {
01091 CMesh::CSkinWeight &sw= m.SkinWeights[i];
01092
01093
01094 nlassert(sw.Weights[0]!=0);
01095
01096
01097 for(j=1;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01098 {
01099
01100 if(sw.Weights[j]==0)
01101 {
01102
01103 sw.MatrixId[j]= sw.MatrixId[0];
01104 }
01105 }
01106 }
01107
01108
01109
01110
01111 for(i=0;i<(sint)tmpFaces.size();i++)
01112 {
01113 CFaceTmp &face= tmpFaces[i];
01114
01115 for(j=0;j<3;j++)
01116 {
01117 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
01118 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01119 {
01120
01121
01122 remainingBones[sw.MatrixId[k]].RefCount++;
01123 }
01124 }
01125 }
01126
01127
01128
01129
01130 for(i=0;i<(sint)tmpFaces.size();i++)
01131 {
01132 remainingFaces.push_back(i);
01133 }
01134
01135
01136
01137
01138
01139
01140 vector<uint> boneUse;
01141 boneUse.reserve(NL3D_MESH_SKINNING_MAX_MATRIX*3);
01142
01143
01144 while(!remainingFaces.empty())
01145 {
01146
01147 _MatrixBlocks.push_back(CMatrixBlock());
01148 CMatrixBlock &matrixBlock= _MatrixBlocks[_MatrixBlocks.size()-1];
01149 matrixBlock.NumMatrix=0;
01150
01151
01152
01153 ItBoneMap itBone;
01154 for(itBone= remainingBones.begin();itBone!=remainingBones.end();itBone++)
01155 {
01156 itBone->second.Inserted= false;
01157 }
01158
01159
01160
01161
01162 while(!remainingBones.empty())
01163 {
01164
01165 uint currentBoneId= remainingBones.begin()->first;
01166
01167
01168 if(remainingBones.begin()->second.RefCount==0)
01169 {
01170 remainingBones.erase(remainingBones.begin());
01171 continue;
01172 }
01173
01174
01175 bool faceAdded= false;
01176
01177
01178 list<uint>::iterator itFace;
01179 for(itFace= remainingFaces.begin(); itFace!=remainingFaces.end();)
01180 {
01181 bool useCurrentBoneId;
01182 uint newBoneAdded;
01183
01184
01185
01186
01187
01188 tmpFaces[*itFace].buildBoneUse(boneUse, m.SkinWeights);
01189
01190
01191 useCurrentBoneId= false;
01192 for(i=0;i<(sint)boneUse.size();i++)
01193 {
01194
01195 if(boneUse[i]==currentBoneId)
01196 {
01197 useCurrentBoneId= true;
01198 break;
01199 }
01200 }
01201
01202 newBoneAdded=0;
01203 for(i=0;i<(sint)boneUse.size();i++)
01204 {
01205
01206 if(!remainingBones[boneUse[i]].Inserted)
01207 newBoneAdded++;
01208 }
01209
01210
01211
01212
01213
01214
01215
01216 if( newBoneAdded==0 ||
01217 (useCurrentBoneId && newBoneAdded+matrixBlock.NumMatrix < IDriver::MaxModelMatrix) )
01218 {
01219
01220
01221 CFaceTmp &face= tmpFaces[*itFace];
01222
01223
01224 for(j=0;j<3;j++)
01225 {
01226 CMesh::CSkinWeight &sw= m.SkinWeights[face.Corner[j].Vertex];
01227
01228
01229 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01230 {
01231
01232 uint boneId= sw.MatrixId[k];
01233
01234 CBoneTmp &bone= remainingBones[boneId];
01235
01236
01237 bone.RefCount--;
01238
01239
01240 if( !bone.Inserted )
01241 {
01242
01243 bone.Inserted= true;
01244
01245 bone.MatrixIdInMB= matrixBlock.NumMatrix;
01246
01247
01248 matrixBlock.MatrixId[matrixBlock.NumMatrix]= boneId;
01249
01250 matrixBlock.NumMatrix++;
01251 }
01252
01253
01254
01255 face.Corner[j].Palette.MatrixId[k]= bone.MatrixIdInMB;
01256
01257 face.Corner[j].Weights[k]= sw.Weights[k];
01258 }
01259 }
01260
01261
01262 face.MatrixBlockId= _MatrixBlocks.size()-1;
01263
01264
01265 itFace= remainingFaces.erase(itFace);
01266
01267
01268 faceAdded= true;
01269 }
01270 else
01271 {
01272
01273 itFace++;
01274 }
01275 }
01276
01277
01278
01279 if(!faceAdded)
01280 break;
01281 }
01282
01283 }
01284
01285
01286
01287
01288
01289
01290 vector<CMatrixBlockRemap> blockRemaps;
01291 blockRemaps.resize(_MatrixBlocks.size());
01292
01293
01294
01295 for(i=1;i<(sint)_MatrixBlocks.size();i++)
01296 {
01297 CMatrixBlock &mBlock= _MatrixBlocks[i];
01298 CMatrixBlock &mPrevBlock= _MatrixBlocks[i-1];
01299 CMatrixBlockRemap &remap= blockRemaps[i];
01300
01301
01302 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01303 {
01304 remap.Remap[j]= mBlock.MatrixId[j];
01305 }
01306
01307
01308 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01309 {
01310
01311 sint idLoc= mPrevBlock.getMatrixIdLocation(mBlock.MatrixId[j]);
01312
01313
01314 if(idLoc==-1 || idLoc>=(sint)mBlock.NumMatrix || idLoc==j)
01315 {
01316
01317 j++;
01318 }
01319 else
01320 {
01321
01322 swap(mBlock.MatrixId[j], mBlock.MatrixId[idLoc]);
01323
01324 }
01325 }
01326
01327
01328 for(j=0;j<(sint)mBlock.NumMatrix;j++)
01329 {
01330
01331 uint boneId= remap.Remap[j];
01332
01333 remap.Remap[j]= mBlock.getMatrixIdLocation(boneId);
01334 }
01335
01336
01337 }
01338
01339
01340
01341 for(i=0;i<(sint)tmpFaces.size();i++)
01342 {
01343 CFaceTmp &face= tmpFaces[i];
01344
01345 if(face.MatrixBlockId!=0)
01346 {
01347 CMatrixBlockRemap &remap= blockRemaps[face.MatrixBlockId];
01348
01349 for(j=0;j<3;j++)
01350 {
01351 for(k=0;k<NL3D_MESH_SKINNING_MAX_MATRIX;k++)
01352 {
01353 uint oldId= face.Corner[j].Palette.MatrixId[k];
01354 face.Corner[j].Palette.MatrixId[k]= (uint8)remap.Remap[oldId];
01355 }
01356 }
01357 }
01358 }
01359
01360 }
01361
01362
01363
01364 void CMeshGeom::CFaceTmp::buildBoneUse(vector<uint> &boneUse, vector<CMesh::CSkinWeight> &skinWeights)
01365 {
01366 boneUse.clear();
01367
01368
01369 for(sint i=0;i<3;i++)
01370 {
01371
01372 CMesh::CSkinWeight &sw= skinWeights[Corner[i].Vertex];
01373
01374
01375 for(sint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
01376 {
01377 uint boneId= sw.MatrixId[j];
01378
01379 if( find(boneUse.begin(), boneUse.end(), boneId)==boneUse.end() )
01380 boneUse.push_back(boneId);
01381 }
01382 }
01383
01384
01385 }
01386
01387
01388
01389
01390 sint CMeshGeom::CMatrixBlock::getMatrixIdLocation(uint32 boneId) const
01391 {
01392 for(uint i=0;i<NumMatrix;i++)
01393 {
01394 if(MatrixId[i]==boneId)
01395 return i;
01396 }
01397
01398
01399 return -1;
01400 }
01401
01402
01403
01404 float CMeshGeom::getNumTriangles (float distance)
01405 {
01406
01407 uint32 triCount=0;
01408
01409
01410 uint mbCount=_MatrixBlocks.size();
01411 for (uint mb=0; mb<mbCount; mb++)
01412 {
01413 CMatrixBlock &block=_MatrixBlocks[mb];
01414
01415
01416 uint pCount=block.RdrPass.size();
01417 for (uint pb=0; pb<pCount; pb++)
01418 {
01419
01420 CRdrPass &pass=block.RdrPass[pb];
01421
01422
01423 triCount+=pass.PBlock.getNumTriangles ();
01424 }
01425 }
01426 return (float)triCount;
01427 }
01428
01429
01430
01431 void CMeshGeom::computeBonesId (CSkeletonModel *skeleton)
01432 {
01433
01434 if (!_BoneIdComputed)
01435 {
01436
01437 nlassert (skeleton);
01438 if (skeleton)
01439 {
01440
01441 _BonesId.resize(_BonesName.size());
01442
01443
01444 uint matrixBlock;
01445 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01446 {
01447
01448 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01449
01450
01451 uint matrix;
01452 for (matrix=0; matrix<mb.NumMatrix; matrix++)
01453 {
01454
01455 nlassert (mb.MatrixId[matrix]<_BonesName.size());
01456 sint32 boneId = skeleton->getBoneIdByName (_BonesName[mb.MatrixId[matrix]]);
01457
01458
01459 _BonesId[mb.MatrixId[matrix]]= boneId;
01460
01461
01462 if (boneId != -1)
01463 {
01464
01465 mb.MatrixId[matrix] = (uint32)boneId;
01466 }
01467 else
01468 {
01469
01470 mb.MatrixId[matrix] = 0;
01471
01472
01473 nlwarning ("Bone %s not found in the skeleton.", _BonesName[mb.MatrixId[matrix]].c_str());
01474 }
01475 }
01476 }
01477
01478
01479 _BoneIdComputed = true;
01480 }
01481 }
01482
01483
01484 if (!_BoneIdExtended)
01485 {
01486 nlassert (skeleton);
01487 if (skeleton)
01488 {
01489
01490 vector<bool> boneUsage;
01491 boneUsage.resize(skeleton->Bones.size(), false);
01492
01493
01494 uint i;
01495 for(i=0; i<_BonesId.size(); i++)
01496 {
01497
01498 if(_BonesId[i]<0)
01499 continue;
01500
01501
01502 skeleton->flagBoneAndParents(_BonesId[i], boneUsage);
01503 }
01504
01505
01506 _BonesIdExt.clear();
01507 for(i=0; i<boneUsage.size();i++)
01508 {
01509
01510 if(boneUsage[i])
01511 _BonesIdExt.push_back(i);
01512 }
01513
01514 }
01515
01516
01517 _BoneIdExtended= true;
01518 }
01519
01520 }
01521
01522
01523
01524 void CMeshGeom::buildBoneUsageVer3 ()
01525 {
01526 if(_Skinned)
01527 {
01528
01529 uint32 maxBoneId= 0;
01530
01531 uint matrixBlock;
01532 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01533 {
01534 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01535
01536 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01537 {
01538 maxBoneId= max(mb.MatrixId[matrix], maxBoneId);
01539 }
01540 }
01541
01542
01543 std::vector<uint8> boneUsage;
01544 boneUsage.resize(maxBoneId+1, 0);
01545
01546
01547 for (matrixBlock=0; matrixBlock<_MatrixBlocks.size(); matrixBlock++)
01548 {
01549 CMatrixBlock &mb = _MatrixBlocks[matrixBlock];
01550
01551 for (uint matrix=0; matrix<mb.NumMatrix; matrix++)
01552 {
01553
01554 boneUsage[mb.MatrixId[matrix]]= 1;
01555 }
01556 }
01557
01558
01559 _BonesId.clear();
01560 for(uint i=0; i<boneUsage.size();i++)
01561 {
01562
01563 if(boneUsage[i])
01564 _BonesId.push_back(i);
01565 }
01566 }
01567 }
01568
01569
01570
01571 void CMeshGeom::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
01572 {
01573
01574 for(uint i=0; i<_BonesIdExt.size();i++)
01575 {
01576 uint boneId= _BonesIdExt[i];
01577
01578 if(boneId>=sm->Bones.size())
01579 nlerror(" Skin is incompatible with Skeleton: tries to use bone %d", boneId);
01580
01581 if(increment)
01582 sm->incBoneUsage(boneId, CSkeletonModel::UsageNormal);
01583 else
01584 sm->decBoneUsage(boneId, CSkeletonModel::UsageNormal);
01585 }
01586 }
01587
01588
01589
01590 void CMeshGeom::bkupOriginalSkinVertices()
01591 {
01592 nlassert(_Skinned);
01593
01594
01595 contReset(_OriginalSkinVertices);
01596 contReset(_OriginalSkinNormals);
01597 contReset(_OriginalTGSpace);
01598
01599
01600 uint numVertices= _VBuffer.getNumVertices();
01601
01602
01603 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01604 {
01605
01606 _OriginalSkinVertices.resize(numVertices);
01607 for(uint i=0; i<numVertices;i++)
01608 {
01609 _OriginalSkinVertices[i]= *(CVector*)_VBuffer.getVertexCoordPointer(i);
01610 }
01611 }
01612 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01613 {
01614
01615 _OriginalSkinNormals.resize(numVertices);
01616 for(uint i=0; i<numVertices;i++)
01617 {
01618 _OriginalSkinNormals[i]= *(CVector*)_VBuffer.getNormalCoordPointer(i);
01619 }
01620 }
01621
01622
01623 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01624 {
01625
01626 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01627 uint tgSpaceStage = _VBuffer.getNumTexCoordUsed() - 1;
01628 _OriginalTGSpace.resize(numVertices);
01629 for(uint i=0; i<numVertices;i++)
01630 {
01631 _OriginalTGSpace[i]= *(CVector*)_VBuffer.getTexCoordPointer(i, tgSpaceStage);
01632 }
01633 }
01634 }
01635
01636
01637
01638 void CMeshGeom::restoreOriginalSkinVertices()
01639 {
01640 nlassert(_Skinned);
01641
01642
01643 uint numVertices= _VBuffer.getNumVertices();
01644
01645
01646 if(_VBuffer.getVertexFormat() & CVertexBuffer::PositionFlag)
01647 {
01648
01649 for(uint i=0; i<numVertices;i++)
01650 {
01651 *(CVector*)_VBuffer.getVertexCoordPointer(i)= _OriginalSkinVertices[i];
01652 }
01653 }
01654 if(_VBuffer.getVertexFormat() & CVertexBuffer::NormalFlag)
01655 {
01656
01657 for(uint i=0; i<numVertices;i++)
01658 {
01659 *(CVector*)_VBuffer.getNormalCoordPointer(i)= _OriginalSkinNormals[i];
01660 }
01661 }
01662 if (_MeshVertexProgram && _MeshVertexProgram->needTangentSpace())
01663 {
01664 uint numTexCoords = _VBuffer.getNumTexCoordUsed();
01665 nlassert(numTexCoords >= 2);
01666 nlassert(_OriginalTGSpace.size() == numVertices);
01667
01668 for(uint i = 0; i < numVertices; ++i)
01669 {
01670 *(CVector*)_VBuffer.getTexCoordPointer(i, numTexCoords - 1)= _OriginalTGSpace[i];
01671 }
01672 }
01673
01674
01675 _OriginalSkinRestored= true;
01676 }
01677
01678
01679
01680
01681 #define NL3D_SOFTSKIN_VNEEDCOMPUTE 3
01682 #define NL3D_SOFTSKIN_VMUSTCOMPUTE 1
01683 #define NL3D_SOFTSKIN_VCOMPUTED 0
01684
01685
01686
01687
01688
01689
01690 void CMeshGeom::applySkin(CSkeletonModel *skeleton)
01691 {
01692
01693
01694 if(_OriginalSkinVertices.empty())
01695 return;
01696
01697
01698 TSkinType skinType;
01699 if( _OriginalSkinNormals.empty() )
01700 skinType= SkinPosOnly;
01701 else if( _OriginalTGSpace.empty() )
01702 skinType= SkinWithNormal;
01703 else
01704 skinType= SkinWithTgSpace;
01705
01706
01707 uint numVertices= _OriginalSkinVertices.size();
01708 uint dstStride= _VBuffer.getVertexSize();
01709
01710 uint tgSpaceStage = 0;
01711 if( skinType>= SkinWithTgSpace)
01712 {
01713 nlassert(_VBuffer.getNumTexCoordUsed() > 0);
01714 tgSpaceStage= _VBuffer.getNumTexCoordUsed() - 1;
01715 }
01716
01717
01718 static vector<uint8> skinFlags;
01719 skinFlags.resize(numVertices);
01720
01721 memset(&skinFlags[0], NL3D_SOFTSKIN_VNEEDCOMPUTE, numVertices );
01722
01723
01724
01725
01726 for(uint mb= 0; mb<_MatrixBlocks.size();mb++)
01727 {
01728
01729 static CMatrix3x4 matrixes[IDriver::MaxModelMatrix];
01730 computeSkinMatrixes(skeleton, matrixes, mb==0?NULL:&_MatrixBlocks[mb-1], _MatrixBlocks[mb]);
01731
01732
01733 flagSkinVerticesForMatrixBlock(&skinFlags[0], _MatrixBlocks[mb]);
01734
01735
01736 uint8 *pFlag= &skinFlags[0];
01737 CVector *srcVector= &_OriginalSkinVertices[0];
01738 uint8 *srcPal= (uint8*)_VBuffer.getPaletteSkinPointer(0);
01739 uint8 *srcWgt= (uint8*)_VBuffer.getWeightPointer(0);
01740 uint8 *dstVector= (uint8*)_VBuffer.getVertexCoordPointer(0);
01741
01742 CVector *srcNormal= NULL;
01743 uint8 *dstNormal= NULL;
01744 if(skinType>=SkinWithNormal)
01745 {
01746 srcNormal= &_OriginalSkinNormals[0];
01747 dstNormal= (uint8*)_VBuffer.getNormalCoordPointer(0);
01748 }
01749
01750 CVector *srcTgSpace= NULL;
01751 uint8 *dstTgSpace= NULL;
01752 if(skinType>=SkinWithTgSpace)
01753 {
01754 srcTgSpace= &_OriginalTGSpace[0];
01755 dstTgSpace= (uint8*)_VBuffer.getTexCoordPointer(0, tgSpaceStage);
01756 }
01757
01758
01759
01760 uint size= numVertices;
01761 for(;size>0;size--)
01762 {
01763
01764 if(*pFlag==NL3D_SOFTSKIN_VMUSTCOMPUTE)
01765 {
01766
01767 *pFlag=NL3D_SOFTSKIN_VCOMPUTED;
01768
01769 CPaletteSkin *psPal= (CPaletteSkin*)srcPal;
01770
01771
01772 nlassert(psPal->MatrixId[0]<IDriver::MaxModelMatrix);
01773 nlassert(psPal->MatrixId[1]<IDriver::MaxModelMatrix);
01774 nlassert(psPal->MatrixId[2]<IDriver::MaxModelMatrix);
01775 nlassert(psPal->MatrixId[3]<IDriver::MaxModelMatrix);
01776
01777
01778 computeSoftwarePointSkinning(matrixes, srcVector, psPal, (float*)srcWgt, (CVector*)dstVector);
01779
01780
01781 if(skinType>=SkinWithNormal)
01782 computeSoftwareVectorSkinning(matrixes, srcNormal, psPal, (float*)srcWgt, (CVector*)dstNormal);
01783
01784
01785 if(skinType>=SkinWithTgSpace)
01786 computeSoftwareVectorSkinning(matrixes, srcTgSpace, psPal, (float*)srcWgt, (CVector*)dstTgSpace);
01787 }
01788
01789
01790 pFlag++;
01791
01792 srcVector++;
01793 srcNormal++;
01794 srcTgSpace++;
01795
01796 srcPal+= dstStride;
01797 srcWgt+= dstStride;
01798 dstVector+= dstStride;
01799 dstNormal+= dstStride;
01800 dstTgSpace+= dstStride;
01801 }
01802 }
01803
01804
01805
01806 _OriginalSkinRestored= false;
01807 }
01808
01809
01810
01811 void CMeshGeom::flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb)
01812 {
01813 for(uint i=0; i<mb.RdrPass.size(); i++)
01814 {
01815 CPrimitiveBlock &PB= mb.RdrPass[i].PBlock;
01816
01817 uint32 *pIndex;
01818 uint nIndex;
01819
01820
01821
01822
01823
01824
01825
01826 pIndex= (uint32*)PB.getLinePointer();
01827 nIndex= PB.getNumLine()*2;
01828 for(;nIndex>0;nIndex--, pIndex++)
01829 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01830
01831 pIndex= (uint32*)PB.getTriPointer();
01832 nIndex= PB.getNumTri()*3;
01833 for(;nIndex>0;nIndex--, pIndex++)
01834 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01835
01836 pIndex= (uint32*)PB.getQuadPointer();
01837 nIndex= PB.getNumQuad()*4;
01838 for(;nIndex>0;nIndex--, pIndex++)
01839 skinFlags[*pIndex]&= NL3D_SOFTSKIN_VMUSTCOMPUTE;
01840 }
01841 }
01842
01843
01844
01845 void CMeshGeom::computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01846 {
01847 CMatrix3x4 *pMat;
01848
01849
01850
01851
01852 pMat= matrixes + srcPal->MatrixId[0];
01853 pMat->mulSetPoint(*srcVec, srcWgt[0], *pDst);
01854
01855 pMat= matrixes + srcPal->MatrixId[1];
01856 pMat->mulAddPoint(*srcVec, srcWgt[1], *pDst);
01857
01858 pMat= matrixes + srcPal->MatrixId[2];
01859 pMat->mulAddPoint(*srcVec, srcWgt[2], *pDst);
01860
01861 pMat= matrixes + srcPal->MatrixId[3];
01862 pMat->mulAddPoint(*srcVec, srcWgt[3], *pDst);
01863 }
01864
01865
01866
01867 void CMeshGeom::computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVec, CPaletteSkin *srcPal, float *srcWgt, CVector *pDst)
01868 {
01869 CMatrix3x4 *pMat;
01870
01871
01872
01873
01874 pMat= matrixes + srcPal->MatrixId[0];
01875 pMat->mulSetVector(*srcVec, srcWgt[0], *pDst);
01876
01877 pMat= matrixes + srcPal->MatrixId[1];
01878 pMat->mulAddVector(*srcVec, srcWgt[1], *pDst);
01879
01880 pMat= matrixes + srcPal->MatrixId[2];
01881 pMat->mulAddVector(*srcVec, srcWgt[2], *pDst);
01882
01883 pMat= matrixes + srcPal->MatrixId[3];
01884 pMat->mulAddVector(*srcVec, srcWgt[3], *pDst);
01885 }
01886
01887
01888
01889 void CMeshGeom::computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock *prevBlock, CMatrixBlock &mBlock)
01890 {
01891
01892 for(uint idMat=0;idMat<mBlock.NumMatrix;idMat++)
01893 {
01894 uint curBoneId= mBlock.MatrixId[idMat];
01895
01896
01897 if(prevBlock && idMat<prevBlock->NumMatrix && prevBlock->MatrixId[idMat]== curBoneId)
01898 continue;
01899
01900
01901 matrixes[idMat].set(skeleton->getActiveBoneSkinMatrix(curBoneId));
01902 }
01903 }
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 bool CMeshGeom::supportMeshBlockRendering () const
01915 {
01916 return _SupportMeshBlockRendering;
01917 }
01918
01919
01920 bool CMeshGeom::sortPerMaterial() const
01921 {
01922 return true;
01923 }
01924
01925 uint CMeshGeom::getNumRdrPasses() const
01926 {
01927 return _MatrixBlocks[0].RdrPass.size();
01928 }
01929
01930 void CMeshGeom::beginMesh(CMeshGeomRenderContext &rdrCtx)
01931 {
01932 if(rdrCtx.RenderThroughVBHeap)
01933 {
01934
01935 }
01936 else
01937 {
01938
01939 updateVertexBufferHard ( rdrCtx.Driver );
01940
01941
01942
01943 if(_VertexBufferHard != NULL)
01944 {
01945
01946 rdrCtx.Driver->activeVertexBufferHard(_VertexBufferHard);
01947 }
01948 else
01949 {
01950
01951 rdrCtx.Driver->activeVertexBuffer(_VBuffer);
01952 }
01953 }
01954 }
01955
01956 void CMeshGeom::activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount)
01957 {
01958
01959 rdrCtx.Driver->setupModelMatrix(inst->getWorldMatrix());
01960
01961
01962 inst->changeLightSetup(rdrCtx.RenderTrav);
01963
01964
01965 }
01966
01967 void CMeshGeom::renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *mi, float polygonCount, uint rdrPassId)
01968 {
01969 CMatrixBlock &mBlock= _MatrixBlocks[0];
01970
01971 CRdrPass &rdrPass= mBlock.RdrPass[rdrPassId];
01972
01973 if( ( (mi->Materials[rdrPass.MaterialId].getBlend() == false) ) )
01974 {
01975
01976
01977 if(rdrCtx.RenderThroughVBHeap)
01978
01979 rdrCtx.Driver->render(rdrPass.VBHeapPBlock, mi->Materials[rdrPass.MaterialId]);
01980 else
01981
01982 rdrCtx.Driver->render(rdrPass.PBlock, mi->Materials[rdrPass.MaterialId]);
01983 }
01984 }
01985
01986 void CMeshGeom::endMesh(CMeshGeomRenderContext &rdrCtx)
01987 {
01988
01989
01990 }
01991
01992
01993 bool CMeshGeom::getVBHeapInfo(uint &vertexFormat, uint &numVertices)
01994 {
01995
01996 vertexFormat= _VBuffer.getVertexFormat();
01997 numVertices= _VBuffer.getNumVertices();
01998 return _SupportMeshBlockRendering;
01999 }
02000
02001
02002 void CMeshGeom::computeMeshVBHeap(void *dst, uint indexStart)
02003 {
02004
02005 memcpy(dst, _VBuffer.getVertexCoordPointer(), _VBuffer.getNumVertices()*_VBuffer.getVertexSize() );
02006
02007
02008 nlassert(_MatrixBlocks.size()==1);
02009 CMatrixBlock &mBlock= _MatrixBlocks[0];
02010
02011 for(uint i=0;i<mBlock.RdrPass.size();i++)
02012 {
02013
02014 CPrimitiveBlock &srcPb= mBlock.RdrPass[i].PBlock;
02015 CPrimitiveBlock &dstPb= mBlock.RdrPass[i].VBHeapPBlock;
02016 uint j;
02017
02018
02019 dstPb.setNumLine(srcPb.getNumLine());
02020 uint32 *srcLinePtr= srcPb.getLinePointer();
02021 uint32 *dstLinePtr= dstPb.getLinePointer();
02022 for(j=0; j<dstPb.getNumLine()*2;j++)
02023 {
02024 dstLinePtr[j]= srcLinePtr[j]+indexStart;
02025 }
02026
02027 dstPb.setNumTri(srcPb.getNumTri());
02028 uint32 *srcTriPtr= srcPb.getTriPointer();
02029 uint32 *dstTriPtr= dstPb.getTriPointer();
02030 for(j=0; j<dstPb.getNumTri()*3;j++)
02031 {
02032 dstTriPtr[j]= srcTriPtr[j]+indexStart;
02033 }
02034
02035 dstPb.setNumQuad(srcPb.getNumQuad());
02036 uint32 *srcQuadPtr= srcPb.getQuadPointer();
02037 uint32 *dstQuadPtr= dstPb.getQuadPointer();
02038 for(j=0; j<dstPb.getNumQuad()*4;j++)
02039 {
02040 dstQuadPtr[j]= srcQuadPtr[j]+indexStart;
02041 }
02042 }
02043 }
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055 CMesh::CCorner::CCorner()
02056 {
02057 sint i;
02058 Vertex= 0;
02059 Normal= CVector::Null;
02060 for(i=0;i<CVertexBuffer::MaxStage;i++)
02061 {
02062 Uvws[i]= CUVW(0, 0, 0);
02063 }
02064 Color.set(255,255,255,255);
02065 Specular.set(0,0,0,0);
02066 }
02067
02068
02069
02070 void CMesh::CCorner::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02071 {
02072 nlassert(0);
02073 f.serial(Vertex);
02074 f.serial(Normal);
02075 for(int i=0;i<CVertexBuffer::MaxStage;++i) f.serial(Uvws[i]);
02076 f.serial(Color);
02077 f.serial(Specular);
02078 }
02079
02080
02081 void CMesh::CFace::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02082 {
02083 for(int i=0;i<3;++i)
02084 f.serial(Corner[i]);
02085 f.serial(MaterialId);
02086 f.serial(SmoothGroup);
02087 }
02088
02089
02090 void CMesh::CSkinWeight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02091 {
02092 for(int i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;++i)
02093 {
02094 f.serial(MatrixId[i]);
02095 f.serial(Weights[i]);
02096 }
02097 }
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118 CMesh::CMeshBuild::CMeshBuild()
02119 {
02120 for (uint k = 0; k < CVertexBuffer::MaxStage; ++k)
02121 {
02122 NumCoords[k] = 2;
02123 }
02124 }
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136 CMesh::CMesh()
02137 {
02138
02139 _MeshGeom= new CMeshGeom;
02140 }
02141
02142 CMesh::~CMesh()
02143 {
02144
02145 delete _MeshGeom;
02146 }
02147
02148
02149
02150 CMesh::CMesh(const CMesh &mesh)
02151 {
02152
02153 _MeshGeom= new CMeshGeom(*mesh._MeshGeom);
02154 }
02155
02156
02157
02158 CMesh &CMesh::operator=(const CMesh &mesh)
02159 {
02160
02161 (CMeshBase&)*this= (CMeshBase&)mesh;
02162
02163
02164 *_MeshGeom= *mesh._MeshGeom;
02165
02166
02167 return *this;
02168 }
02169
02170
02171
02172
02173 void CMesh::build (CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &m)
02174 {
02176 CMeshBase::buildMeshBase (mbase);
02177
02178
02179 _MeshGeom->build (m, mbase.Materials.size());
02180 }
02181
02182
02183
02184 void CMesh::optimizeMaterialUsage(std::vector<sint> &remap)
02185 {
02186
02187 vector<bool> materialUsed;
02188 materialUsed.resize(CMeshBase::_Materials.size(), false);
02189 for(uint mb=0;mb<getNbMatrixBlock();mb++)
02190 {
02191 for(uint rp=0;rp<getNbRdrPass(mb);rp++)
02192 {
02193 uint matId= getRdrPassMaterial(mb, rp);
02194
02195 materialUsed[matId]= true;
02196 }
02197 }
02198
02199
02200 CMeshBase::applyMaterialUsageOptim(materialUsed, remap);
02201
02202
02203 _MeshGeom->applyMaterialRemap(remap);
02204 }
02205
02206
02207
02208 void CMesh::setBlendShapes(std::vector<CBlendShape>&bs)
02209 {
02210 _MeshGeom->setBlendShapes (bs);
02211 }
02212
02213
02214 void CMesh::build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom)
02215 {
02217 CMeshBase::buildMeshBase(mbuild);
02218
02219
02220 *_MeshGeom= meshGeom;
02221 }
02222
02223
02224
02225 CTransformShape *CMesh::createInstance(CScene &scene)
02226 {
02227
02228
02229 CMeshInstance *mi= (CMeshInstance*)scene.createModel(NL3D::MeshInstanceId);
02230 mi->Shape= this;
02231
02232
02233
02234 CMeshBase::instanciateMeshBase(mi, &scene);
02235
02236
02237
02238 _MeshGeom->initInstance(mi);
02239
02240
02241 return mi;
02242 }
02243
02244
02245
02246 bool CMesh::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
02247 {
02248 return _MeshGeom->clip(pyramid, worldMatrix);
02249 }
02250
02251
02252
02253 void CMesh::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
02254 {
02255
02256 uint32 mask= (0-(uint32)passOpaque);
02257 uint32 rdrFlags;
02258
02259 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
02260 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
02261
02262 _MeshGeom->render(drv, trans, 0, rdrFlags, 1);
02263 }
02264
02265
02266
02267 void CMesh::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
02268 {
02269
02270
02271
02272
02273
02274
02275
02276 sint ver= f.serialVersion(6);
02277
02278
02279 if(ver<6)
02280 throw NLMISC::EStream(f, "Mesh in Stream is too old (Mesh version < 6)");
02281
02282
02283
02284 CMeshBase::serialMeshBase(f);
02285
02286
02287
02288 _MeshGeom->serial(f);
02289
02290 }
02291
02292
02293
02294 const NLMISC::CAABBoxExt& CMesh::getBoundingBox() const
02295 {
02296 return _MeshGeom->getBoundingBox();
02297 }
02298
02299 const CVertexBuffer &CMesh::getVertexBuffer() const
02300 {
02301 return _MeshGeom->getVertexBuffer() ;
02302 }
02303
02304 uint CMesh::getNbMatrixBlock() const
02305 {
02306 return _MeshGeom->getNbMatrixBlock();
02307 }
02308
02309 uint CMesh::getNbRdrPass(uint matrixBlockIndex) const
02310 {
02311 return _MeshGeom->getNbRdrPass(matrixBlockIndex) ;
02312 }
02313
02314 const CPrimitiveBlock &CMesh::getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
02315 {
02316 return _MeshGeom->getRdrPassPrimitiveBlock(matrixBlockIndex, renderingPassIndex) ;
02317 }
02318
02319 uint32 CMesh::getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
02320 {
02321 return _MeshGeom->getRdrPassMaterial(matrixBlockIndex, renderingPassIndex) ;
02322 }
02323
02324 float CMesh::getNumTriangles (float distance)
02325 {
02326
02327 return 0;
02328 }
02329
02330 const CMeshGeom& CMesh::getMeshGeom () const
02331 {
02332 return *_MeshGeom;
02333 }
02334
02335 void CMesh::computeBonesId (CSkeletonModel *skeleton)
02336 {
02337 nlassert (_MeshGeom);
02338 _MeshGeom->computeBonesId (skeleton);
02339 }
02340
02341
02342
02343 void CMesh::updateSkeletonUsage(CSkeletonModel *sm, bool increment)
02344 {
02345 nlassert (_MeshGeom);
02346 _MeshGeom->updateSkeletonUsage(sm, increment);
02347 }
02348
02349
02350 IMeshGeom *CMesh::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
02351 {
02352
02353 if(_MeshGeom->supportMeshBlockRendering())
02354 {
02355 polygonCount= 0;
02356 return _MeshGeom;
02357 }
02358 else
02359 return NULL;
02360 }
02361
02362
02363 }
02364
02365
02366