00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "nel/misc/hierarchical_timer.h"
00029 #include "3d/skeleton_model.h"
00030 #include "3d/hrc_trav.h"
00031 #include "3d/clip_trav.h"
00032 #include "3d/anim_detail_trav.h"
00033 #include "3d/render_trav.h"
00034 #include "3d/skeleton_shape.h"
00035 #include "3d/scene.h"
00036 #include "3d/lod_character_manager.h"
00037 #include "3d/lod_character_shape.h"
00038 #include "3d/skip_model.h"
00039 #include "nel/misc/rgba.h"
00040 #include "nel/misc/aabbox.h"
00041 #include "3d/mesh_skin_manager.h"
00042 #include "3d/mesh_base_instance.h"
00043 #include "3d/async_texture_manager.h"
00044
00045
00046
00047 using namespace std;
00048 using namespace NLMISC;
00049
00050 namespace NL3D
00051 {
00052
00053
00054
00055 void CSkeletonModel::registerBasic()
00056 {
00057 CMOT::registerModel(SkeletonModelId, TransformShapeId, CSkeletonModel::creator);
00058 CMOT::registerObs(AnimDetailTravId, SkeletonModelId, CSkeletonModelAnimDetailObs::creator);
00059 CMOT::registerObs(RenderTravId, SkeletonModelId, CSkeletonModelRenderObs::creator);
00060 }
00061
00062
00063
00064 void CSkeletonModel::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
00065 {
00066 CTransformShape::registerToChannelMixer(chanMixer, prefix);
00067
00068
00069 for(uint i=0;i<Bones.size();i++)
00070 {
00071
00072 Bones[i].registerToChannelMixer(chanMixer, prefix + Bones[i].getBoneName() + ".");
00073 }
00074
00075 }
00076
00077
00078 CSkeletonModel::CSkeletonModel()
00079 {
00080 IAnimatable::resize(AnimValueLast);
00081 HrcTrav= NULL;
00082 ClipTrav= NULL;
00083 _DisplayedAsLodCharacter= false;
00084 _LodCharacterDistance= 0;
00085 _OOLodCharacterDistance= 0;
00086
00087 _DefaultMRMSetup= true;
00088
00089 _SkinToRenderDirty= false;
00090
00091 _CLodVertexColorDirty= true;
00092
00093
00094 CTransform::setIsSkeleton(true);
00095
00096
00097
00098 setOpacity(true);
00099 setTransparency(false);
00100
00101
00102 CTransform::setIsForceAnimDetail(true);
00103
00104
00105 CTransform::setIsLoadbalancable(true);
00106
00107
00108 CTransform::setIsLightable(true);
00109
00110
00111 CTransform::setIsRenderable(true);
00112
00113
00114 buildDefaultLevelDetail();
00115 }
00116
00117
00118
00119 CSkeletonModel::~CSkeletonModel()
00120 {
00121
00122 if(ClipTrav)
00123 {
00124
00125 ClipTrav->Scene->eraseSkeletonModelToList(_ItSkeletonInScene);
00126 }
00127
00128
00129
00130 while(_Skins.begin()!=_Skins.end())
00131 {
00132 detachSkeletonSon(*_Skins.begin());
00133 }
00134
00135
00136 while(_StickedObjects.begin()!=_StickedObjects.end())
00137 {
00138 detachSkeletonSon(*_StickedObjects.begin());
00139 }
00140
00141
00142 setLodCharacterShape(-1);
00143
00144 }
00145
00146
00147
00148 void CSkeletonModel::initModel()
00149 {
00150 IObs *HrcObs= getObs(NL3D::HrcTravId);
00151 HrcTrav= (CHrcTrav*)HrcObs->Trav;
00152 IObs *ClipObs= getObs(NL3D::ClipTravId);
00153 ClipTrav= (CClipTrav*)ClipObs->Trav;
00154
00155
00156 _ItSkeletonInScene= ClipTrav->Scene->appendSkeletonModelToList(this);
00157
00158
00159 CTransformShape::initModel();
00160 }
00161
00162
00163
00164 void CSkeletonModel::initBoneUsages()
00165 {
00166
00167 _BoneUsage.resize(Bones.size());
00168 for(uint i=0; i<_BoneUsage.size(); i++)
00169 {
00170 _BoneUsage[i].Usage= 0;
00171 _BoneUsage[i].ForcedUsage= 0;
00172 _BoneUsage[i].CLodForcedUsage= 0;
00173 _BoneUsage[i].MustCompute= 0;
00174 _BoneUsage[i].ValidBoneSkinMatrix= 0;
00175 }
00176
00177 _BoneToCompute.reserve(Bones.size());
00178
00179 _BoneToComputeDirty= false;
00180 _CurLod= 0;
00181 _CurLodInterp= 1.f;
00182
00183 _LodInterpMultiplier= 1.f / 0.5f;
00184 }
00185
00186
00187
00188 void CSkeletonModel::incBoneUsage(uint i, TBoneUsageType boneUsageType)
00189 {
00190 nlassert(i<_BoneUsage.size());
00191
00192
00193 uint8 *usagePtr;
00194 if(boneUsageType == UsageNormal)
00195 usagePtr= &_BoneUsage[i].Usage;
00196 else if(boneUsageType == UsageForced)
00197 usagePtr= &_BoneUsage[i].ForcedUsage;
00198 else
00199 usagePtr= &_BoneUsage[i].CLodForcedUsage;
00200
00201
00202 if(*usagePtr==0)
00203 _BoneToComputeDirty= true;
00204
00205
00206 nlassert(*usagePtr<255);
00207 (*usagePtr)++;
00208 }
00209
00210
00211
00212 void CSkeletonModel::decBoneUsage(uint i, TBoneUsageType boneUsageType)
00213 {
00214 nlassert(i<_BoneUsage.size());
00215
00216
00217 uint8 *usagePtr;
00218 if(boneUsageType == UsageNormal)
00219 usagePtr= &_BoneUsage[i].Usage;
00220 else if(boneUsageType == UsageForced)
00221 usagePtr= &_BoneUsage[i].ForcedUsage;
00222 else
00223 usagePtr= &_BoneUsage[i].CLodForcedUsage;
00224
00225
00226 if(*usagePtr==1)
00227 _BoneToComputeDirty= true;
00228
00229
00230 nlassert(*usagePtr>0);
00231 (*usagePtr)--;
00232 }
00233
00234
00235
00236 void CSkeletonModel::flagBoneAndParents(uint32 boneId, std::vector<bool> &boneUsage) const
00237 {
00238 nlassert( boneUsage.size()==Bones.size() );
00239 nlassert( boneId<Bones.size() );
00240
00241
00242 boneUsage[boneId]= true;
00243
00244
00245 sint fatherId= Bones[boneId].getFatherId();
00246 if(fatherId>=0)
00247 flagBoneAndParents(fatherId, boneUsage);
00248 }
00249
00250
00251
00252 void CSkeletonModel::incForcedBoneUsageAndParents(uint i, bool forceCLod)
00253 {
00254
00255 incBoneUsage(i, forceCLod?UsageCLodForced:UsageForced );
00256
00257
00258 sint fatherId= Bones[i].getFatherId();
00259
00260 if(fatherId>=0)
00261 incForcedBoneUsageAndParents(fatherId, forceCLod);
00262 }
00263
00264
00265 void CSkeletonModel::decForcedBoneUsageAndParents(uint i, bool forceCLod)
00266 {
00267
00268 decBoneUsage(i, forceCLod?UsageCLodForced:UsageForced);
00269
00270
00271 sint fatherId= Bones[i].getFatherId();
00272
00273 if(fatherId>=0)
00274 decForcedBoneUsageAndParents(fatherId, forceCLod);
00275 }
00276
00277
00278
00279 void CSkeletonModel::updateBoneToCompute()
00280 {
00281
00282 if(!_BoneToComputeDirty)
00283 return;
00284
00285
00286 CChannelMixer *chanMixer= getChannelMixer();
00287
00288
00289 CSkeletonShape *skeShape= (CSkeletonShape*)(IShape*)Shape;
00290 const CSkeletonShape::CLod &lod= skeShape->getLod(_CurLod);
00291
00292
00293 _BoneToCompute.clear();
00294
00295
00296 for(uint i=0; i<_BoneUsage.size(); i++)
00297 {
00298
00299 if(isDisplayedAsLodCharacter())
00300
00301 _BoneUsage[i].MustCompute= 0;
00302 else
00303 {
00304
00305 _BoneUsage[i].MustCompute= (_BoneUsage[i].Usage & lod.ActiveBones[i]) | _BoneUsage[i].ForcedUsage;
00306 }
00307
00308 _BoneUsage[i].MustCompute|= _BoneUsage[i].CLodForcedUsage;
00309
00310
00311 if(_BoneUsage[i].MustCompute)
00312 {
00313
00314 if(chanMixer)
00315 Bones[i].lodEnableChannels(chanMixer, true);
00316
00317
00318 _BoneUsage[i].ValidBoneSkinMatrix= i;
00319
00320
00321
00322 CBoneCompute bc;
00323 bc.Bone= &Bones[i];
00324 sint fatherId= Bones[i].getFatherId();
00325
00326 if(fatherId==-1)
00327 bc.Father= NULL;
00328 else
00329 bc.Father= &Bones[fatherId];
00330
00331 bc.MustInterpolate= false;
00332 const CSkeletonShape::CLod *lodNext= NULL;
00333
00334 if( _CurLod < skeShape->getNumLods()-1 && _LodInterpMultiplier>0 )
00335 {
00336
00337 lodNext= &skeShape->getLod(_CurLod+1);
00338
00339
00340
00341 if(lodNext->ActiveBones[i]==0 && _BoneUsage[i].ForcedUsage==0 && _BoneUsage[i].CLodForcedUsage==0
00342 && bc.Father)
00343 bc.MustInterpolate= true;
00344 }
00345
00346 _BoneToCompute.push_back(bc);
00347 }
00348 else
00349 {
00350
00351 if(chanMixer)
00352 Bones[i].lodEnableChannels(chanMixer, false);
00353
00354
00355 sint fatherId= Bones[i].getFatherId();
00356 if(fatherId<0)
00357
00358 _BoneUsage[i].ValidBoneSkinMatrix= i;
00359 else
00360
00361 _BoneUsage[i].ValidBoneSkinMatrix= _BoneUsage[fatherId].ValidBoneSkinMatrix;
00362 }
00363 }
00364
00365
00366
00367
00368 _BoneToComputeDirty= false;
00369 }
00370
00371
00372
00373 bool CSkeletonModel::isBoneComputed(uint boneId) const
00374 {
00375 if(boneId>=_BoneUsage.size())
00376 return false;
00377 else
00378 return _BoneUsage[boneId].MustCompute!=0;
00379 }
00380
00381
00382
00383 const NLMISC::CMatrix &CSkeletonModel::getActiveBoneSkinMatrix(uint boneId) const
00384 {
00385
00386 uint validBoneId= _BoneUsage[boneId].ValidBoneSkinMatrix;
00387
00388 return Bones[validBoneId].getBoneSkinMatrix();
00389 }
00390
00391
00392
00393 bool CSkeletonModel::bindSkin(CTransform *mi)
00394 {
00395 nlassert(mi);
00396 if( !mi->isSkinnable() )
00397 return false;
00398
00399
00400 if(mi->_FatherSkeletonModel)
00401 mi->_FatherSkeletonModel->detachSkeletonSon(mi);
00402
00403
00404 _Skins.insert(mi);
00405
00406
00407 mi->_FatherSkeletonModel= this;
00408
00409 mi->setApplySkin(true);
00410
00411
00412
00413 nlassert(HrcTrav && ClipTrav);
00414
00415 mi->unfreezeHRC();
00416
00417 mi->unlinkFromValidateList();
00418 HrcTrav->link(HrcTrav->Scene->getSkipModelRoot(), mi);
00419
00420 IModel *father= ClipTrav->getFirstParent(mi);
00421 while(father)
00422 {
00423 ClipTrav->unlink(father, mi);
00424 father= ClipTrav->getFirstParent(mi);
00425 }
00426
00427 mi->_HrcObs->ClipLinkedInSonsOfAncestorSkeletonModelGroup= false;
00428
00429 ClipTrav->link(ClipTrav->Scene->getSkipModelRoot(), mi);
00430
00431
00432
00433 dirtLodVertexColor();
00434
00435 dirtSkinRenderLists();
00436
00437
00438 return true;
00439 }
00440
00441 void CSkeletonModel::stickObject(CTransform *mi, uint boneId)
00442 {
00443
00444 stickObjectEx(mi, boneId, false);
00445 }
00446
00447 void CSkeletonModel::stickObjectEx(CTransform *mi, uint boneId, bool forceCLod)
00448 {
00449 nlassert(mi);
00450
00451
00452 if(dynamic_cast<CSkeletonModel*>(mi))
00453 forceCLod= true;
00454
00455
00456 if(mi->_FatherSkeletonModel)
00457 mi->_FatherSkeletonModel->detachSkeletonSon(mi);
00458
00459
00460 _StickedObjects.insert(mi);
00461
00462 incForcedBoneUsageAndParents(boneId, forceCLod);
00463
00464
00465 mi->_FatherSkeletonModel= this;
00466 mi->_FatherBoneId= boneId;
00467
00468 mi->_ForceCLodSticked= forceCLod;
00469
00470
00471 nlassert(HrcTrav && ClipTrav);
00472 HrcTrav->link(this, mi);
00473
00474
00475 dirtLodVertexColor();
00476 }
00477
00478 void CSkeletonModel::detachSkeletonSon(CTransform *tr)
00479 {
00480 nlassert(tr);
00481
00482
00483 if(tr->_FatherSkeletonModel!=this)
00484 return;
00485
00486
00487 _StickedObjects.erase(tr);
00488
00489 _Skins.erase(tr);
00490
00491
00492 bool wasSkinned= tr->isSkinned()!=0;
00493 if( !wasSkinned )
00494 {
00495
00496 decForcedBoneUsageAndParents(tr->_FatherBoneId, tr->_ForceCLodSticked);
00497 }
00498 else
00499 {
00500
00501
00502 tr->setApplySkin(false);
00503 }
00504
00505
00506 tr->_FatherSkeletonModel= NULL;
00507 tr->_ForceCLodSticked= false;
00508
00509
00510 nlassert(HrcTrav && ClipTrav);
00511 HrcTrav->link(NULL, tr);
00512 if( !wasSkinned )
00513 {
00514
00515 }
00516 else
00517 {
00518
00519
00520 ClipTrav->unlink(ClipTrav->Scene->getSkipModelRoot(), tr);
00521 ClipTrav->link(ClipTrav->getRoot(), tr);
00522
00523 tr->linkToValidateList();
00524 }
00525
00526
00527
00528 dirtLodVertexColor();
00529
00530 if( wasSkinned )
00531 dirtSkinRenderLists();
00532 }
00533
00534
00535
00536 sint32 CSkeletonModel::getBoneIdByName(const std::string &name) const
00537 {
00538 CSkeletonShape *shp= safe_cast<CSkeletonShape*>((IShape*)Shape);
00539 return shp->getBoneIdByName(name);
00540 }
00541
00542
00543
00544 void CSkeletonModel::setInterpolationDistance(float dist)
00545 {
00546 dist= std::max(0.f, dist);
00547
00548 if(dist==0)
00549 _LodInterpMultiplier= 0.f;
00550 else
00551 _LodInterpMultiplier= 1.f / dist;
00552 }
00553
00554
00555 float CSkeletonModel::getInterpolationDistance() const
00556 {
00557 if(_LodInterpMultiplier==0)
00558 return 0.f;
00559 else
00560 return 1.f / _LodInterpMultiplier;
00561 }
00562
00563
00564
00565 void CSkeletonModelAnimDetailObs::traverse(IObs *caller)
00566 {
00567 CSkeletonModel *sm= (CSkeletonModel*)Model;
00568 CSkeletonShape *skeShape= ((CSkeletonShape*)(IShape*)sm->Shape);
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 CTransformAnimDetailObs::updateWorldMatrixFromFather();
00580
00581 float dist= (HrcObs->WorldMatrix.getPos() - ((CClipTrav*)ClipObs->Trav)->CamPos).norm();
00582
00583 uint newLod= skeShape->getLodForDistance( dist );
00584 if(newLod != sm->_CurLod)
00585 {
00586
00587 sm->_CurLod= newLod;
00588
00589 sm->_BoneToComputeDirty= true;
00590 }
00591
00592
00593 bool forceUpdate= sm->_BoneToComputeDirty;
00594 sm->updateBoneToCompute();
00595
00596
00597 CTransformAnimDetailObs::traverseWithoutUpdateWorldMatrix(caller);
00598
00599
00600
00601
00602
00603 float lodBoneInterp;
00604 const CSkeletonShape::CLod *lodNext= NULL;
00605
00606 if( sm->_CurLod < skeShape->getNumLods()-1 && sm->_LodInterpMultiplier>0 )
00607 {
00608
00609 lodNext= &skeShape->getLod(sm->_CurLod+1);
00610
00611 lodBoneInterp= (lodNext->Distance - dist) * sm->_LodInterpMultiplier;
00612 NLMISC::clamp(lodBoneInterp, 0.f, 1.f);
00613
00614 if(lodBoneInterp==1.f)
00615 lodNext=NULL;
00616 }
00617
00618 else
00619 {
00620 lodBoneInterp=1.f;
00621 }
00622
00623 if(lodBoneInterp != sm->_CurLodInterp)
00624 {
00625
00626 sm->_CurLodInterp= lodBoneInterp;
00627
00628 forceUpdate= true;
00629 }
00630
00631
00632
00633
00634
00635
00636
00637 if(sm->IAnimatable::isTouched(CSkeletonModel::OwnerBit) || forceUpdate)
00638 {
00639
00640 CMatrix &modelWorldMatrix= HrcObs->WorldMatrix;
00641
00642
00643
00644 uint numBoneToCompute= sm->_BoneToCompute.size();
00645 CSkeletonModel::CBoneCompute *pBoneCompute= numBoneToCompute? &sm->_BoneToCompute[0] : NULL;
00646
00647 for(;numBoneToCompute>0;numBoneToCompute--, pBoneCompute++)
00648 {
00649
00650 pBoneCompute->Bone->compute( pBoneCompute->Father, modelWorldMatrix);
00651
00652
00653 if(lodNext && pBoneCompute->MustInterpolate)
00654 {
00655
00656 const CMatrix &fatherMatrix= pBoneCompute->Father->getBoneSkinMatrix();
00657 pBoneCompute->Bone->interpolateBoneSkinMatrix(fatherMatrix, lodBoneInterp);
00658 }
00659 }
00660
00661 sm->IAnimatable::clearFlag(CSkeletonModel::OwnerBit);
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671 for(uint i=0;i<sm->_AnimDetailSkins.size();i++)
00672 {
00673
00674 CTransformAnimDetailObs *adObs;
00675 adObs= safe_cast<CTransformAnimDetailObs*>(sm->_AnimDetailSkins[i]->_ClipObs->AnimDetailObs);
00676
00677
00678 adObs->traverse(NULL);
00679 }
00680
00681 }
00682
00683
00684
00685 void CSkeletonModel::computeAllBones(const CMatrix &modelWorldMatrix)
00686 {
00687
00688
00689 for(uint i=0;i<Bones.size();i++)
00690 {
00691 sint fatherId= Bones[i].getFatherId();
00692
00693 if(fatherId==-1)
00694
00695 Bones[i].compute( NULL, modelWorldMatrix);
00696 else
00697
00698 Bones[i].compute( &Bones[fatherId], modelWorldMatrix);
00699 }
00700
00701 }
00702
00703
00704
00705 void CSkeletonModel::setLodCharacterDistance(float dist)
00706 {
00707 _LodCharacterDistance= max(dist, 0.f);
00708 if(_LodCharacterDistance>0)
00709 _OOLodCharacterDistance= 1.0f/_LodCharacterDistance;
00710 else
00711 _OOLodCharacterDistance= 0;
00712 }
00713
00714
00715 void CSkeletonModel::setLodCharacterShape(sint shapeId)
00716 {
00717
00718 CScene *scene= static_cast<CScene*>(_OwnerMot);
00719 CLodCharacterManager *mngr= scene->getLodCharacterManager();
00720
00721
00722 if(!mngr)
00723 return;
00724
00725
00726 if(_CLodInstance.ShapeId>=0)
00727 {
00728 mngr->releaseInstance(_CLodInstance);
00729 _CLodInstance.ShapeId= -1;
00730 }
00731
00732
00733 _CLodInstance.ShapeId= shapeId;
00734
00735
00736 if(_CLodInstance.ShapeId>=0)
00737 {
00738 mngr->initInstance(_CLodInstance);
00739 }
00740 }
00741
00742
00743
00744 void CSkeletonModel::computeLodTexture()
00745 {
00746
00747 if(_CLodInstance.ShapeId<0)
00748 return;
00749
00750
00751 CScene *scene= static_cast<CScene*>(_OwnerMot);
00752 CLodCharacterManager *mngr= scene->getLodCharacterManager();
00753
00754 nlassert(mngr);
00755
00756
00757
00758
00759 CAsyncTextureManager *asyncMngr= scene->getAsyncTextureManager();
00760
00761 if(!asyncMngr)
00762 return;
00763
00764
00765
00766 if(!mngr->startTextureCompute(_CLodInstance))
00767 return;
00768 uint maxNumBmpToReset= 0;
00769
00770
00771 ItTransformSet it= _Skins.begin();
00772 for(;it!=_Skins.end();it++)
00773 {
00774
00775 CMeshBaseInstance *mbi= dynamic_cast<CMeshBaseInstance*>(*it);
00776 if(mbi && mbi->getAsyncTextureMode() && mbi->Shape)
00777 {
00778 CMeshBase *mb= (CMeshBase*)(IShape*)(mbi->Shape);
00779
00780 const CLodCharacterTexture *lodText= mb->getLodCharacterTexture();
00781
00782 if(lodText)
00783 {
00784
00785
00786
00787 uint numMats= mbi->Materials.size();
00788
00789 numMats= min(numMats, 256U);
00790
00791 maxNumBmpToReset= max(maxNumBmpToReset, numMats);
00792
00793 for(uint i=0;i<numMats;i++)
00794 {
00795
00796 CLodCharacterTmpBitmap &dstBmp= mngr->getTmpBitmap(i);
00797
00798
00799 sint asyncTextId= mbi->getAsyncTextureId(i,0);
00800 const CBitmap *coarseBitmap= NULL;
00801 if(asyncTextId!=-1)
00802 {
00803
00804 coarseBitmap= asyncMngr->getCoarseBitmap(asyncTextId);
00805 }
00806
00807
00808 if(!coarseBitmap)
00809 {
00810 dstBmp.build(mbi->Materials[i].getDiffuse());
00811 }
00812 else
00813 {
00814 dstBmp.build(*coarseBitmap);
00815 }
00816 }
00817
00818
00819 mngr->addTextureCompute(_CLodInstance, *lodText);
00820 }
00821 }
00822 }
00823
00824
00825 mngr->endTextureCompute(_CLodInstance, maxNumBmpToReset);
00826
00827 }
00828
00829
00830
00831 void CSkeletonModel::setLodCharacterAnimId(uint animId)
00832 {
00833 _CLodInstance.AnimId= animId;
00834 }
00835
00836
00837 void CSkeletonModel::setLodCharacterAnimTime(TGlobalAnimationTime time)
00838 {
00839 _CLodInstance.AnimTime= time;
00840 }
00841
00842
00843 void CSkeletonModel::setLodCharacterWrapMode(bool wrapMode)
00844 {
00845 _CLodInstance.WrapMode= wrapMode;
00846 }
00847
00848
00849
00850 float CSkeletonModel::computeDisplayLodCharacterPriority() const
00851 {
00852
00853 if(_LodCharacterDistance>0 && _CLodInstance.ShapeId>=0)
00854 {
00855 CVector globalPos;
00856
00857
00858
00859
00860
00861
00862
00863 if( _HrcObs->_AncestorSkeletonModel != NULL)
00864 {
00865
00866 if( !_HrcObs->_AncestorSkeletonModel->isClipVisible() )
00867 return 0;
00868
00869 globalPos= _HrcObs->_AncestorSkeletonModel->getWorldMatrix().getPos();
00870 }
00871 else
00872 {
00873
00874 if( !isClipVisible() )
00875 return 0;
00876
00877 globalPos= _HrcObs->WorldMatrix.getPos();
00878 }
00879
00880
00881 float dist= (ClipTrav->CamPos - globalPos).norm();
00882
00883
00884 return dist*_OOLodCharacterDistance;
00885 }
00886 else
00887 return 0;
00888 }
00889
00890
00891
00892 void CSkeletonModel::setDisplayLodCharacterFlag(bool displayCLod)
00893 {
00894
00895 if(_LodCharacterDistance>0 && _CLodInstance.ShapeId>=0)
00896 {
00897
00898 if(_DisplayedAsLodCharacter != displayCLod)
00899 _BoneToComputeDirty= true;
00900
00901
00902 _DisplayedAsLodCharacter= displayCLod;
00903 }
00904 }
00905
00906
00907
00908 void CSkeletonModelRenderObs::traverse(IObs *caller)
00909 {
00910 H_AUTO( NL3D_Skeleton_Render );
00911
00912 CSkeletonModel *sm= (CSkeletonModel*)Model;
00913
00914
00915 if(sm->isDisplayedAsLodCharacter())
00916 renderCLod();
00917 else
00918 renderSkins();
00919 }
00920
00921
00922
00923 void CSkeletonModel::computeCLodVertexColors(CLodCharacterManager *mngr)
00924 {
00925
00926 if(_CLodInstance.ShapeId<0)
00927 return;
00928
00929 const CLodCharacterShape *lodShape= mngr->getShape(_CLodInstance.ShapeId);
00930 if(lodShape)
00931 {
00932 static vector<CRGBAF> tmpColors;
00933 tmpColors.clear();
00934
00935
00936
00937 lodShape->startBoneColor(tmpColors);
00938
00939
00940 static vector<sint> boneMap;
00941
00942 boneMap.clear();
00943 boneMap.resize(Bones.size(), -1);
00944 uint i;
00945
00946 for(i=0; i<boneMap.size(); i++)
00947 {
00948 boneMap[i]= lodShape->getBoneIdByName(Bones[i].getBoneName());;
00949 }
00950
00951
00952
00953 ItTransformSet it;
00954 for(it= _Skins.begin(); it!=_Skins.end(); it++)
00955 {
00956 CTransform *skin= *it;
00957
00958
00959 CRGBA color= skin->getMeanColor();
00960
00961
00962 const vector<sint32> *skinUsage= skin->getSkinBoneUsage();
00963
00964 if(skinUsage)
00965 {
00966
00967 for(uint i=0; i<skinUsage->size(); i++)
00968 {
00969
00970
00971 sint idInLod= boneMap[(*skinUsage)[i]];
00972
00973 if(idInLod>=0)
00974
00975 lodShape->addBoneColor(idInLod, color, tmpColors);
00976 }
00977
00978 }
00979 }
00980
00981
00982
00983 for(it= _StickedObjects.begin(); it!=_StickedObjects.end(); it++)
00984 {
00985 CTransform *object= *it;
00986
00987
00988 CRGBA color= object->getMeanColor();
00989
00990
00991
00992 sint idInLod= boneMap[object->_FatherBoneId];
00993
00994
00995 if(idInLod>=0)
00996
00997 lodShape->addBoneColor(idInLod, color, tmpColors);
00998 }
00999
01000
01001
01002
01003 lodShape->endBoneColor(tmpColors, _CLodInstance.VertexColors);
01004 }
01005
01006 }
01007
01008
01009
01010 void CSkeletonModel::updateSkinRenderLists()
01011 {
01012
01013 if(_SkinToRenderDirty)
01014 {
01015 _SkinToRenderDirty= false;
01016
01017
01018 _LevelDetail.MinFaceUsed= 0;
01019 _LevelDetail.MaxFaceUsed= 0;
01020
01021 if(_DefaultMRMSetup)
01022 {
01023 _LevelDetail.DistanceCoarsest= 0;
01024 _LevelDetail.DistanceMiddle= 0;
01025 _LevelDetail.DistanceFinest= 0;
01026 }
01027
01028
01029 uint opaqueSize= 0;
01030 uint transparentSize= 0;
01031 uint animDetailSize= 0;
01032 ItTransformSet it;
01033 for(it= _Skins.begin();it!=_Skins.end();it++)
01034 {
01035 CTransform *skin= *it;
01036
01037 if(skin->isTransparent())
01038 transparentSize++;
01039
01040
01041 else if(skin->isOpaque())
01042 opaqueSize++;
01043
01044
01045 if(skin->isAnimDetailable())
01046 animDetailSize++;
01047
01048
01049 CTransformShape *trShape= dynamic_cast<CTransformShape*>(skin);
01050 if(trShape)
01051 {
01052 const CMRMLevelDetail *skinLevelDetail= trShape->getMRMLevelDetail();
01053 if(skinLevelDetail)
01054 {
01055
01056 _LevelDetail.MinFaceUsed+= skinLevelDetail->MinFaceUsed;
01057 _LevelDetail.MaxFaceUsed+= skinLevelDetail->MaxFaceUsed;
01058
01059 if(_DefaultMRMSetup)
01060 {
01061
01062 _LevelDetail.DistanceCoarsest= max(_LevelDetail.DistanceCoarsest, skinLevelDetail->DistanceCoarsest);
01063 _LevelDetail.DistanceMiddle= max(_LevelDetail.DistanceMiddle, skinLevelDetail->DistanceMiddle);
01064 _LevelDetail.DistanceFinest= max(_LevelDetail.DistanceFinest, skinLevelDetail->DistanceFinest);
01065 }
01066 }
01067 }
01068 }
01069
01070
01071 if(_DefaultMRMSetup)
01072 {
01073
01074 if(_LevelDetail.MaxFaceUsed==0)
01075
01076 buildDefaultLevelDetail();
01077 else
01078 _LevelDetail.compileDistanceSetup();
01079 }
01080
01081
01082 _OpaqueSkins.clear();
01083 _TransparentSkins.clear();
01084 _AnimDetailSkins.clear();
01085 _OpaqueSkins.resize(opaqueSize);
01086 _TransparentSkins.resize(transparentSize);
01087 _AnimDetailSkins.resize(animDetailSize);
01088
01089
01090 uint opaqueId= 0;
01091 uint transparentId= 0;
01092 uint animDetailId= 0;
01093 for(it= _Skins.begin();it!=_Skins.end();it++)
01094 {
01095 CTransform *skin= *it;
01096
01097 if(skin->isTransparent())
01098 {
01099 nlassert(transparentId<transparentSize);
01100 _TransparentSkins[transparentId++]= skin;
01101 }
01102
01103
01104 else if(skin->isOpaque())
01105 {
01106 nlassert(opaqueId<opaqueSize);
01107 _OpaqueSkins[opaqueId++]= skin;
01108 }
01109
01110
01111 if(skin->isAnimDetailable())
01112 {
01113 nlassert(animDetailId<animDetailSize);
01114 _AnimDetailSkins[animDetailId++]= skin;
01115 }
01116 }
01117
01118
01119 setTransparency( transparentSize>0 );
01120 }
01121 }
01122
01123
01124
01125 void CSkeletonModel::buildDefaultLevelDetail()
01126 {
01127
01128 _LevelDetail.MinFaceUsed= 0;
01129 _LevelDetail.MaxFaceUsed= 0;
01130 _LevelDetail.DistanceFinest= 1;
01131 _LevelDetail.DistanceMiddle= 2;
01132 _LevelDetail.DistanceCoarsest= 3;
01133 _LevelDetail.compileDistanceSetup();
01134 }
01135
01136
01137
01138 void CSkeletonModelRenderObs::renderCLod()
01139 {
01140 CRenderTrav *trav= (CRenderTrav*)Trav;
01141 CSkeletonModel *sm= (CSkeletonModel*)Model;
01142 IDriver *drv= trav->getDriver();
01143 CScene *scene= trav->Scene;
01144
01145 CLodCharacterManager *mngr= trav->Scene->getLodCharacterManager();
01146 if(!mngr)
01147 return;
01148
01149
01150
01151 const CLightContribution *lightContrib;
01152
01153 CTransformHrcObs *hrcObs= (CTransformHrcObs*)HrcObs;
01154
01155
01156 if(hrcObs->_AncestorSkeletonModel==NULL)
01157 lightContrib= &sm->getSkeletonLightContribution();
01158
01159 else
01160 lightContrib= &hrcObs->_AncestorSkeletonModel->getSkeletonLightContribution();
01161
01162
01163 CRGBA mainAmbient= scene->getSunAmbient();
01164 CRGBA mainDiffuse= scene->getSunDiffuse();
01165
01166 mainDiffuse.modulateFromuiRGBOnly(mainDiffuse, lightContrib->SunContribution );
01167 CVector mainLightDir= scene->getSunDirection();
01168
01169
01170
01171
01172
01173 CPointLight *mainPL= lightContrib->PointLight[0];
01174 if(mainPL)
01175 {
01176 CRGBA plDiffuse;
01177
01178 plDiffuse.modulateFromuiRGBOnly(mainPL->getDiffuse(), lightContrib->AttFactor[0]);
01179
01180 uint d0= mainDiffuse.R + mainDiffuse.G + mainDiffuse.B;
01181 uint d1= plDiffuse.R + plDiffuse.G + plDiffuse.B;
01182
01183 if(d1>d0)
01184 {
01185
01186 mainDiffuse= plDiffuse;
01187 mainLightDir= hrcObs->WorldMatrix.getPos() - mainPL->getPosition();
01188 mainLightDir.normalize();
01189 }
01190 }
01191
01192
01193
01194
01195
01196
01197
01198 if(sm->_CLodVertexColorDirty)
01199 {
01200
01201 sm->computeCLodVertexColors(mngr);
01202
01203 sm->_CLodVertexColorDirty= false;
01204 }
01205
01206
01207
01208
01209 nlassert(mngr->isRendering());
01210
01211
01212
01213 if(!mngr->addRenderCharacterKey(sm->_CLodInstance, hrcObs->WorldMatrix,
01214 mainAmbient, mainDiffuse, mainLightDir) )
01215 {
01216
01217
01218
01219 mngr->endRender();
01220
01221 mngr->beginRender(drv, trav->CamPos);
01222
01223
01224 mngr->addRenderCharacterKey(sm->_CLodInstance, hrcObs->WorldMatrix,
01225 mainAmbient, mainDiffuse, mainLightDir);
01226 }
01227 }
01228
01229
01230
01231 void CSkeletonModelRenderObs::renderSkins()
01232 {
01233
01234 CRenderTrav *rdrTrav= (CRenderTrav*)Trav;
01235 CSkeletonModel *sm= (CSkeletonModel*)Model;
01236 CTransformHrcObs *hrcObs= (CTransformHrcObs*)HrcObs;
01237
01238 IDriver *drv= rdrTrav->getDriver();
01239 nlassert(drv);
01240
01241
01242
01243 float alphaMRM= sm->_LevelDetail.getLevelDetailFromPolyCount(sm->getNumTrianglesAfterLoadBalancing());
01244
01245
01246 bool bkupNorm= drv->isForceNormalize();
01247 drv->forceNormalize(true);
01248
01249
01250
01251 if(rdrTrav->isCurrentPassOpaque())
01252 {
01253
01254
01255
01256
01257 if(hrcObs->_AncestorSkeletonModel==NULL)
01258 sm->setupCurrentLightContribution(&sm->_LightContribution, false);
01259
01260 else
01261 sm->setupCurrentLightContribution(&hrcObs->_AncestorSkeletonModel->_LightContribution, false);
01262
01263
01264
01265 sm->changeLightSetup( rdrTrav );
01266 rdrTrav->getDriver()->setupModelMatrix(hrcObs->WorldMatrix);
01267
01268
01269
01270 renderSkinList(sm->_OpaqueSkins, alphaMRM);
01271 }
01272 else
01273 {
01274
01275
01276
01277 sm->changeLightSetup( rdrTrav );
01278 rdrTrav->getDriver()->setupModelMatrix(hrcObs->WorldMatrix);
01279
01280
01281
01282 renderSkinList(sm->_TransparentSkins, alphaMRM);
01283 }
01284
01285
01286
01287 drv->forceNormalize(bkupNorm);
01288 }
01289
01290
01291
01292 void CSkeletonModelRenderObs::renderSkinList(NLMISC::CObjectVector<CTransform*, false> &skinList, float alphaMRM)
01293 {
01294 CRenderTrav *rdrTrav= (CRenderTrav*)Trav;
01295
01296
01297 if( !rdrTrav->getMeshSkinManager() || !rdrTrav->getMeshSkinManager()->enabled() )
01298 {
01299 for(uint i=0;i<skinList.size();i++)
01300 {
01301 skinList[i]->renderSkin(alphaMRM);
01302 }
01303 }
01304 else
01305 {
01306
01307 CMeshSkinManager &meshSkinManager= *rdrTrav->getMeshSkinManager();
01308
01309
01310 static std::vector<CTransform*> skinsToGroup;
01311 static std::vector<uint> baseVertices;
01312 skinsToGroup.clear();
01313 baseVertices.clear();
01314
01315
01316 uint maxVertices= meshSkinManager.getMaxVertices();
01317 uint vertexSize= meshSkinManager.getVertexSize();
01318
01319
01320 for(uint i=0;i<skinList.size();i++)
01321 {
01322
01323 if(!skinList[i]->supportSkinGrouping())
01324 {
01325 H_AUTO( NL3D_Skin_NotGrouped );
01326 skinList[i]->renderSkin(alphaMRM);
01327 }
01328 else
01329 {
01330 skinsToGroup.push_back(skinList[i]);
01331 }
01332 }
01333
01334 H_AUTO( NL3D_Skin_Grouped );
01335
01336
01337 baseVertices.resize(skinsToGroup.size());
01338
01339
01340 uint skinId= 0;
01341 while(skinId<skinsToGroup.size())
01342 {
01343
01344 uint remainingVertices= maxVertices;
01345 uint currentBaseVertex= 0;
01346
01347
01348
01349
01350 uint8 *vbDest= meshSkinManager.lock();
01351
01352
01353 uint startSkinId= skinId;
01354 while(skinId<skinsToGroup.size())
01355 {
01356
01357 sint numVerticesAdded= skinsToGroup[skinId]->renderSkinGroupGeom(alphaMRM, remainingVertices,
01358 vbDest + vertexSize*currentBaseVertex );
01359
01360 if(numVerticesAdded==-1)
01361 break;
01362
01363 baseVertices[skinId]= currentBaseVertex;
01364
01365 currentBaseVertex+= numVerticesAdded;
01366 remainingVertices-= numVerticesAdded;
01367
01368
01369 skinId++;
01370 }
01371
01372
01373 meshSkinManager.unlock(currentBaseVertex);
01374
01375
01376
01377 meshSkinManager.activate();
01378 for(uint i=startSkinId;i<skinId;i++)
01379 {
01380
01381 skinsToGroup[i]->renderSkinGroupPrimitives(baseVertices[i]);
01382 }
01383
01384
01385
01386 meshSkinManager.swapVBHard();
01387 }
01388 }
01389 }
01390
01391
01392
01393 float CSkeletonModel::getNumTriangles (float distance)
01394 {
01395
01396 if( isDisplayedAsLodCharacter() )
01397 return 0;
01398 else
01399
01400 return _LevelDetail.getNumTriangles(distance);
01401 }
01402
01403
01404 void CSkeletonModel::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
01405 {
01406
01407 if(distanceFinest<0) return;
01408 if(distanceMiddle<=distanceFinest) return;
01409 if(distanceCoarsest<=distanceMiddle) return;
01410
01411
01412 _LevelDetail.DistanceFinest= distanceFinest;
01413 _LevelDetail.DistanceMiddle= distanceMiddle;
01414 _LevelDetail.DistanceCoarsest= distanceCoarsest;
01415
01416
01417 _LevelDetail.compileDistanceSetup();
01418
01419
01420 _DefaultMRMSetup= false;
01421 }
01422
01423
01424
01425 void CSkeletonModel::resetDefaultMRMDistanceSetup()
01426 {
01427 _DefaultMRMSetup= true;
01428
01429
01430 dirtSkinRenderLists();
01431 }
01432
01433
01434
01435 bool CSkeletonModel::computeRenderedBBox(NLMISC::CAABBox &bbox)
01436 {
01437
01438 CAABBox tmpBBox;
01439 tmpBBox.setCenter(CVector::Null);
01440 tmpBBox.setHalfSize(CVector::Null);
01441 bool empty= true;
01442
01443
01444 if(!getLastClippedState())
01445 return false;
01446
01447
01448 uint i;
01449 for(i=0;i<Bones.size();i++)
01450 {
01451 if(isBoneComputed(i))
01452 {
01453 const CVector &pos= Bones[i].getLocalSkeletonMatrix().getPos();
01454 if(empty)
01455 {
01456 empty= false;
01457 tmpBBox.setCenter(pos);
01458 }
01459 else
01460 tmpBBox.extend(pos);
01461 }
01462 }
01463
01464
01465 if(!empty)
01466 {
01467 bbox= tmpBBox;
01468 return true;
01469 }
01470 else
01471 return false;
01472 }
01473
01474
01475
01476 bool CSkeletonModel::computeCurrentBBox(NLMISC::CAABBox &bbox, bool forceCompute )
01477 {
01478
01479 CChannelMixer *chanmix= getChannelMixer();
01480 if (chanmix)
01481 {
01482
01483 chanmix->resetEvalDetailDate();
01484 chanmix->eval(true, 0);
01485 chanmix->resetEvalDetailDate();
01486 }
01487
01488 computeAllBones(CMatrix::Identity);
01489
01490
01491 CAABBox tmpBBox;
01492 tmpBBox.setCenter(CVector::Null);
01493 tmpBBox.setHalfSize(CVector::Null);
01494 bool empty= true;
01495
01496
01497 uint i;
01498 for(i=0;i<Bones.size();i++)
01499 {
01500
01501 uint8 mustCompute = forceCompute ? 1 : _BoneUsage[i].Usage | _BoneUsage[i].ForcedUsage | _BoneUsage[i].CLodForcedUsage;
01502
01503
01504 if(mustCompute)
01505 {
01506 const CVector &pos= Bones[i].getLocalSkeletonMatrix().getPos();
01507 if(empty)
01508 {
01509 empty= false;
01510 tmpBBox.setCenter(pos);
01511 }
01512 else
01513 tmpBBox.extend(pos);
01514 }
01515 }
01516
01517
01518 if(!empty)
01519 {
01520 bbox= tmpBBox;
01521 return true;
01522 }
01523 else
01524 return false;
01525 }
01526
01527
01528 }