From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- docs/doxygen/nel/skeleton__model_8cpp-source.html | 1597 +++++++++++++++++++++ 1 file changed, 1597 insertions(+) create mode 100644 docs/doxygen/nel/skeleton__model_8cpp-source.html (limited to 'docs/doxygen/nel/skeleton__model_8cpp-source.html') diff --git a/docs/doxygen/nel/skeleton__model_8cpp-source.html b/docs/doxygen/nel/skeleton__model_8cpp-source.html new file mode 100644 index 00000000..5a9a416f --- /dev/null +++ b/docs/doxygen/nel/skeleton__model_8cpp-source.html @@ -0,0 +1,1597 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

skeleton_model.cpp

Go to the documentation of this file.
00001 
+00007 /* Copyright, 2001 Nevrax Ltd.
+00008  *
+00009  * This file is part of NEVRAX NEL.
+00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00011  * it under the terms of the GNU General Public License as published by
+00012  * the Free Software Foundation; either version 2, or (at your option)
+00013  * any later version.
+00014 
+00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00018  * General Public License for more details.
+00019 
+00020  * You should have received a copy of the GNU General Public License
+00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00023  * MA 02111-1307, USA.
+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         // Add any bones.
+00069         for(uint i=0;i<Bones.size();i++)
+00070         {
+00071                 // append  bonename.
+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         // Inform the transform that I am a skeleton
+00094         CTransform::setIsSkeleton(true);
+00095 
+00096         // By default, no skins, hence, impossible to have transparent pass. But opaque pass is always possible
+00097         // because of CLod rendering
+00098         setOpacity(true);
+00099         setTransparency(false);
+00100 
+00101         // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
+00102         CTransform::setIsForceAnimDetail(true);
+00103 
+00104         // LoadBalancing behavior. true because directly act on skins to draw all their MRM level
+00105         CTransform::setIsLoadbalancable(true);
+00106 
+00107         // Lighting behavior. Lightable because skins/stickedObjects may surely need its LightContribution
+00108         CTransform::setIsLightable(true);
+00109 
+00110         // Render behavior. Always renderable, because either render the skeleton as a CLod, or render skins
+00111         CTransform::setIsRenderable(true);
+00112 
+00113         // build a bug-free level detail
+00114         buildDefaultLevelDetail();
+00115 }
+00116 
+00117         
+00118 // ***************************************************************************
+00119 CSkeletonModel::~CSkeletonModel()
+00120 {
+00121         // if initModel() called
+00122         if(ClipTrav)
+00123         {
+00124                 // remove from scene
+00125                 ClipTrav->Scene->eraseSkeletonModelToList(_ItSkeletonInScene);
+00126         }
+00127 
+00128 
+00129         // detach skeleton sons from skins.
+00130         while(_Skins.begin()!=_Skins.end())
+00131         {
+00132                 detachSkeletonSon(*_Skins.begin());
+00133         }
+00134 
+00135         // detach skeleton sons from sticked objects.
+00136         while(_StickedObjects.begin()!=_StickedObjects.end())
+00137         {
+00138                 detachSkeletonSon(*_StickedObjects.begin());
+00139         }
+00140 
+00141         // Free Lod instance
+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         // Link this skeleton to the CScene.
+00156         _ItSkeletonInScene= ClipTrav->Scene->appendSkeletonModelToList(this);
+00157 
+00158         // Call base class
+00159         CTransformShape::initModel();
+00160 }
+00161 
+00162 
+00163 // ***************************************************************************
+00164 void            CSkeletonModel::initBoneUsages()
+00165 {
+00166         // reset all to 0.
+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         // reserve space for bone to compute
+00177         _BoneToCompute.reserve(Bones.size());
+00178 
+00179         _BoneToComputeDirty= false;
+00180         _CurLod= 0;
+00181         _CurLodInterp= 1.f;
+00182         // Default is 0.5 meters.
+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         // Get ptr on according refCount
+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         // If the bone was not used before, must update MustCompute.
+00202         if(*usagePtr==0)
+00203                 _BoneToComputeDirty= true;
+00204 
+00205         // Inc the refCount of the bone.
+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         // Get ptr on according refCount
+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         // If the bone was used before (and now won't be more), must update MustCompute.
+00226         if(*usagePtr==1)
+00227                 _BoneToComputeDirty= true;
+00228 
+00229         // Inc the refCount of the bone.
+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         // Flag this bone.
+00242         boneUsage[boneId]= true;
+00243 
+00244         // if has father, flag it (recurs).
+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         // inc forced.
+00255         incBoneUsage(i, forceCLod?UsageCLodForced:UsageForced );
+00256 
+00257         // recurs to father
+00258         sint    fatherId= Bones[i].getFatherId();
+00259         // if not a root bone...
+00260         if(fatherId>=0)
+00261                 incForcedBoneUsageAndParents(fatherId, forceCLod);
+00262 }
+00263 
+00264 // ***************************************************************************
+00265 void            CSkeletonModel::decForcedBoneUsageAndParents(uint i, bool forceCLod)
+00266 {
+00267         // dec forced
+00268         decBoneUsage(i, forceCLod?UsageCLodForced:UsageForced);
+00269 
+00270         // recurs to father
+00271         sint    fatherId= Bones[i].getFatherId();
+00272         // if not a root bone...
+00273         if(fatherId>=0)
+00274                 decForcedBoneUsageAndParents(fatherId, forceCLod);
+00275 }
+00276 
+00277 
+00278 // ***************************************************************************
+00279 void            CSkeletonModel::updateBoneToCompute()
+00280 {
+00281         // If already computed, skip
+00282         if(!_BoneToComputeDirty)
+00283                 return;
+00284 
+00285         // get the channelMixer owned by CTransform.
+00286         CChannelMixer   *chanMixer= getChannelMixer();
+00287 
+00288         // Get Lod infos from skeletonShape
+00289         CSkeletonShape          *skeShape= (CSkeletonShape*)(IShape*)Shape;
+00290         const CSkeletonShape::CLod      &lod= skeShape->getLod(_CurLod);
+00291 
+00292         // reset _BoneToCompute
+00293         _BoneToCompute.clear();
+00294 
+00295         // For all bones
+00296         for(uint i=0; i<_BoneUsage.size(); i++)
+00297         {
+00298                 // If we are in CLod mode
+00299                 if(isDisplayedAsLodCharacter())
+00300                         // don't compute the bone
+00301                         _BoneUsage[i].MustCompute= 0;
+00302                 else
+00303                 {
+00304                         // set MustCompute to non 0 if (Usage && Lod) || ForcedUsage;
+00305                         _BoneUsage[i].MustCompute= (_BoneUsage[i].Usage & lod.ActiveBones[i]) | _BoneUsage[i].ForcedUsage;
+00306                 }
+00307                 // if CLodForcedUsage for the bone, it must be computed, whatever _DisplayedAsLodCharacter state
+00308                 _BoneUsage[i].MustCompute|= _BoneUsage[i].CLodForcedUsage;
+00309 
+00310                 // If the bone must be computed (if !0)
+00311                 if(_BoneUsage[i].MustCompute)
+00312                 {
+00313                         // lodEnable the channels of this bone
+00314                         if(chanMixer)
+00315                                 Bones[i].lodEnableChannels(chanMixer, true);
+00316 
+00317                         // This bone is computed => take his valid boneSkinMatrix.
+00318                         _BoneUsage[i].ValidBoneSkinMatrix= i;
+00319 
+00320                         // Append to the list to compute.
+00321                         //-------
+00322                         CBoneCompute    bc;
+00323                         bc.Bone= &Bones[i];
+00324                         sint    fatherId= Bones[i].getFatherId();
+00325                         // if a root bone...
+00326                         if(fatherId==-1)
+00327                                 bc.Father= NULL;
+00328                         else
+00329                                 bc.Father= &Bones[fatherId];
+00330                         // MustInterpolate??
+00331                         bc.MustInterpolate= false;
+00332                         const CSkeletonShape::CLod      *lodNext= NULL;
+00333                         // if a lod exist after current lod, and if lod interpolation enabled
+00334                         if( _CurLod < skeShape->getNumLods()-1 && _LodInterpMultiplier>0 )
+00335                         {
+00336                                 // get next lod.
+00337                                 lodNext= &skeShape->getLod(_CurLod+1);
+00338                                 // Lod interpolation on this bone ?? only if at next lod, the bone is disabled.
+00339                                 // And only if it is not enabed because of a "Forced reason"
+00340                                 // Must also have a father, esle can't interpolate.
+00341                                 if(lodNext->ActiveBones[i]==0 && _BoneUsage[i].ForcedUsage==0 && _BoneUsage[i].CLodForcedUsage==0 
+00342                                         && bc.Father)
+00343                                         bc.MustInterpolate= true;
+00344                         }
+00345                         // append
+00346                         _BoneToCompute.push_back(bc);
+00347                 }
+00348                 else
+00349                 {
+00350                         // lodDisable the channels of this bone
+00351                         if(chanMixer)
+00352                                 Bones[i].lodEnableChannels(chanMixer, false);
+00353 
+00354                         // This bone is not computed => take the valid boneSkinMatrix of his father
+00355                         sint    fatherId= Bones[i].getFatherId();
+00356                         if(fatherId<0)
+00357                                 // just take me, even if not computed.
+00358                                 _BoneUsage[i].ValidBoneSkinMatrix= i;
+00359                         else
+00360                                 // NB: father ValidBoneSkinMatrix already computed because of the hierarchy order of Bones array.
+00361                                 _BoneUsage[i].ValidBoneSkinMatrix= _BoneUsage[fatherId].ValidBoneSkinMatrix;
+00362                 }
+00363         }
+00364 
+00365         // For 
+00366 
+00367         // computed
+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         // Get me or first father with MustCompute==true.
+00386         uint validBoneId= _BoneUsage[boneId].ValidBoneSkinMatrix;
+00387         // return his WorldMatrix.
+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         // try to detach this object from any skeleton first (possibly me).
+00400         if(mi->_FatherSkeletonModel)
+00401                 mi->_FatherSkeletonModel->detachSkeletonSon(mi);
+00402 
+00403         // Then Add me.
+00404         _Skins.insert(mi);
+00405 
+00406         // advert skin transform it is skinned.
+00407         mi->_FatherSkeletonModel= this;
+00408         // setApplySkin() use _FatherSkeletonModel to computeBonesId() and to update current skeleton bone usage.
+00409         mi->setApplySkin(true);
+00410 
+00411 
+00412         // Unlink the Skin from Hrc and clip, because SkeletonModel now does the job for him.
+00413         nlassert(HrcTrav && ClipTrav);
+00414         // First ensure that the transform is not frozen (unlink from some quadGrids etc...)
+00415         mi->unfreezeHRC();
+00416         // then never re-parse in validateList/Hrc/Clip
+00417         mi->unlinkFromValidateList();
+00418         HrcTrav->link(HrcTrav->Scene->getSkipModelRoot(), mi);
+00419         // ClipTrav is a graph, so must unlink from ALL olds models.
+00420         IModel  *father= ClipTrav->getFirstParent(mi);
+00421         while(father)
+00422         {
+00423                 ClipTrav->unlink(father, mi);
+00424                 father= ClipTrav->getFirstParent(mi);
+00425         }
+00426         // Ensure flag is correct
+00427         mi->_HrcObs->ClipLinkedInSonsOfAncestorSkeletonModelGroup= false;
+00428         // link to the SkipModelRoot One.
+00429         ClipTrav->link(ClipTrav->Scene->getSkipModelRoot(), mi);
+00430 
+00431 
+00432         // must recompute lod vertex color when LodCharacter used
+00433         dirtLodVertexColor();
+00434         // must recompute list of skins.
+00435         dirtSkinRenderLists();
+00436 
+00437         // Ok, skinned
+00438         return true;
+00439 }
+00440 // ***************************************************************************
+00441 void            CSkeletonModel::stickObject(CTransform *mi, uint boneId)
+00442 {
+00443         // by default don't force display of "mi" if the skeleton become in CLod state
+00444         stickObjectEx(mi, boneId, false);
+00445 }
+00446 // ***************************************************************************
+00447 void            CSkeletonModel::stickObjectEx(CTransform *mi, uint boneId, bool forceCLod)
+00448 {
+00449         nlassert(mi);
+00450 
+00451         // if "mi" is a skeleton, forceCLod must be true, for correct animation purpose
+00452         if(dynamic_cast<CSkeletonModel*>(mi))
+00453                 forceCLod= true;
+00454 
+00455         // try to detach this object from any skeleton first (possibly me).
+00456         if(mi->_FatherSkeletonModel)
+00457                 mi->_FatherSkeletonModel->detachSkeletonSon(mi);
+00458 
+00459         // Then Add me.
+00460         _StickedObjects.insert(mi);
+00461         // increment the refCount usage of the bone
+00462         incForcedBoneUsageAndParents(boneId, forceCLod);
+00463 
+00464         // advert transform of its sticked state.
+00465         mi->_FatherSkeletonModel= this;
+00466         mi->_FatherBoneId= boneId;
+00467         // advert him if it is "ForceCLod" sticked
+00468         mi->_ForceCLodSticked= forceCLod;
+00469 
+00470         // link correctly Hrc only. ClipTrav grah updated in Hrc traversal.
+00471         nlassert(HrcTrav && ClipTrav);
+00472         HrcTrav->link(this, mi);
+00473 
+00474         // must recompute lod vertex color when LodCharacter used
+00475         dirtLodVertexColor();
+00476 }
+00477 // ***************************************************************************
+00478 void            CSkeletonModel::detachSkeletonSon(CTransform *tr)
+00479 {
+00480         nlassert(tr);
+00481 
+00482         // If the instance is not binded/sticked to the skeleton, exit.
+00483         if(tr->_FatherSkeletonModel!=this)
+00484                 return;
+00485 
+00486         // try to erase from StickObject.
+00487         _StickedObjects.erase(tr);
+00488         // try to erase from Skins.
+00489         _Skins.erase(tr);
+00490 
+00491         // If the instance is not skinned, then it is sticked
+00492         bool    wasSkinned= tr->isSkinned()!=0;
+00493         if( !wasSkinned )
+00494         {
+00495                 // Then decrement Bone Usage RefCount. Decrement from CLodForcedUsage if was sticked with forceCLod==true
+00496                 decForcedBoneUsageAndParents(tr->_FatherBoneId, tr->_ForceCLodSticked);
+00497         }
+00498         else
+00499         {
+00500                 // it is skinned, advert the skinning is no more OK.
+00501                 // setApplySkin() use _FatherSkeletonModel to update current skeleton bone usage.
+00502                 tr->setApplySkin(false);
+00503         }
+00504 
+00505         // advert transform it is no more sticked/skinned.
+00506         tr->_FatherSkeletonModel= NULL;
+00507         tr->_ForceCLodSticked= false;
+00508 
+00509         // link correctly Hrc / Clip / ValidateList...
+00510         nlassert(HrcTrav && ClipTrav);
+00511         HrcTrav->link(NULL, tr);
+00512         if( !wasSkinned )
+00513         {
+00514                 //  No-op. ClipTrav graph/ValidateList updated in Hrc traversal.
+00515         }
+00516         else
+00517         {
+00518                 // Skin case: must do the Job here.
+00519                 // Update ClipTrav here.
+00520                 ClipTrav->unlink(ClipTrav->Scene->getSkipModelRoot(), tr);
+00521                 ClipTrav->link(ClipTrav->getRoot(), tr);
+00522                 // Must re-add to the validate list.
+00523                 tr->linkToValidateList();
+00524         }
+00525 
+00526 
+00527         // must recompute lod vertex color when LodCharacter used
+00528         dirtLodVertexColor();
+00529         // must recompute list of skins if was skinned
+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         // disable interpolation?
+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         // Update Lod, and animate.
+00571         //===============
+00572 
+00573         /*
+00574                 CTransformAnimDetailObs::traverse() is torn in 2 here because 
+00575                 channels may be enabled/disabled by updateBoneToCompute()
+00576         */
+00577 
+00578         // First update Skeleton WorldMatrix (case where the skeleton is sticked).
+00579         CTransformAnimDetailObs::updateWorldMatrixFromFather();
+00580         // get dist from camera.
+00581         float   dist= (HrcObs->WorldMatrix.getPos() - ((CClipTrav*)ClipObs->Trav)->CamPos).norm();
+00582         // Use dist to get current lod to use for this skeleton
+00583         uint    newLod= skeShape->getLodForDistance( dist );
+00584         if(newLod != sm->_CurLod)
+00585         {
+00586                 // set new lod to use.
+00587                 sm->_CurLod= newLod;
+00588                 // dirt the skeleton.
+00589                 sm->_BoneToComputeDirty= true;
+00590         }
+00591 
+00592         // If needed, let's know which bone has to be computed, and enable / disable (lod) channels in channelMixer.
+00593         bool forceUpdate= sm->_BoneToComputeDirty;
+00594         sm->updateBoneToCompute();
+00595 
+00596         // Animate skeleton.
+00597         CTransformAnimDetailObs::traverseWithoutUpdateWorldMatrix(caller);
+00598 
+00599 
+00600         // Prepare Lod Bone interpolation.
+00601         //===============
+00602 
+00603         float   lodBoneInterp;
+00604         const CSkeletonShape::CLod      *lodNext= NULL;
+00605         // if a lod exist after current lod, and if lod interpolation enabled
+00606         if( sm->_CurLod < skeShape->getNumLods()-1 && sm->_LodInterpMultiplier>0 )
+00607         {
+00608                 // get next lod.
+00609                 lodNext= &skeShape->getLod(sm->_CurLod+1);
+00610                 // get interp value to next.
+00611                 lodBoneInterp= (lodNext->Distance - dist) * sm->_LodInterpMultiplier;
+00612                 NLMISC::clamp(lodBoneInterp, 0.f, 1.f);
+00613                 // if still 1, keep cur matrix => disable interpolation
+00614                 if(lodBoneInterp==1.f)
+00615                         lodNext=NULL;
+00616         }
+00617         // else, no interpolation
+00618         else
+00619         {
+00620                 lodBoneInterp=1.f;
+00621         }
+00622         // If the interpolation value is different from last one, must update.
+00623         if(lodBoneInterp != sm->_CurLodInterp)
+00624         {
+00625                 // set new one.
+00626                 sm->_CurLodInterp= lodBoneInterp;
+00627                 // must update bone compute.
+00628                 forceUpdate= true;
+00629         }
+00630 
+00631 
+00632 
+00633         // Compute bones
+00634         //===============
+00635 
+00636         // test if bones must be updated. either if animation change or if BoneUsage change.
+00637         if(sm->IAnimatable::isTouched(CSkeletonModel::OwnerBit) || forceUpdate)
+00638         {
+00639                 // Retrieve the WorldMatrix of the current CTransformShape.
+00640                 CMatrix         &modelWorldMatrix= HrcObs->WorldMatrix;
+00641 
+00642                 // must test / update the hierarchy of Bones.
+00643                 // Since they are orderd in depth-first order, we are sure that parent are computed before sons.
+00644                 uint                                                    numBoneToCompute= sm->_BoneToCompute.size();
+00645                 CSkeletonModel::CBoneCompute    *pBoneCompute= numBoneToCompute? &sm->_BoneToCompute[0] : NULL;
+00646                 // traverse only bones which need to be computed
+00647                 for(;numBoneToCompute>0;numBoneToCompute--, pBoneCompute++)
+00648                 {
+00649                         // compute the bone with his father, if any
+00650                         pBoneCompute->Bone->compute( pBoneCompute->Father, modelWorldMatrix);
+00651 
+00652                         // Lod interpolation on this bone .. only if interp is enabled now, and if bone wants it
+00653                         if(lodNext && pBoneCompute->MustInterpolate)
+00654                         {
+00655                                 // interpolate with my father matrix.
+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         // Sticked Objects: 
+00665         // they will update their WorldMatrix after, because of the AnimDetail traverse scheme:
+00666         // traverse visible ClipObs, and if skeleton, traverse Hrc sons.
+00667 
+00668 
+00669         // Update Animated Skins.
+00670         //===============
+00671         for(uint i=0;i<sm->_AnimDetailSkins.size();i++)
+00672         {
+00673                 // get the detail Obs, via the clipObs
+00674                 CTransformAnimDetailObs         *adObs;
+00675                 adObs= safe_cast<CTransformAnimDetailObs*>(sm->_AnimDetailSkins[i]->_ClipObs->AnimDetailObs);
+00676 
+00677                 // traverse it. NB: updateWorldMatrixFromFather() is called but no-op because isSkinned()
+00678                 adObs->traverse(NULL);
+00679         }
+00680 
+00681 }
+00682 
+00683 
+00684 // ***************************************************************************
+00685 void            CSkeletonModel::computeAllBones(const CMatrix &modelWorldMatrix)
+00686 {
+00687         // must test / update the hierarchy of Bones.
+00688         // Since they are orderd in depth-first order, we are sure that parent are computed before sons.
+00689         for(uint i=0;i<Bones.size();i++)
+00690         {
+00691                 sint    fatherId= Bones[i].getFatherId();
+00692                 // if a root bone...
+00693                 if(fatherId==-1)
+00694                         // Compute root bone worldMatrix.
+00695                         Bones[i].compute( NULL, modelWorldMatrix);
+00696                 else
+00697                         // Compute bone worldMatrix.
+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         // get a ptr on the scene which owns us, and so on the lodManager.
+00718         CScene                                  *scene= static_cast<CScene*>(_OwnerMot);
+00719         CLodCharacterManager    *mngr= scene->getLodCharacterManager();
+00720 
+00721         // if mngr not setuped, noop (lod not possible).
+00722         if(!mngr)
+00723                 return;
+00724 
+00725         // If a shape was setup, free the instance
+00726         if(_CLodInstance.ShapeId>=0)
+00727         {
+00728                 mngr->releaseInstance(_CLodInstance);
+00729                 _CLodInstance.ShapeId= -1;
+00730         }
+00731 
+00732         // assign
+00733         _CLodInstance.ShapeId= shapeId;
+00734 
+00735         // if a real shape is setuped, alloc an instance
+00736         if(_CLodInstance.ShapeId>=0)
+00737         {
+00738                 mngr->initInstance(_CLodInstance);
+00739         }
+00740 }
+00741 
+00742 
+00743 // ***************************************************************************
+00744 void            CSkeletonModel::computeLodTexture()
+00745 {
+00746         // is lod setuped
+00747         if(_CLodInstance.ShapeId<0)
+00748                 return;
+00749 
+00750         // get a ptr on the scene which owns us, and so on the lodManager.
+00751         CScene                                  *scene= static_cast<CScene*>(_OwnerMot);
+00752         CLodCharacterManager    *mngr= scene->getLodCharacterManager();
+00753         // mngr must be setuped since shape Id is >-1
+00754         nlassert(mngr);
+00755         /* Get the asyncTextureManager. This is a Hack. We use the AsyncTextureManager to store very low version of Textures
+00756                 (kept in DXTC1 format for minimum memory overhead).
+00757                 HENCE Lod Texture can work only with Async Textured instances!!
+00758         */
+00759         CAsyncTextureManager    *asyncMngr= scene->getAsyncTextureManager();
+00760         // if not setuped, cancel
+00761         if(!asyncMngr)
+00762                 return;
+00763 
+00764 
+00765         // **** start process. If cannot (TextureId==no more texture space), just quit.
+00766         if(!mngr->startTextureCompute(_CLodInstance))
+00767                 return;
+00768         uint maxNumBmpToReset= 0;
+00769 
+00770         // **** For all skins which have a LodTexture setuped
+00771         ItTransformSet  it= _Skins.begin();
+00772         for(;it!=_Skins.end();it++)
+00773         {
+00774                 // the skin should be a meshBaseInstance setuped to asyncTexturing
+00775                 CMeshBaseInstance       *mbi= dynamic_cast<CMeshBaseInstance*>(*it);
+00776                 if(mbi && mbi->getAsyncTextureMode() && mbi->Shape)
+00777                 {
+00778                         CMeshBase       *mb= (CMeshBase*)(IShape*)(mbi->Shape);
+00779                         // get the LodTexture info of this shape.
+00780                         const CLodCharacterTexture      *lodText= mb->getLodCharacterTexture();
+00781                         // if setuped
+00782                         if(lodText)
+00783                         {
+00784                                 // Ok, compute influence of this instance on the Lod.
+00785 
+00786                                 // ---- Build all bmps of the instance with help of the asyncTextureManager
+00787                                 uint    numMats= mbi->Materials.size();
+00788                                 // 256 materials possibles for the lod Manager
+00789                                 numMats= min(numMats, 256U);
+00790                                 // for endTexturecompute
+00791                                 maxNumBmpToReset= max(maxNumBmpToReset, numMats);
+00792                                 // process each materials
+00793                                 for(uint i=0;i<numMats;i++)
+00794                                 {
+00795                                         // get the manager bitmap to write to
+00796                                         CLodCharacterTmpBitmap  &dstBmp= mngr->getTmpBitmap(i);
+00797 
+00798                                         // if the material stage 0 is not textured, or has not a valid async id, build the bitmap with a color.
+00799                                         sint                    asyncTextId= mbi->getAsyncTextureId(i,0);
+00800                                         const CBitmap   *coarseBitmap= NULL;
+00801                                         if(asyncTextId!=-1)
+00802                                         {
+00803                                                 // get it from async manager
+00804                                                 coarseBitmap= asyncMngr->getCoarseBitmap(asyncTextId);
+00805                                         }
+00806 
+00807                                         // So if we have no bmp here, build with material color, else build a texture
+00808                                         if(!coarseBitmap)
+00809                                         {
+00810                                                 dstBmp.build(mbi->Materials[i].getDiffuse());
+00811                                         }
+00812                                         else
+00813                                         {
+00814                                                 dstBmp.build(*coarseBitmap);
+00815                                         }
+00816                                 }
+00817 
+00818                                 // ---- add the lodTextureInfo to the current texture computed
+00819                                 mngr->addTextureCompute(_CLodInstance, *lodText);
+00820                         }
+00821                 }
+00822         }
+00823 
+00824         // **** compile the process
+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         // if enabled
+00853         if(_LodCharacterDistance>0 && _CLodInstance.ShapeId>=0)
+00854         {
+00855                 CVector         globalPos;
+00856                 /* \todo yoyo: bad test of visibility. If the skeleton is hidden but has a _AncestorSkeletonModel 
+00857                         wich is visible, then it is supposed to be visible (in this test), but only for The CLod LoadBalancing 
+00858                         (priority not 0). Not so important...
+00859                 */
+00860 
+00861                 // Get object position, test visibility;
+00862                 // If has a skeleton ancestor, take his world position instead, because ours is invalid.
+00863                 if( _HrcObs->_AncestorSkeletonModel != NULL)
+00864                 {
+00865                         // if the ancestore is clipped, quit
+00866                         if( !_HrcObs->_AncestorSkeletonModel->isClipVisible() )
+00867                                 return 0;
+00868                         // take ancestor world position
+00869                         globalPos= _HrcObs->_AncestorSkeletonModel->getWorldMatrix().getPos();
+00870                 }
+00871                 else
+00872                 {
+00873                         // if the skeleton is clipped, quit
+00874                         if( !isClipVisible() )
+00875                                 return 0;
+00876                         // take our world position
+00877                         globalPos= _HrcObs->WorldMatrix.getPos();
+00878                 }
+00879 
+00880                 // compute distance from camera.
+00881                 float   dist= (ClipTrav->CamPos - globalPos).norm();
+00882 
+00883                 // compute priority
+00884                 return dist*_OOLodCharacterDistance;
+00885         }
+00886         else
+00887                 return 0;
+00888 }
+00889 
+00890 
+00891 // ***************************************************************************
+00892 void            CSkeletonModel::setDisplayLodCharacterFlag(bool displayCLod)
+00893 {
+00894         // if enabled
+00895         if(_LodCharacterDistance>0 && _CLodInstance.ShapeId>=0)
+00896         {
+00897                 // If the flag has changed since last frame, must recompute bone Usage.
+00898                 if(_DisplayedAsLodCharacter != displayCLod)
+00899                         _BoneToComputeDirty= true;
+00900 
+00901                 // set new state
+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         // render as CLod, or render Skins.
+00915         if(sm->isDisplayedAsLodCharacter())
+00916                 renderCLod();
+00917         else
+00918                 renderSkins();
+00919 }
+00920 
+00921 
+00922 // ***************************************************************************
+00923 void                    CSkeletonModel::computeCLodVertexColors(CLodCharacterManager *mngr)
+00924 {
+00925         // if shape id set.
+00926         if(_CLodInstance.ShapeId<0)
+00927                 return;
+00928         // get the lod shape,a nd check exist in the manager
+00929         const CLodCharacterShape        *lodShape= mngr->getShape(_CLodInstance.ShapeId);
+00930         if(lodShape)
+00931         {
+00932                 static vector<CRGBAF>   tmpColors;
+00933                 tmpColors.clear();
+00934 
+00935                 // start process.
+00936                 //-----------------
+00937                 lodShape->startBoneColor(tmpColors);
+00938 
+00939                 // build an Id map, from Skeleton Ids to the lodShapes ids. (because may be differents)
+00940                 static vector<sint>     boneMap;
+00941                 // reset to -1 (ie not found)
+00942                 boneMap.clear();
+00943                 boneMap.resize(Bones.size(), -1);
+00944                 uint i;
+00945                 // for all skeletons bones.
+00946                 for(i=0; i<boneMap.size(); i++)
+00947                 {
+00948                         boneMap[i]= lodShape->getBoneIdByName(Bones[i].getBoneName());;
+00949                 }
+00950 
+00951                 // Parse all skins
+00952                 //-----------------
+00953                 ItTransformSet  it;
+00954                 for(it= _Skins.begin(); it!=_Skins.end(); it++)
+00955                 {
+00956                         CTransform      *skin= *it;
+00957 
+00958                         // get color of this skin.
+00959                         CRGBA   color= skin->getMeanColor();
+00960 
+00961                         // get array of bone used for this skin.
+00962                         const vector<sint32>    *skinUsage= skin->getSkinBoneUsage();
+00963                         // check correct skin
+00964                         if(skinUsage)
+00965                         {
+00966                                 // For all bones used
+00967                                 for(uint i=0; i<skinUsage->size(); i++)
+00968                                 {
+00969                                         // the id in the vector point to a bone in the skeleton. Hence use the boneMap to translate it
+00970                                         // in the lodShape ids.
+00971                                         sint    idInLod= boneMap[(*skinUsage)[i]];
+00972                                         // only if id found in the lod shape
+00973                                         if(idInLod>=0)
+00974                                                 // add color to this bone.
+00975                                                 lodShape->addBoneColor(idInLod, color, tmpColors);
+00976                                 }
+00977 
+00978                         }
+00979                 }
+00980 
+00981                 // Parse all sticked objects
+00982                 //-----------------
+00983                 for(it= _StickedObjects.begin(); it!=_StickedObjects.end(); it++)
+00984                 {
+00985                         CTransform      *object= *it;
+00986 
+00987                         // get color of this object.
+00988                         CRGBA   color= object->getMeanColor();
+00989 
+00990                         // get on which bone this object is linked.
+00991                         // use the boneMap to translate id to lodShape id.
+00992                         sint    idInLod= boneMap[object->_FatherBoneId];
+00993 
+00994                         // only if id found in the lod shape
+00995                         if(idInLod>=0)
+00996                                 // add color to this bone.
+00997                                 lodShape->addBoneColor(idInLod, color, tmpColors);
+00998                 }
+00999 
+01000 
+01001                 // compile colors
+01002                 //-----------------
+01003                 lodShape->endBoneColor(tmpColors, _CLodInstance.VertexColors);
+01004         }
+01005 
+01006 }
+01007 
+01008 
+01009 // ***************************************************************************
+01010 void                    CSkeletonModel::updateSkinRenderLists()
+01011 {
+01012         // If need to update array of skins to compute
+01013         if(_SkinToRenderDirty)
+01014         {
+01015                 _SkinToRenderDirty= false;
+01016 
+01017                 // Reset the LevelDetail.
+01018                 _LevelDetail.MinFaceUsed= 0;
+01019                 _LevelDetail.MaxFaceUsed= 0;
+01020                 // If must follow default MRM setup from skins.
+01021                 if(_DefaultMRMSetup)
+01022                 {
+01023                         _LevelDetail.DistanceCoarsest= 0;
+01024                         _LevelDetail.DistanceMiddle= 0;
+01025                         _LevelDetail.DistanceFinest= 0;
+01026                 }
+01027 
+01028                 // Parse to count new size of the arrays, and to build MRM info
+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                         // if transparent, then must fill in transparent list.
+01037                         if(skin->isTransparent())
+01038                                 transparentSize++;
+01039                         // else may fill in opaquelist. NB: for optimisation, don't add in opaqueList 
+01040                         // if added to the transperent list (all materials are rendered)
+01041                         else if(skin->isOpaque())
+01042                                 opaqueSize++;
+01043 
+01044                         // if animDetailable, then must fill list
+01045                         if(skin->isAnimDetailable())
+01046                                 animDetailSize++;
+01047 
+01048                         // if the skin support MRM, then must update levelDetal number of faces
+01049                         CTransformShape         *trShape= dynamic_cast<CTransformShape*>(skin);
+01050                         if(trShape)
+01051                         {
+01052                                 const   CMRMLevelDetail         *skinLevelDetail= trShape->getMRMLevelDetail();
+01053                                 if(skinLevelDetail)
+01054                                 {
+01055                                         // Add Faces to the Skeleton level detail
+01056                                         _LevelDetail.MinFaceUsed+= skinLevelDetail->MinFaceUsed;
+01057                                         _LevelDetail.MaxFaceUsed+= skinLevelDetail->MaxFaceUsed;
+01058                                         // MRM Max skin setup.
+01059                                         if(_DefaultMRMSetup)
+01060                                         {
+01061                                                 // Get the maximum distance setup (ie the one which degrades the less)
+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                 // MRM Max skin setup.
+01071                 if(_DefaultMRMSetup)
+01072                 {
+01073                         // compile LevelDetail.
+01074                         if(_LevelDetail.MaxFaceUsed==0)
+01075                                 // build a bug-free level detail
+01076                                 buildDefaultLevelDetail();
+01077                         else
+01078                                 _LevelDetail.compileDistanceSetup();
+01079                 }
+01080 
+01081                 // alloc array.
+01082                 _OpaqueSkins.clear();
+01083                 _TransparentSkins.clear();
+01084                 _AnimDetailSkins.clear();
+01085                 _OpaqueSkins.resize(opaqueSize);
+01086                 _TransparentSkins.resize(transparentSize);
+01087                 _AnimDetailSkins.resize(animDetailSize);
+01088 
+01089                 // ReParse, to fill array.
+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                         // if transparent, then must fill in transparent list.
+01097                         if(skin->isTransparent())
+01098                         {
+01099                                 nlassert(transparentId<transparentSize);
+01100                                 _TransparentSkins[transparentId++]= skin;
+01101                         }
+01102                         // else may fill in opaquelist. NB: for optimisation, don't add in opaqueList 
+01103                         // if added to the transperent list (all materials are rendered)
+01104                         else if(skin->isOpaque())
+01105                         {
+01106                                 nlassert(opaqueId<opaqueSize);
+01107                                 _OpaqueSkins[opaqueId++]= skin;
+01108                         }
+01109 
+01110                         // if animDetailable, then must fill list
+01111                         if(skin->isAnimDetailable())
+01112                         {
+01113                                 nlassert(animDetailId<animDetailSize);
+01114                                 _AnimDetailSkins[animDetailId++]= skin;
+01115                         }
+01116                 }
+01117 
+01118                 // set the Transparency to the skeleton only if has at least one transparent skin
+01119                 setTransparency( transparentSize>0 );
+01120         }
+01121 }
+01122 
+01123 
+01124 // ***************************************************************************
+01125 void                    CSkeletonModel::buildDefaultLevelDetail()
+01126 {
+01127         // Avoid divide by zero.
+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         // the lod manager. no op if not here
+01145         CLodCharacterManager    *mngr= trav->Scene->getLodCharacterManager();
+01146         if(!mngr)
+01147                 return;
+01148 
+01149         // Get global lighting on the instance. Suppose SunAmbient only.
+01150         //=================
+01151         const CLightContribution        *lightContrib;
+01152         // Get HrcObs.
+01153         CTransformHrcObs        *hrcObs= (CTransformHrcObs*)HrcObs;
+01154 
+01155         // the std case is to take my model lightContribution
+01156         if(hrcObs->_AncestorSkeletonModel==NULL)
+01157                 lightContrib= &sm->getSkeletonLightContribution();
+01158         // but if skinned/sticked (directly or not) to a skeleton, take its.
+01159         else
+01160                 lightContrib= &hrcObs->_AncestorSkeletonModel->getSkeletonLightContribution();
+01161 
+01162         // compute his main light contribution result. Try first with sun
+01163         CRGBA   mainAmbient= scene->getSunAmbient();
+01164         CRGBA   mainDiffuse= scene->getSunDiffuse();
+01165         // modulate sun contribution
+01166         mainDiffuse.modulateFromuiRGBOnly(mainDiffuse, lightContrib->SunContribution );
+01167         CVector mainLightDir= scene->getSunDirection();
+01168 
+01169 
+01170         /* During night, and in the buildings, it may be better to use one of the other Points lights
+01171                 Test only with the first pointLight, for faster compute, even if It may fail in some cases.
+01172         */
+01173         CPointLight     *mainPL= lightContrib->PointLight[0];
+01174         if(mainPL)
+01175         {
+01176                 CRGBA   plDiffuse;
+01177                 // get the diffuse of the pointLight, attenuated from distance and importance.
+01178                 plDiffuse.modulateFromuiRGBOnly(mainPL->getDiffuse(), lightContrib->AttFactor[0]);
+01179                 // compare the 2 diffuse
+01180                 uint    d0= mainDiffuse.R + mainDiffuse.G + mainDiffuse.B;
+01181                 uint    d1= plDiffuse.R + plDiffuse.G + plDiffuse.B;
+01182                 // if the pointLight is lighter, take it.
+01183                 if(d1>d0)
+01184                 {
+01185                         // leave ambient, but take diffuse and pointLight fake Direction
+01186                         mainDiffuse= plDiffuse;
+01187                         mainLightDir= hrcObs->WorldMatrix.getPos() - mainPL->getPosition();
+01188                         mainLightDir.normalize();
+01189                 }
+01190         }
+01191 
+01192 
+01193         // compute colors of the lods.
+01194         //=================
+01195         // NB: even if texturing is sufficient, still important for AlphaTest.
+01196 
+01197         // If must recompute color because of change of skin color or if skin added/deleted
+01198         if(sm->_CLodVertexColorDirty)
+01199         {
+01200                 // recompute vertex colors
+01201                 sm->computeCLodVertexColors(mngr);
+01202                 // set sm->_CLodVertexColorDirty to false.
+01203                 sm->_CLodVertexColorDirty= false;
+01204         }
+01205 
+01206         // render the Lod in the LodManager.
+01207         //=================
+01208         // render must have been intialized
+01209         nlassert(mngr->isRendering());
+01210 
+01211 
+01212         // add the instance to the manager. 
+01213         if(!mngr->addRenderCharacterKey(sm->_CLodInstance, hrcObs->WorldMatrix, 
+01214                 mainAmbient, mainDiffuse, mainLightDir) )
+01215         {
+01216                 // If failed to add it because no more vertex space in the manager, retry.
+01217 
+01218                 // close vertexBlock, compile render
+01219                 mngr->endRender();
+01220                 // and restart.
+01221                 mngr->beginRender(drv, trav->CamPos);
+01222 
+01223                 // retry. but no-op if refail.
+01224                 mngr->addRenderCharacterKey(sm->_CLodInstance, hrcObs->WorldMatrix, 
+01225                         mainAmbient, mainDiffuse, mainLightDir);
+01226         }
+01227 }
+01228 
+01229 
+01230 // ***************************************************************************
+01231 void                    CSkeletonModelRenderObs::renderSkins()
+01232 {
+01233         // Render skins according to the pass.
+01234         CRenderTrav                     *rdrTrav= (CRenderTrav*)Trav;
+01235         CSkeletonModel          *sm= (CSkeletonModel*)Model;
+01236         CTransformHrcObs        *hrcObs= (CTransformHrcObs*)HrcObs;
+01237         // get a ptr on the driver
+01238         IDriver                         *drv= rdrTrav->getDriver();
+01239         nlassert(drv);
+01240 
+01241 
+01242         // Compute the levelOfDetail
+01243         float   alphaMRM= sm->_LevelDetail.getLevelDetailFromPolyCount(sm->getNumTrianglesAfterLoadBalancing());
+01244 
+01245         // force normalisation of normals..
+01246         bool    bkupNorm= drv->isForceNormalize();
+01247         drv->forceNormalize(true);                      
+01248 
+01249 
+01250         // rdr good pass
+01251         if(rdrTrav->isCurrentPassOpaque())
+01252         {
+01253                 // Compute in Pass Opaque only the light contribution. 
+01254                 // Easier for skeleton: suppose lightable, no local attenuation
+01255 
+01256                 // the std case is to take my model lightContribution
+01257                 if(hrcObs->_AncestorSkeletonModel==NULL)
+01258                         sm->setupCurrentLightContribution(&sm->_LightContribution, false);
+01259                 // but if sticked (directly or not) to a skeleton, take its.
+01260                 else
+01261                         sm->setupCurrentLightContribution(&hrcObs->_AncestorSkeletonModel->_LightContribution, false);
+01262 
+01263 
+01264                 // Activate Driver setup: light and modelMatrix
+01265                 sm->changeLightSetup( rdrTrav );
+01266                 rdrTrav->getDriver()->setupModelMatrix(hrcObs->WorldMatrix);
+01267 
+01268 
+01269                 // Render all totaly opaque skins.
+01270                 renderSkinList(sm->_OpaqueSkins, alphaMRM);
+01271         }
+01272         else
+01273         {
+01274                 // NB: must have some transparent skins, since thee skeletonModel is traversed in the transparent pass.
+01275 
+01276                 // Activate Driver setup: light and modelMatrix
+01277                 sm->changeLightSetup( rdrTrav );
+01278                 rdrTrav->getDriver()->setupModelMatrix(hrcObs->WorldMatrix);
+01279 
+01280 
+01281                 // render all opaque/transparent skins
+01282                 renderSkinList(sm->_TransparentSkins, alphaMRM);
+01283         }
+01284 
+01285 
+01286         // bkup force normalisation.
+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         // if the SkinManager is not possible at all, just rendered the std way
+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                 // get the meshSkinManager
+01307                 CMeshSkinManager        &meshSkinManager= *rdrTrav->getMeshSkinManager();
+01308 
+01309                 // array (rarely allocated) of skins with grouping support
+01310                 static  std::vector<CTransform*>        skinsToGroup;
+01311                 static  std::vector<uint>                       baseVertices;
+01312                 skinsToGroup.clear();
+01313                 baseVertices.clear();
+01314 
+01315                 // get the maxVertices the manager support
+01316                 uint    maxVertices= meshSkinManager.getMaxVertices();
+01317                 uint    vertexSize= meshSkinManager.getVertexSize();
+01318 
+01319                 // render any skins which do not support SkinGrouping, and fill array of skins to group
+01320                 for(uint i=0;i<skinList.size();i++)
+01321                 {
+01322                         // If don't support, or if too big to fit in the manager, just renderSkin()
+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                 // For each skin, have an index which gives the decal of the vertices in the buffer
+01337                 baseVertices.resize(skinsToGroup.size());
+01338 
+01339                 // while there is skin to render in group
+01340                 uint    skinId= 0;
+01341                 while(skinId<skinsToGroup.size())
+01342                 {
+01343                         // space left in the manager
+01344                         uint    remainingVertices= maxVertices;
+01345                         uint    currentBaseVertex= 0;
+01346 
+01347                         // First pass, fill The VB.
+01348                         //------------
+01349                         // lock buffer
+01350                         uint8   *vbDest= meshSkinManager.lock();
+01351 
+01352                         // For all skins until the buffer is full
+01353                         uint    startSkinId= skinId;
+01354                         while(skinId<skinsToGroup.size())
+01355                         {
+01356                                 // if success to fill the AGP
+01357                                 sint    numVerticesAdded= skinsToGroup[skinId]->renderSkinGroupGeom(alphaMRM, remainingVertices, 
+01358                                         vbDest + vertexSize*currentBaseVertex );
+01359                                 // -1 means that this skin can't render because no space left for her. Then stop for this block
+01360                                 if(numVerticesAdded==-1)
+01361                                         break;
+01362                                 // Else ok, get the currentBaseVertex for this skin
+01363                                 baseVertices[skinId]= currentBaseVertex;
+01364                                 // and jump to the next place
+01365                                 currentBaseVertex+= numVerticesAdded;
+01366                                 remainingVertices-= numVerticesAdded;
+01367 
+01368                                 // go to the next skin
+01369                                 skinId++;
+01370                         }
+01371 
+01372                         // release buffer. ATI: release only vertices used.
+01373                         meshSkinManager.unlock(currentBaseVertex);
+01374 
+01375                         // Second pass, render the primitives.
+01376                         //------------
+01377                         meshSkinManager.activate();
+01378                         for(uint i=startSkinId;i<skinId;i++)
+01379                         {
+01380                                 // render the skin in the current buffer
+01381                                 skinsToGroup[i]->renderSkinGroupPrimitives(baseVertices[i]);
+01382                         }
+01383 
+01384 
+01385                         // End of this block, swap to the next buffer
+01386                         meshSkinManager.swapVBHard();
+01387                 }
+01388         }
+01389 }
+01390 
+01391 
+01392 // ***************************************************************************
+01393 float                   CSkeletonModel::getNumTriangles (float distance)
+01394 {
+01395         // If the skeleton is displayed as a CLod suppose 0 triangles.
+01396         if( isDisplayedAsLodCharacter() )
+01397                 return 0;
+01398         else
+01399                 // NB: this is an approximation, but this is continious.
+01400                 return _LevelDetail.getNumTriangles(distance);
+01401 }
+01402 
+01403 // ***************************************************************************
+01404 void                    CSkeletonModel::changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest)
+01405 {
+01406         // check input.
+01407         if(distanceFinest<0)    return;
+01408         if(distanceMiddle<=distanceFinest)      return;
+01409         if(distanceCoarsest<=distanceMiddle)    return;
+01410 
+01411         // Change.
+01412         _LevelDetail.DistanceFinest= distanceFinest;
+01413         _LevelDetail.DistanceMiddle= distanceMiddle;
+01414         _LevelDetail.DistanceCoarsest= distanceCoarsest;
+01415 
+01416         // compile 
+01417         _LevelDetail.compileDistanceSetup();
+01418 
+01419         // Never more use MAX skin setup.
+01420         _DefaultMRMSetup= false;
+01421 }
+01422 
+01423 
+01424 // ***************************************************************************
+01425 void                    CSkeletonModel::resetDefaultMRMDistanceSetup()
+01426 {
+01427         _DefaultMRMSetup= true;
+01428 
+01429         // Must use Skins linked to know the MRM setup.
+01430         dirtSkinRenderLists();
+01431 }
+01432 
+01433 
+01434 // ***************************************************************************
+01435 bool                    CSkeletonModel::computeRenderedBBox(NLMISC::CAABBox &bbox)
+01436 {
+01437         // reset bbox
+01438         CAABBox         tmpBBox;
+01439         tmpBBox.setCenter(CVector::Null);
+01440         tmpBBox.setHalfSize(CVector::Null);
+01441         bool    empty= true;
+01442 
+01443         // Not visible => empty bbox
+01444         if(!getLastClippedState())
+01445                 return false;
+01446 
+01447         // For all bones
+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         // End!
+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 /* = false*/)
+01477 {
+01478         // animate all bones channels (detail only channels). don't bother cur lod state.
+01479         CChannelMixer   *chanmix= getChannelMixer();
+01480         if (chanmix)
+01481         {       
+01482                 // Force detail evaluation.
+01483                 chanmix->resetEvalDetailDate();
+01484                 chanmix->eval(true, 0);
+01485                 chanmix->resetEvalDetailDate();
+01486         }
+01487         // compute all skeleton bones
+01488         computeAllBones(CMatrix::Identity);
+01489 
+01490         // reset bbox
+01491         CAABBox         tmpBBox;
+01492         tmpBBox.setCenter(CVector::Null);
+01493         tmpBBox.setHalfSize(CVector::Null);
+01494         bool    empty= true;
+01495 
+01496         // For all bones
+01497         uint    i;
+01498         for(i=0;i<Bones.size();i++)
+01499         {
+01500                 // Is the bone used ?? (whatever bone lod, or CLod state)
+01501                 uint8   mustCompute = forceCompute ? 1 : _BoneUsage[i].Usage | _BoneUsage[i].ForcedUsage | _BoneUsage[i].CLodForcedUsage;
+01502 
+01503                 // If the bone is used.
+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         // End!
+01518         if(!empty)
+01519         {
+01520                 bbox= tmpBBox;
+01521                 return true;
+01522         }
+01523         else
+01524                 return false;
+01525 }
+01526 
+01527 
+01528 } // NL3D
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1