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