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