00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/mesh_multi_lod.h"
00029 #include "3d/mesh_multi_lod_instance.h"
00030 #include "3d/mesh_instance.h"
00031 #include "3d/mesh_mrm.h"
00032 #include "3d/scene.h"
00033 #include "3d/coarse_mesh_manager.h"
00034 #include "3d/skeleton_model.h"
00035 #include "3d/fast_floor.h"
00036 #include "3d/mesh_blender.h"
00037
00038 #include "nel/misc/debug.h"
00039
00040 using namespace NLMISC;
00041
00042 namespace NL3D
00043 {
00044
00045
00046
00047
00048
00049
00050 void CMeshMultiLod::build(CMeshMultiLodBuild &mbuild)
00051 {
00052
00053 clear ();
00054
00055
00056 CMeshBase::buildMeshBase (mbuild.BaseMesh);
00057
00058
00059 _StaticLod=mbuild.StaticLod;
00060
00061
00062 _MeshVector.resize (mbuild.LodMeshes.size());
00063
00064
00065 uint coarse=0;
00066
00067
00068 for (uint slot=0; slot<mbuild.LodMeshes.size(); slot++)
00069 {
00070
00071 _MeshVector[slot].DistMax=mbuild.LodMeshes[slot].DistMax;
00072
00073
00074 _MeshVector[slot].BlendLength=mbuild.LodMeshes[slot].BlendLength;
00075
00076
00077 _MeshVector[slot].Flags=0;
00078
00079
00080 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::BlendIn)
00081 _MeshVector[slot].Flags|=CMeshSlot::BlendIn;
00082
00083
00084 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::BlendOut)
00085 _MeshVector[slot].Flags|=CMeshSlot::BlendOut;
00086
00087
00088 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::CoarseMesh)
00089 {
00090
00091 nlassert (coarse<=1);
00092
00093
00094 _MeshVector[slot].Flags|=CMeshSlot::CoarseMesh;
00095
00096
00097 if (coarse==1)
00098 _MeshVector[slot].Flags|=CMeshSlot::CoarseMeshId;
00099
00100
00101 coarse++;
00102 }
00103
00104
00105 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::IsOpaque)
00106 _MeshVector[slot].Flags|=CMeshSlot::IsOpaque;
00107
00108
00109 if (mbuild.LodMeshes[slot].Flags & CMeshMultiLodBuild::CBuildSlot::IsTransparent)
00110 _MeshVector[slot].Flags|=CMeshSlot::IsTransparent;
00111
00112
00113 nlassert (mbuild.LodMeshes[slot].MeshGeom);
00114
00115
00116 if (_MeshVector[slot].Flags&CMeshSlot::CoarseMesh)
00117 {
00118
00119 if (dynamic_cast<CMeshGeom*>(mbuild.LodMeshes[slot].MeshGeom)==NULL)
00120 {
00121
00122 _MeshVector[slot].MeshGeom = NULL;
00123 delete mbuild.LodMeshes[slot].MeshGeom;
00124 }
00125 else
00126
00127 _MeshVector[slot].MeshGeom = mbuild.LodMeshes[slot].MeshGeom;
00128 }
00129 else
00130
00131 _MeshVector[slot].MeshGeom = mbuild.LodMeshes[slot].MeshGeom;
00132 }
00133
00134
00135 for (int i=mbuild.LodMeshes.size()-1; i>0; i--)
00136 for (int j=0; j<i; j++)
00137 {
00138
00139 if (_MeshVector[j].DistMax>_MeshVector[j+1].DistMax)
00140 {
00141
00142 CMeshSlot tmp=_MeshVector[j];
00143 _MeshVector[j]=_MeshVector[j+1];
00144 _MeshVector[j+1]=tmp;
00145 tmp.MeshGeom=NULL;
00146 }
00147 }
00148
00149
00150 for (uint k=0; k<mbuild.LodMeshes.size(); k++)
00151 {
00152
00153 float startDist;
00154 if (k==0)
00155 startDist=0;
00156 else
00157 startDist=_MeshVector[k-1].DistMax;
00158
00159
00160 float startPolyCount;
00161 startPolyCount=_MeshVector[k].MeshGeom->getNumTriangles (startDist);
00162
00163
00164 float endDist=_MeshVector[k].DistMax;
00165
00166
00167 if (k==mbuild.LodMeshes.size()-1)
00168 {
00169 _MeshVector[k].EndPolygonCount=_MeshVector[k].MeshGeom->getNumTriangles (endDist);
00170 if (startPolyCount==_MeshVector[k].EndPolygonCount)
00171 _MeshVector[k].EndPolygonCount=startPolyCount/2;
00172 }
00173 else
00174 _MeshVector[k].EndPolygonCount=_MeshVector[k+1].MeshGeom->getNumTriangles (endDist);
00175
00176
00177 if (endDist==startDist)
00178 _MeshVector[k].A=0;
00179 else
00180 _MeshVector[k].A=(_MeshVector[k].EndPolygonCount-startPolyCount)/(endDist-startDist);
00181
00182
00183 _MeshVector[k].B=_MeshVector[k].EndPolygonCount-_MeshVector[k].A*endDist;
00184 }
00185
00186
00187 compileDistMax();
00188 }
00189
00190
00191
00192 CTransformShape *CMeshMultiLod::createInstance(CScene &scene)
00193 {
00194
00195 CMeshMultiLodInstance *mi=(CMeshMultiLodInstance*)scene.createModel(NL3D::MeshMultiLodInstanceId);
00196 mi->Shape= this;
00197 mi->_LastLodMatrixDate[0]=0;
00198 mi->_LastLodMatrixDate[1]=0;
00199
00200
00201 CMeshBase::instanciateMeshBase(mi, &scene);
00202
00203
00204
00205 for(uint i=0; i<_MeshVector.size(); i++)
00206 {
00207 if(_MeshVector[i].MeshGeom)
00208 _MeshVector[i].MeshGeom->initInstance(mi);
00209 }
00210
00211
00212 return mi;
00213 }
00214
00215
00216
00217 bool CMeshMultiLod::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
00218 {
00219
00220 uint meshCount=_MeshVector.size();
00221 for (uint i=0; i<meshCount; i++)
00222 {
00223
00224 CMeshSlot &slot=_MeshVector[i];
00225
00226
00227 if (slot.MeshGeom)
00228 {
00229
00230 return slot.MeshGeom->clip (pyramid, worldMatrix);
00231 }
00232 }
00233 return true;
00234 }
00235
00236
00237
00238 void CMeshMultiLod::render(IDriver *drv, CTransformShape *trans, bool passOpaque)
00239 {
00240
00241 CMeshMultiLodInstance *instance=safe_cast<CMeshMultiLodInstance*>(trans);
00242
00243
00244 CCoarseMeshManager *manager;
00245 if (_StaticLod)
00246 {
00247
00248 manager=instance->getScene()->getStaticCoarseMeshManager();
00249 }
00250 else
00251 {
00252
00253 manager=instance->getScene()->getDynamicCoarseMeshManager();
00254 }
00255
00256
00257
00258
00259 if ( (instance->Lod1!=0xffffffff) && (passOpaque==false) )
00260 {
00261
00262
00263 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
00264 IMeshGeom::RenderGlobalAlpha | IMeshGeom::RenderGADisableZWrite;
00265
00266 renderMeshGeom (instance->Lod1, drv, instance, instance->PolygonCountLod1, rdrFlags, 1.f-instance->BlendFactor, manager);
00267 }
00268
00269
00270
00271 if ( (instance->Flags&CMeshMultiLodInstance::Lod0Blend) == 0)
00272 {
00273
00274 if ( _MeshVector[instance->Lod0].Flags&CMeshSlot::CoarseMesh )
00275 {
00276
00277 if(passOpaque)
00278 renderCoarseMesh (instance->Lod0, drv, instance, manager);
00279 }
00280 else
00281 {
00282
00283 uint32 mask= (0-(uint32)passOpaque);
00284 uint32 rdrFlags;
00285
00286 rdrFlags= mask & (IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderPassOpaque);
00287 rdrFlags|= ~mask & (IMeshGeom::RenderTransparentMaterial);
00288
00289 renderMeshGeom (instance->Lod0, drv, instance, instance->PolygonCountLod0, rdrFlags, 1, manager);
00290 }
00291 }
00292 else
00293 {
00294
00295 nlassert (passOpaque==false);
00296
00297
00298
00299 uint32 rdrFlags= IMeshGeom::RenderOpaqueMaterial | IMeshGeom::RenderTransparentMaterial |
00300 IMeshGeom::RenderGlobalAlpha;
00301
00302
00303 renderMeshGeom (instance->Lod0, drv, instance, instance->PolygonCountLod0, rdrFlags, instance->BlendFactor, manager);
00304 }
00305
00306
00307
00308 if (manager)
00309 {
00310 uint meshCount=_MeshVector.size();
00311 for (uint j=0; j<meshCount; j++)
00312 {
00313
00314 if ( _MeshVector[j].Flags&CMeshSlot::CoarseMesh )
00315 {
00316
00317 bool alphaTrans= instance->Flags&CMeshMultiLodInstance::Lod0Blend;
00318
00319
00320 if ( alphaTrans || (j!=instance->Lod0) )
00321 {
00322
00323 uint coarseId=(_MeshVector[j].Flags&CMeshSlot::CoarseMeshId)?1:0;
00324 uint flag=CMeshMultiLodInstance::Coarse0Loaded<<coarseId;
00325
00326
00327 if ( instance->Flags&flag )
00328 {
00329
00330
00331
00332 manager->removeMesh (instance->CoarseMeshId[coarseId]);
00333
00334
00335 instance->Flags&=~flag;
00336 }
00337 }
00338 }
00339 }
00340 }
00341 }
00342
00343
00344
00345 void CMeshMultiLod::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00346 {
00347
00348 (void)f.serialVersion (0);
00349
00350
00351 CMeshBase::serialMeshBase(f);
00352
00353
00354 f.serial (_StaticLod);
00355
00356
00357 f.serialCont (_MeshVector);
00358
00359
00360
00361 if (f.isReading())
00362 {
00363 compileDistMax();
00364 }
00365 }
00366
00367
00368
00369 float CMeshMultiLod::getNumTriangles (float distance)
00370 {
00371
00372 uint meshCount=_MeshVector.size();
00373
00374
00375 if (meshCount>0)
00376 {
00377 uint i=0;
00378
00379
00380 while ( _MeshVector[i].DistMax<distance )
00381 {
00382 if (i==meshCount-1)
00383
00384 break;
00385 i++;
00386 }
00387
00388
00389 CMeshSlot &slot=_MeshVector[i];
00390
00391
00392 if (slot.MeshGeom)
00393 {
00394
00395 float polyCount=slot.A * distance + slot.B;
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 return polyCount;
00415 }
00416 }
00417
00418 return 0;
00419 }
00420
00421
00422
00423 void CMeshMultiLod::getAABBox(NLMISC::CAABBox &bbox) const
00424 {
00425
00426 uint count=_MeshVector.size();
00427 for (uint slot=0; slot<count; slot++)
00428 {
00429
00430 if (_MeshVector[slot].MeshGeom)
00431 {
00432
00433 bbox=_MeshVector[slot].MeshGeom->getBoundingBox().getAABBox();
00434
00435
00436 break;
00437 }
00438 }
00439 }
00440
00441
00442
00443 void CMeshMultiLod::clear ()
00444 {
00445 _MeshVector.clear ();
00446 }
00447
00448
00449
00450 void CMeshMultiLod::CMeshSlot::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00451 {
00452
00453 (void)f.serialVersion (0);
00454
00455 f.serialPolyPtr (MeshGeom);
00456 f.serial (A);
00457 f.serial (B);
00458 f.serial (DistMax);
00459 f.serial (EndPolygonCount);
00460 f.serial (BlendLength);
00461 f.serial (Flags);
00462
00463 if (f.isReading())
00464 {
00465 }
00466 }
00467
00468
00469
00470 CMeshMultiLod::CMeshSlot::CMeshSlot ()
00471 {
00472 MeshGeom=NULL;
00473 }
00474
00475
00476
00477 CMeshMultiLod::CMeshSlot::~CMeshSlot ()
00478 {
00479 if (MeshGeom)
00480 delete MeshGeom;
00481 }
00482
00483
00484
00485 void CMeshMultiLod::renderMeshGeom (uint slot, IDriver *drv, CMeshMultiLodInstance *trans, float numPoylgons, uint32 rdrFlags, float alpha, CCoarseMeshManager *manager)
00486 {
00487
00488 CMeshSlot &slotRef=_MeshVector[slot];
00489
00490
00491 if (slotRef.MeshGeom)
00492 {
00493
00494 if(slotRef.Flags&CMeshSlot::CoarseMesh)
00495 {
00496
00497 if(manager && (rdrFlags & IMeshGeom::RenderOpaqueMaterial) )
00498 {
00499 bool gaDisableZWrite= (rdrFlags & IMeshGeom::RenderGADisableZWrite)?true:false;
00500
00501
00502 CMaterial &material= manager->getMaterial();
00503
00504
00505
00506
00507 CRGBA newCol= trans->getCoarseMeshLighting();
00508
00509
00510 CMeshBlender blender;
00511 blender.prepareRenderForGlobalAlphaCoarseMesh(material, drv, newCol, alpha, gaDisableZWrite);
00512
00513
00514
00515 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
00516 meshGeom->renderSimpleWithMaterial(drv, trans->getWorldMatrix(), material);
00517
00518
00519
00520
00521
00522 blender.restoreRenderCoarseMesh(material, drv, gaDisableZWrite);
00523 }
00524 }
00525 else
00526 {
00527
00528
00529 slotRef.MeshGeom->render (drv, trans, numPoylgons, rdrFlags, alpha);
00530 }
00531 }
00532 }
00533
00534
00535 void CMeshMultiLod::renderCoarseMesh (uint slot, IDriver *drv, CMeshMultiLodInstance *trans, CCoarseMeshManager *manager)
00536 {
00537
00538 if(manager==NULL)
00539 return;
00540
00541
00542 CMeshSlot &slotRef=_MeshVector[slot];
00543
00544
00545 nlassert(slotRef.Flags&CMeshSlot::CoarseMesh);
00546
00547
00548 uint coarseId=(slotRef.Flags&CMeshSlot::CoarseMeshId)?1:0;
00549 uint maskFlag = CMeshMultiLodInstance::Coarse0Loaded<<coarseId;
00550
00551
00552 CMeshGeom *meshGeom= safe_cast<CMeshGeom*>(slotRef.MeshGeom);
00553
00554
00555 if ( (trans->Flags&maskFlag) == 0)
00556 {
00557
00558 trans->CoarseMeshId[coarseId]=manager->addMesh (*meshGeom);
00559
00560
00561 if (trans->CoarseMeshId[coarseId]!=CCoarseMeshManager::CantAddCoarseMesh)
00562
00563 trans->Flags|=maskFlag;
00564
00565
00566 trans->_LastLodMatrixDate[coarseId]=0;
00567
00568 trans->_LastLodLightingDate[coarseId]= -0x100;
00569 }
00570
00571
00572 if (trans->Flags&maskFlag)
00573 {
00574
00575 if ( trans->ITransformable::compareMatrixDate (trans->_LastLodMatrixDate[coarseId]) )
00576 {
00577
00578 trans->_LastLodMatrixDate[coarseId] = trans->ITransformable::getMatrixDate();
00579
00580
00581 manager->setMatrixMesh ( trans->CoarseMeshId[coarseId], *meshGeom, trans->getMatrix() );
00582 }
00583
00584
00585 CScene *scene= trans->getScene();
00586 if(scene)
00587 {
00588 sint64 currentDate= scene->getHrcTrav()->CurrentDate;
00589 if( trans->_LastLodLightingDate[coarseId] < currentDate - scene->getCoarseMeshLightingUpdate() )
00590 {
00591
00592 trans->_LastLodLightingDate[coarseId]= currentDate;
00593
00594
00595 CRGBA sunContrib= trans->getCoarseMeshLighting();
00596
00597
00598 manager->setColorMesh ( trans->CoarseMeshId[coarseId], *meshGeom, sunContrib );
00599 }
00600 }
00601 }
00602 }
00603
00604
00605 void CMeshMultiLod::compileDistMax()
00606 {
00607
00608 std::vector<CMeshSlot>::const_iterator ite=_MeshVector.end();
00609 ite--;
00610 if (ite!=_MeshVector.end())
00611 IShape::_DistMax= ite->DistMax;
00612 else
00613 IShape::_DistMax= -1;
00614 }
00615
00616
00617 const IMeshGeom& CMeshMultiLod::getMeshGeom (uint slot) const
00618 {
00619
00620 nlassert (slot<getNumSlotMesh ());
00621
00622 return *_MeshVector[slot].MeshGeom;
00623 }
00624
00625
00626
00627 void CMeshMultiLod::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
00628 {
00629
00630 if(getNumSlotMesh ()==0)
00631 return;
00632
00633
00634 if(_MeshVector[0].MeshGeom==NULL)
00635 return;
00636
00637
00638 CMeshMRMGeom *mgeom= dynamic_cast<CMeshMRMGeom*>(_MeshVector[0].MeshGeom);
00639 if(mgeom==NULL)
00640 return;
00641
00642
00643 mgeom->changeMRMDistanceSetup(distanceFinest, distanceMiddle, distanceCoarsest);
00644 }
00645
00646
00647
00648 IMeshGeom *CMeshMultiLod::supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const
00649 {
00650 IMeshGeom *ret= NULL;
00651
00652
00653 CMeshMultiLodInstance *instance=safe_cast<CMeshMultiLodInstance*>(trans);
00654
00655
00656 if ( (instance->Flags&CMeshMultiLodInstance::Lod0Blend) == 0)
00657 {
00658 uint slot= instance->Lod0;
00659
00660 if ( (_MeshVector[slot].Flags&CMeshSlot::CoarseMesh)==0 )
00661 {
00662
00663 ret= _MeshVector[slot].MeshGeom;
00664 }
00665 }
00666
00667
00668 if( ret && ret->supportMeshBlockRendering() )
00669 {
00670 polygonCount= instance->PolygonCountLod0;
00671 return ret;
00672 }
00673 else
00674 return NULL;
00675 }
00676
00677
00678 }