# 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  

transform.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 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 "3d/transform.h"
00029 #include "3d/skeleton_model.h"
00030 #include "3d/skip_model.h"
00031 #include "3d/scene.h"
00032 #include "3d/root_model.h"
00033 #include "3d/fast_floor.h"
00034 
00035 
00036 using namespace NLMISC;
00037 
00038 
00039 namespace       NL3D
00040 {
00041 
00042 
00043 // ***************************************************************************
00044 void    CTransform::registerBasic()
00045 {
00046         CMOT::registerModel( TransformId, 0, CTransform::creator);
00047         CMOT::registerObs( HrcTravId,                   TransformId, CTransformHrcObs::creator                  );
00048         CMOT::registerObs( ClipTravId,                  TransformId, CTransformClipObs::creator                 );
00049         CMOT::registerObs( AnimDetailTravId,    TransformId, CTransformAnimDetailObs::creator   );
00050         CMOT::registerObs( LightTravId,                 TransformId, CTransformLightObs::creator                );
00051         CMOT::registerObs( RenderTravId,                TransformId, CTransformRenderObs::creator               );
00052 }
00053 
00054 
00055 // ***************************************************************************
00056 CTransform::CTransform()
00057 {
00058         _HrcObs= NULL;
00059         _ClipObs= NULL;
00060         _LightObs=NULL;
00061 
00062         TouchObs.resize(Last);
00063 
00064         Visibility= CHrcTrav::Herit;
00065 
00066         _LastTransformableMatrixDate= 0;
00067 
00068         _FatherSkeletonModel= NULL;
00069 
00070         _ClusterSystem = NULL;
00071 
00072         _FreezeHRCState= FreezeHRCStateDisabled;
00073 
00074         _OrderingLayer = 0;
00075 
00076         
00077         // No logicInfo by default
00078         _LogicInfo= NULL;
00079 
00080         _ForceCLodSticked= false;
00081 
00082         // default MeanColor value
00083         _MeanColor.set(255,255,255,255);
00084 
00085 
00086         // Setup some state.
00087 
00088         /*
00089                 Default are:
00090                         IsAnimDetailable= 0
00091                         IsLoadBalancable= 0
00092                         IsLightable= 0
00093                         IsRenderable= 0
00094                         IsTransparent= 0
00095                         IsOpaque= 1
00096                         QuadGridClipEnabled= 0.
00097 
00098                         IsUserLightable= 1                      // default, the model may be lighted.
00099                         IsFinalLightable= 0
00100                         IsNeedUpdateLighting= 0
00101                         ISNeedUpdateFrozenStaticLightSetup= 0
00102 
00103                         IsSkeleton= 0
00104 
00105                         IsDeleteChannelMixer = 0;
00106         */
00107         _StateFlags= IsOpaque | IsUserLightable;
00108 }
00109 
00110 
00111 // ***************************************************************************
00112 void    CTransform::initModel()
00113 {
00114         IModel::initModel();
00115 
00116         _HrcObs= (CTransformHrcObs*)getObs(HrcTravId);
00117         _ClipObs= (CTransformClipObs*)getObs(ClipTravId);
00118         _LightObs= (CTransformLightObs*)getObs(LightTravId);
00119 }
00120 
00121 
00122 // ***************************************************************************
00123 CTransform::~CTransform()
00124 {
00125         // If still binded to a father skeleton
00126         if( _FatherSkeletonModel )
00127         {
00128                 /* If skinned, cannot detach me from skeleton here because detachSkeletonSon()
00129                         use some virtual calls of transform: setApplySkin().
00130                         Hence, It is the deriver job to detach himself from the skeleton.
00131 
00132                         NB: test isSkinned(), not isSkinnable(), since isSkinned() is not virtual ....
00133                         This means that if a Mesh isSkinnable(), but never skinned, it is not asserted here.
00134                 */
00135                 if( isSkinned() )
00136                 {
00137                         nlstop;
00138                 }
00139                 else
00140                         // Can detach Me. Important for UTransform sticked
00141                         _FatherSkeletonModel->detachSkeletonSon(this);
00142         }
00143 
00144         // resetLighting, removing me from PointLight Transform list.
00145         // NB: not done for FrozenStaticLightSetup, because those lights don't owns me.
00146         resetLighting();
00147 
00148         // Must also remove me from the lightingManager.
00149         // must test _LightObs because of CCluster usage out of mot (thanks to mat!! :) )
00150         if(_LightObs)
00151         {
00152                 CLightTrav      *lightTrav= (CLightTrav*)_LightObs->Trav;
00153                 _LightedModelIt= lightTrav->LightingManager.eraseStaticLightedModel(_LightedModelIt);
00154         }
00155 
00156         if (getChannelMixerOwnerShip()) delete (CChannelMixer *) _ChannelMixer;
00157 }
00158 
00159 // ***************************************************************************
00160 void            CTransform::hide()
00161 {
00162         // Optim: do nothing if already set (=> not foulTransform() -ed).
00163         if(Visibility!= CHrcTrav::Hide)
00164         {
00165                 foulTransform();
00166                 Visibility= CHrcTrav::Hide;
00167         }
00168 }
00169 // ***************************************************************************
00170 void            CTransform::show()
00171 {
00172         // Optim: do nothing if already set (=> not foulTransform() -ed).
00173         if(Visibility!= CHrcTrav::Show)
00174         {
00175                 foulTransform();
00176                 Visibility= CHrcTrav::Show;
00177         }
00178 }
00179 // ***************************************************************************
00180 void            CTransform::heritVisibility()
00181 {
00182         // Optim: do nothing if already set (=> not foulTransform() -ed).
00183         if(Visibility!= CHrcTrav::Herit)
00184         {
00185                 foulTransform();
00186                 Visibility= CHrcTrav::Herit;
00187         }
00188 }
00189 
00190 
00191 // ***************************************************************************
00192 CTrackDefaultVector             CTransform::DefaultPos( CVector::Null );
00193 CTrackDefaultVector             CTransform::DefaultRotEuler( CVector::Null );
00194 CTrackDefaultQuat               CTransform::DefaultRotQuat( NLMISC::CQuat::Identity );
00195 CTrackDefaultVector             CTransform::DefaultScale( CVector(1,1,1) );
00196 CTrackDefaultVector             CTransform::DefaultPivot( CVector::Null );
00197 
00198 ITrack* CTransform::getDefaultTrack (uint valueId)
00199 {
00200         // Cyril: prefer do it here in CTransform, because of CCamera, CLight etc... (which may not need a default value too!!)
00201 
00202         // what value ?
00203         switch (valueId)
00204         {
00205         case PosValue:                  return &DefaultPos;
00206         case RotEulerValue:             return &DefaultRotEuler;
00207         case RotQuatValue:              return &DefaultRotQuat;
00208         case ScaleValue:                return &DefaultScale;
00209         case PivotValue:                return &DefaultPivot;
00210         }
00211 
00212         // No, only ITrnasformable values!
00213         nlstop;
00214         // Deriver note: else call BaseClass::getDefaultTrack(valueId);
00215 
00216         return NULL;
00217 
00218 }
00219 
00220 // ***************************************************************************
00221 void    CTransform::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
00222 {
00223         if (getChannelMixerOwnerShip() && chanMixer != _ChannelMixer)
00224         {
00225                 delete _ChannelMixer;
00226                 setChannelMixerOwnerShip(false);
00227         }
00228 
00229         // Hey!! we are animated!!
00230         _ChannelMixer= chanMixer;
00231 
00232         // Update flag, if we must be inserted in AnimDetail
00233         setStateFlag(IsAnimDetailable, _ChannelMixer || getStateFlag(IsForceAnimDetail) );
00234 
00235         // If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
00236         if(isSkinned())
00237         {
00238                 nlassert(_FatherSkeletonModel);
00239                 _FatherSkeletonModel->dirtSkinRenderLists();
00240         }
00241 
00242         // For CTransfom, channels are not detailled.
00243         addValue(chanMixer, PosValue, OwnerBit, prefix, false);
00244         addValue(chanMixer, RotEulerValue, OwnerBit, prefix, false);
00245         addValue(chanMixer, RotQuatValue, OwnerBit, prefix, false);
00246         addValue(chanMixer, ScaleValue, OwnerBit, prefix, false);
00247         addValue(chanMixer, PivotValue, OwnerBit, prefix, false);
00248 
00249         // Deriver note: if necessary, call     BaseClass::registerToChannelMixer(chanMixer, prefix);
00250 }
00251 
00252 
00253 
00254 // ***************************************************************************
00255 void                    CTransform::updateWorldMatrixFromFather()
00256 {
00257         // If I am not skinned
00258         if(!isSkinned())
00259         {
00260                 // Compute the HRC WorldMatrix.
00261                 // if I am not sticked.
00262                 if(!_FatherSkeletonModel)
00263                 {
00264                         // get the normal father worldMatrix in Hrc.
00265                         CTransform      *fatherTransform= dynamic_cast<CTransform*>(_HrcObs->Trav->getFirstParent(this));
00266                         // if exist
00267                         if(fatherTransform)
00268                         {
00269                                 const CMatrix &parentWM= fatherTransform->_HrcObs->WorldMatrix;
00270                                 // combine worldMatrix
00271                                 _HrcObs->WorldMatrix= parentWM * _HrcObs->LocalMatrix;
00272                         }
00273                         else
00274                                 _HrcObs->WorldMatrix= _HrcObs->LocalMatrix;
00275                 }
00276                 else
00277                 {
00278                         // get the worldMatrix of the bone if I am sticked.
00279                         const CMatrix &parentWM= _FatherSkeletonModel->Bones[_FatherBoneId].getWorldMatrix();
00280                         // combine worldMatrix
00281                         _HrcObs->WorldMatrix= parentWM * _HrcObs->LocalMatrix;
00282                 }
00283         }
00284 }
00285 
00286 
00287 // ***************************************************************************
00288 void                    CTransform::freeze()
00289 {
00290         // First, validate the model, and all his observers.
00291         // Frozen state is disabled here (in CTransformHrcObs::update()).
00292         validate();
00293 
00294         // Then flag the frozen state.
00295         _HrcObs->Frozen= true;
00296 }
00297 
00298 // ***************************************************************************
00299 void                    CTransform::setDontUnfreezeChildren(bool val)
00300 {
00301         _HrcObs->DontUnfreezeChildren = val;
00302 }
00303 
00304 
00305 // ***************************************************************************
00306 const CMatrix& CTransform::getWorldMatrix()
00307 {
00308         return _HrcObs->WorldMatrix;
00309 }
00310 
00311 // ***************************************************************************
00312 bool    CTransform::getLastClippedState() const
00313 {
00314         return _ClipObs->Visible;
00315 }
00316 
00317 
00318 
00319 // ***************************************************************************
00320 void            CTransform::freezeHRC()
00321 {
00322         // if disabled, say we are ready to validate our worldMatrix for long.
00323         if(_FreezeHRCState==FreezeHRCStateDisabled)
00324         {
00325                 _FreezeHRCState= FreezeHRCStateRequest;
00326                 setStateFlag(QuadGridClipEnabled, true);
00327         }
00328 }
00329 
00330 
00331 // ***************************************************************************
00332 void            CTransform::unfreezeHRC()
00333 {
00334         // if this model is no HRC frozen disabled
00335         if(_FreezeHRCState!=FreezeHRCStateDisabled)
00336         {
00337                 // if model correctly frozen.
00338                 if(_FreezeHRCState == CTransform::FreezeHRCStateEnabled )
00339                 {
00340                         // Trick: get the traversal via the HrcObs.
00341                         CHrcTrav        *hrcTrav= static_cast<CHrcTrav*>(_HrcObs->Trav);
00342                         // if linked to SkipModelRoot, link this model to root of HRC.
00343                         if( hrcTrav->getFirstParent(this) == hrcTrav->Scene->getSkipModelRoot() )
00344                                 hrcTrav->link(NULL, this);
00345 
00346                         // Link this object to the validateList.
00347                         linkToValidateList();
00348 
00349                         // if lightable()
00350                         if( isLightable() )
00351                         {
00352                                 CLightTrav      *lightTrav= static_cast<CLightTrav*>(_LightObs->Trav);
00353                                 // Lighting: must remove the object from the quadGrid.
00354                                 // NB: works if _LightedModelIt==NULL. result is that _LightedModelIt= NULL.
00355                                 _LightedModelIt= lightTrav->LightingManager.eraseStaticLightedModel(_LightedModelIt);
00356                         }
00357 
00358                 }
00359 
00360                 _FreezeHRCState= FreezeHRCStateDisabled;
00361                 setStateFlag(QuadGridClipEnabled, false);
00362         }
00363 }
00364 
00365 
00366 // ***************************************************************************
00367 void            CTransform::update()
00368 {
00369         IModel::update();
00370 
00371         // test if the matrix has been changed in ITransformable.
00372         if(ITransformable::compareMatrixDate(_LastTransformableMatrixDate))
00373         {
00374                 _LastTransformableMatrixDate= ITransformable::getMatrixDate();
00375                 foul(TransformDirty);
00376         }
00377 
00378         // update the freezeHRC state.
00379         if(_FreezeHRCState != CTransform::FreezeHRCStateDisabled)
00380         {
00381                 // if the model request to be frozen in HRC
00382                 if(_FreezeHRCState == CTransform::FreezeHRCStateRequest )
00383                 {
00384                         // Wait for next Hrc traversal to compute good WorldMatrix for this model and his sons.
00385                         // Also, next Hrc traversal will insert the model in the LightingManager quadGrid (if lightable)
00386                         _FreezeHRCState = CTransform::FreezeHRCStateReady;
00387                 }
00388                 // if the model is ready to be frozen in HRC, then do it!!
00389                 else if( _FreezeHRCState == CTransform::FreezeHRCStateReady )
00390                 {
00391                         // Trick: get the traversal via the HrcObs.
00392                         CHrcTrav        *hrcTrav= static_cast<CHrcTrav*>(_HrcObs->Trav);
00393                         // if linked to root of HRC, link this model to SkipModelRoot.
00394                         if( hrcTrav->getFirstParent(this) == hrcTrav->getRoot() )
00395                                 hrcTrav->link(hrcTrav->Scene->getSkipModelRoot(), this);
00396 
00397                         // unLink this object from the validateList. NB: the list will still be correclty parsed.
00398                         unlinkFromValidateList();
00399 
00400                         // if lightable, the model is inserted in a quadgrid to update his lighting only when
00401                         // dynamicLights touch him (since himself is static).
00402                         if( isLightable() )
00403                         {
00404                                 CLightTrav      *lightTrav= static_cast<CLightTrav*>(_LightObs->Trav);
00405                                 // Lighting: must reinsert the object from the quadGrid.
00406                                 // NB: works if _LightedModelIt==NULL. result is that _LightedModelIt= NULL.
00407                                 _LightedModelIt= lightTrav->LightingManager.eraseStaticLightedModel(_LightedModelIt);
00408                                 // insert in the quadgrid.
00409                                 _LightedModelIt= lightTrav->LightingManager.insertStaticLightedModel(this);
00410                         }
00411 
00412                         // Now this model won't be tested for validation nor for worldMatrix update. End!!
00413                         _FreezeHRCState = CTransform::FreezeHRCStateEnabled;
00414                 }
00415         }
00416 }
00417 
00418 
00419 // ***************************************************************************
00420 void    CTransform::getAABBox(NLMISC::CAABBox &bbox) const
00421 {
00422         bbox.setCenter(CVector::Null);
00423         bbox.setHalfSize(CVector::Null);
00424 }
00425 
00426 
00427 // ***************************************************************************
00428 void    CTransform::setLoadBalancingGroup(const std::string &group)
00429 {
00430         // get the LoadBalancing observer
00431         IBaseLoadBalancingObs   *obs= (IBaseLoadBalancingObs*)getObs(LoadBalancingTravId);
00432         nlassert(obs);
00433 
00434         // Get the traversal.
00435         CLoadBalancingTrav      *trav= (CLoadBalancingTrav*)obs->Trav;
00436         nlassert(trav);
00437         // get the group from trav (create if needed), and set it.
00438         obs->LoadBalancingGroup= trav->getOrCreateGroup(group);
00439 }
00440 
00441 
00442 // ***************************************************************************
00443 const std::string &CTransform::getLoadBalancingGroup() const
00444 {
00445         // get the LoadBalancing observer
00446         IBaseLoadBalancingObs   *obs= (IBaseLoadBalancingObs*)getObs(LoadBalancingTravId);
00447         nlassert(obs);
00448 
00449         // get the group name
00450         return obs->LoadBalancingGroup->Name;
00451 }
00452 
00453 
00454 // ***************************************************************************
00455 void            CTransform::setMeanColor(CRGBA color)
00456 {
00457         // if the color is different from prec
00458         if(color!=_MeanColor)
00459         {
00460                 // change it.
00461                 _MeanColor= color;
00462                 // if skinned or sticked to a skeleton model.
00463                 if(_FatherSkeletonModel)
00464                 {
00465                         // must dirt the vertex color of the lod skeleton because some object color has changed
00466                         _FatherSkeletonModel->dirtLodVertexColor();
00467                 }
00468         }
00469 }
00470 
00471 
00472 // ***************************************************************************
00473 void            CTransform::setIsLightable(bool val)
00474 {
00475         setStateFlag(IsLightable, val);
00476         // update IsFinalLightable
00477         setStateFlag(IsFinalLightable, (getStateFlag(IsLightable) && getStateFlag(IsUserLightable)) );
00478 }
00479 // ***************************************************************************
00480 void            CTransform::setUserLightable(bool enable)
00481 {
00482         setStateFlag(IsUserLightable, enable);
00483         // update IsFinalLightable
00484         setStateFlag(IsFinalLightable, (getStateFlag(IsLightable) && getStateFlag(IsUserLightable)) );
00485 }
00486 
00487 
00488 // ***************************************************************************
00489 void            CTransform::setIsRenderable(bool val)
00490 {
00491         setStateFlag(IsRenderable, val);
00492 }
00493 
00494 // ***************************************************************************
00495 void            CTransform::setIsBigLightable(bool val)
00496 {
00497         setStateFlag(IsBigLightable, val);
00498 }
00499 // ***************************************************************************
00500 void            CTransform::setIsSkeleton(bool val)
00501 {
00502         setStateFlag(IsSkeleton, val);
00503 }
00504 
00505 // ***************************************************************************
00506 void            CTransform::setApplySkin(bool state)
00507 {
00508         setStateFlag(IsSkinned, state);
00509 }
00510 
00511 // ***************************************************************************
00512 void            CTransform::setIsForceAnimDetail(bool val)
00513 {
00514         setStateFlag(IsForceAnimDetail, val );
00515 
00516         // Update flag, if we must be inserted in AnimDetail
00517         setStateFlag(IsAnimDetailable, _ChannelMixer || getStateFlag(IsForceAnimDetail) );
00518 
00519         // If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
00520         if(isSkinned())
00521         {
00522                 nlassert(_FatherSkeletonModel);
00523                 _FatherSkeletonModel->dirtSkinRenderLists();
00524         }
00525 }
00526 // ***************************************************************************
00527 void            CTransform::setIsLoadbalancable(bool val)
00528 {
00529         setStateFlag(IsLoadBalancable, val );
00530 }
00531 
00532 
00533 // ***************************************************************************
00534 // ***************************************************************************
00535 // Observers.
00536 // ***************************************************************************
00537 // ***************************************************************************
00538 
00539 
00540 // ***************************************************************************
00541 void    CTransformHrcObs::update()
00542 {
00543         IBaseHrcObs::update();
00544 
00545         if(Model->TouchObs[CTransform::TransformDirty])
00546         {
00547                 // update the local matrix.
00548                 LocalMatrix= static_cast<CTransform*>(Model)->getMatrix();
00549                 IBaseHrcObs::LocalVis= static_cast<CTransform*>(Model)->Visibility;
00550                 // update the date of the local matrix.
00551                 LocalDate= static_cast<CHrcTrav*>(Trav)->CurrentDate;
00552 
00553                 // The transform has been modified. Hence, it is no more frozen.
00554                 Frozen= false;
00555         }
00556 
00557 }
00558 
00559 
00560 // ***************************************************************************
00561 void    CTransformHrcObs::updateWorld(IBaseHrcObs *caller)
00562 {
00563         const   CMatrix         *pFatherWM;
00564         bool                            visFather;
00565         CTransform                      *transModel= (CTransform*)Model;
00566 
00567         // If not root case, link to caller.
00568         if(caller)
00569         {
00570                 pFatherWM= &(caller->WorldMatrix);
00571                 visFather= caller->WorldVis;
00572 
00573                 // If father is not Frozen, so do I.
00574                 CTransformHrcObs        *hrcTransCaller= dynamic_cast<CTransformHrcObs*>(caller);
00575 
00576                 // if caller is a CTransformHrcObs
00577                 //  and if it is not frozen (for any reason), disable us!
00578 
00579                 if (hrcTransCaller && !hrcTransCaller->Frozen && !hrcTransCaller->DontUnfreezeChildren)
00580                         Frozen= false;
00581 
00582                 // if caller is a CTransformHrcObs, may herit his _AncestorSkeletonModel
00583                 // if caller is ! a CTransformHrcObs, final result undefined.
00584                 if (hrcTransCaller && hrcTransCaller->_AncestorSkeletonModel)
00585                         // If my father has an _AncestorSkeletonModel, get it.
00586                         _AncestorSkeletonModel= hrcTransCaller->_AncestorSkeletonModel;
00587                 else
00588                         // else I have an ancestor skel model if I am sticked/binded directly to a skeleton model.
00589                         _AncestorSkeletonModel= transModel->_FatherSkeletonModel;
00590 
00591         }
00592         // else, default!!
00593         else
00594         {
00595                 pFatherWM= &(CMatrix::Identity);
00596                 visFather= true;
00597 
00598                 // at the root of the hierarchy, we have no parent, hence no FatherSkeletonModel nor _AncestorSkeletonModel.
00599                 _AncestorSkeletonModel= NULL;
00600 
00601                 // NB: Root is Frozen by essence :), so don't modify the frozen state here.
00602         }
00603 
00604         // Combine matrix
00605         if(LocalDate>WorldDate || (caller && caller->WorldDate>WorldDate) )
00606         {
00607                 // Must recompute the world matrix.  ONLY IF I AM NOT SKINNED/STICKED TO A SKELETON in the hierarchy!
00608                 if( _AncestorSkeletonModel==NULL )
00609                 {
00610                         WorldMatrix=  *pFatherWM * LocalMatrix;
00611                         WorldDate= static_cast<CHrcTrav*>(Trav)->CurrentDate;
00612 
00613                         // Add the model to the moving object list
00614                         if (!Frozen)
00615                                 static_cast<CHrcTrav*>(Trav)->_MovingObjects.push_back (Model);
00616                 }
00617         }
00618 
00619         // Update dynamic lighting.
00620         /*
00621                 If the model is not frozen in StaticLight, then must update lighting each frame.
00622                 Even if the object doesn't move, a new dynamic light may enter in its aera. Hence we must test
00623                 it in the light quadrid. StaticLight-ed Objects don't need it because they are inserted in a special quadgrid, 
00624                 where dynamics lights touch all StaticLight-ed object to force their computing
00625 
00626                 NB: not done if _AncestorSkeletonModel!=NULL. no need because  in this case, 
00627                 result is driven by the _LightContribution of the _AncestorSkeletonModel.
00628         */
00629         if( !transModel->_LightContribution.FrozenStaticLightSetup && _AncestorSkeletonModel==NULL )
00630         {
00631                 // if the model is lightable reset lighting
00632                 if( transModel->isLightable() )
00633                         transModel->resetLighting();
00634         }
00635 
00636         // Combine visibility.
00637         switch(LocalVis)
00638         {
00639                 case CHrcTrav::Herit: WorldVis= visFather; break;
00640                 case CHrcTrav::Hide: WorldVis= false; break;
00641                 case CHrcTrav::Show: WorldVis= true; break;
00642                 default: break;
00643         }
00644 
00645 
00646         // If I have an ancestor Skeleton Model, I must be binded in ClipTrav to the SonsOfAncestorSkeletonModelGroup
00647         updateClipTravForAncestorSkeleton();
00648 
00649 }
00650 
00651 
00652 // ***************************************************************************
00653 void    CTransformHrcObs::updateClipTravForAncestorSkeleton()
00654 {
00655         CTransform                      *transModel= (CTransform*)Model;
00656         CClipTrav                       *clipTrav= (CClipTrav*)transModel->_ClipObs->Trav;
00657 
00658         // If I have an ancestor Skeleton Model, I must be binded in ClipTrav to the SonsOfAncestorSkeletonModelGroup
00659         if(_AncestorSkeletonModel && !ClipLinkedInSonsOfAncestorSkeletonModelGroup)
00660         {
00661                 // ClipTrav is a graph, so must unlink from ALL olds models.
00662                 IModel  *father= clipTrav->getFirstParent(transModel);
00663                 while(father)
00664                 {
00665                         clipTrav->unlink(father, transModel);
00666                         father= clipTrav->getFirstParent(transModel);
00667                 }
00668 
00669                 // And link to SonsOfAncestorSkeletonModelGroup.
00670                 clipTrav->link(clipTrav->SonsOfAncestorSkeletonModelGroup, transModel);
00671 
00672                 // update the flag.
00673                 ClipLinkedInSonsOfAncestorSkeletonModelGroup= true;
00674         }
00675 
00676 
00677         // else I must be binded to the standard Root.
00678         if(!_AncestorSkeletonModel && ClipLinkedInSonsOfAncestorSkeletonModelGroup)
00679         {
00680                 // verify first I am really still linked to the SonsOfAncestorSkeletonModelGroup.
00681                 // This test is important, because link may have changed for any reason (portals, clipManager....).
00682                 if( clipTrav->getNumParents(transModel) == 1 &&
00683                         clipTrav->getFirstParent(transModel)==clipTrav->SonsOfAncestorSkeletonModelGroup )
00684                 {
00685                         // yes, unlink from it.
00686                         clipTrav->unlink(clipTrav->SonsOfAncestorSkeletonModelGroup, transModel);
00687                         // and now, link to std root.
00688                         clipTrav->link(clipTrav->getRoot(), transModel);
00689                 }
00690 
00691                 // update the flag
00692                 ClipLinkedInSonsOfAncestorSkeletonModelGroup= false;
00693         }
00694 }
00695 
00696 
00697 // ***************************************************************************
00698 void    CTransformHrcObs::traverse(IObs *caller)
00699 {
00700         // Recompute the matrix, according to caller matrix mode, and local matrix.
00701         nlassert(!caller || dynamic_cast<IBaseHrcObs*>(caller));
00702         updateWorld(static_cast<IBaseHrcObs*>(caller));
00703         // DoIt the sons.
00704         traverseSons();
00705 }
00706 
00707 
00708 // ***************************************************************************
00709 void    CTransformClipObs::traverse(IObs *caller)
00710 {
00711         nlassert(!caller || dynamic_cast<IBaseClipObs*>(caller));
00712 
00713         CClipTrav               *clipTrav= safe_cast<CClipTrav*>(Trav);
00714         IBaseClipObs    *callerClipObs= static_cast<IBaseClipObs*>(caller);
00715         CTransform              *transform= (CTransform*)Model;
00716 
00717         if ((Date == clipTrav->CurrentDate) && Visible)
00718                 return;
00719         Date = clipTrav->CurrentDate;
00720 
00721         // clip: update Visible flag.
00722         Visible= false;
00723         // if at least visible.
00724         if(HrcObs->WorldVis)
00725         {
00726                 // If linked to a SkeletonModel anywhere in the hierarchy, don't clip, and use skeleton model clip result.
00727                 // This works because we are sons of a special node which is not in the clip traversal, and
00728                 // which is traversed at end of the traversal.
00729                 if( ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel!=NULL )
00730                 {
00731                         Visible= ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel->isClipVisible();
00732                         // Special test: if we are sticked to a skeletonModel, and if we are still visible, maybe we don't have to
00733                         if(Visible && transform->_FatherSkeletonModel)
00734                         {
00735                                 // if our skeletonModel father is displayed with a Lod, maybe we are not to be displayed
00736                                 if(transform->_FatherSkeletonModel->isDisplayedAsLodCharacter())
00737                                 {
00738                                         // We are visible only if we where sticked to the skeleton with forceCLod==true.
00739                                         // This is also true if we are actually a skeletonModel
00740                                         if(!transform->_ForceCLodSticked)
00741                                                 // otherWise we are not visible. eg: this is the case of skins and some sticked object
00742                                                 Visible= false;
00743                                 }
00744                         }
00745                 }
00746                 // else, clip.
00747                 else
00748                         Visible= clip(callerClipObs);
00749         }
00750 
00751         // if visible, add to list.
00752         if(Visible)
00753         {
00754                 // add this observer to the visibility list.
00755                 clipTrav->addVisibleObs(this);
00756 
00757                 // Has not an ancestor skeleton model?
00758                 if( ((CTransformHrcObs*)HrcObs)->_AncestorSkeletonModel==NULL )
00759                 {
00760                         // If needed, insert the model in the lighted list.
00761                         // don't insert if has an ancestorSkeletonModel, because in this case, result is driven by 
00762                         // the _LightContribution of the _AncestorSkeletonModel.
00763                         if( transform->isLightable() )
00764                                 clipTrav->LightTrav->addLightedObs(transform->_LightObs);
00765 
00766                         // If needed, insert the model in the animDetail list.
00767                         // don't insert if has an ancestoreSkeletonModel, because in this case, this ancestore will 
00768                         // animDetail through the hierarchy...
00769                         if( transform->isAnimDetailable() )
00770                                 clipTrav->AnimDetailTrav->addVisibleObs(safe_cast<CTransformAnimDetailObs*>(AnimDetailObs));
00771                 }
00772 
00773                 // If needed, Add it to the loadBalancing trav
00774                 if( transform->isLoadBalancable() )
00775                         clipTrav->LoadBalancingTrav->addVisibleObs(LoadBalancingObs);
00776 
00777                 // If needed, insert the model in the render list.
00778                 if( transform->isRenderable() )
00779                         clipTrav->RenderTrav->addRenderObs(RenderObs);
00780         }
00781 
00782         // DoIt the sons.
00783         traverseSons();
00784 }
00785 
00786 
00787 
00788 // ***************************************************************************
00789 void    CTransformAnimDetailObs::updateWorldMatrixFromFather()
00790 {
00791         CTransform              *transModel= static_cast<CTransform*>(Model);
00792 
00793         // If I have an ancestore Skeleton model
00794         if(transModel->_HrcObs->_AncestorSkeletonModel)
00795         {
00796                 // then must first update my worldMatrix.
00797                 transModel->updateWorldMatrixFromFather();
00798         }
00799 }
00800 
00801 // ***************************************************************************
00802 void    CTransformAnimDetailObs::traverseWithoutUpdateWorldMatrix(IObs *caller)
00803 {
00804         CTransform              *transModel= static_cast<CTransform*>(Model);
00805 
00806         // AnimDetail behavior: animate only if not clipped.
00807         // NB: no need to test because of VisibilityList use.
00808 
00809         // test if the refptr is NULL or not (RefPtr).
00810         CChannelMixer   *chanmix= transModel->_ChannelMixer;
00811         if(chanmix)
00812         {
00813                 // eval detail!!
00814                 chanmix->eval(true, static_cast<CAnimDetailTrav*>(Trav)->CurrentDate);
00815         }
00816 }
00817 
00818 // ***************************************************************************
00819 void    CTransformAnimDetailObs::traverse(IObs *caller)
00820 {
00821         // First, test if I must update my HrcObs worldMatrix because of the ancestorSkeleton scheme
00822         updateWorldMatrixFromFather();
00823 
00824         // eval channelMixer.
00825         traverseWithoutUpdateWorldMatrix(caller);
00826 
00827         // NB: if want to add something, do it in traverseWithoutUpdateWorldMatrix(), because
00828         // CSkeletonModel doesn't call CTransformAnimDetailObs::traverse()
00829 
00830         // no need to traverseSons. No graph here.
00831 }
00832 
00833 
00834 // ***************************************************************************
00835 // ***************************************************************************
00836 // Lighting.
00837 // ***************************************************************************
00838 // ***************************************************************************
00839 
00840 
00841 // ***************************************************************************
00842 void            CTransform::resetLighting()
00843 {
00844         // if the model is already isNeedUpdateLighting, his light setup is reseted.
00845         // so no need to reset again
00846         if(isNeedUpdateLighting())
00847                 return;
00848 
00849 
00850         // For all light not in FrozenStaticLightSetup, remove me from their list
00851         uint    startLight= 0;
00852         if(_LightContribution.FrozenStaticLightSetup)
00853         {
00854                 startLight= _LightContribution.NumFrozenStaticLight;
00855         }
00856 
00857         // for all light in the list, remove me from their list.
00858         for(uint i=startLight; i<NL3D_MAX_LIGHT_CONTRIBUTION; i++)
00859         {
00860                 CPointLight             *pl= _LightContribution.PointLight[i];
00861                 // if end of list, break.
00862                 if(!pl)
00863                         break;
00864                 else
00865                 {
00866                         // remove me from this light.
00867                         pl->removeLightedModel(_LightContribution.TransformIterator[i]);
00868                 }
00869         }
00870         // empty the list.
00871         if(startLight<NL3D_MAX_LIGHT_CONTRIBUTION)
00872                 _LightContribution.PointLight[startLight]= NULL;
00873 
00874 
00875         // the model needs to update his lighting.
00876         setStateFlag(IsNeedUpdateLighting, true);
00877         
00878 }
00879 
00880 
00881 // ***************************************************************************
00882 void                    CTransform::freezeStaticLightSetup(CPointLight *pointLight[NL3D_MAX_LIGHT_CONTRIBUTION], 
00883                 uint numPointLights, uint8 sunContribution, CPointLight *frozenAmbientlight)
00884 {
00885         nlassert(numPointLights <= NL3D_MAX_LIGHT_CONTRIBUTION);
00886 
00887         // resetLighting() first.
00888         resetLighting();
00889 
00890         // Enable StaticLightSetup.
00891         _LightContribution.FrozenStaticLightSetup= true;
00892         _LightContribution.NumFrozenStaticLight= numPointLights;
00893         _LightContribution.SunContribution= sunContribution;
00894         // setup the FrozenAmbientLight
00895         _LightContribution.FrozenAmbientLight= frozenAmbientlight;
00896         // Setup other pointLights
00897         uint i;
00898         for(i=0;i<numPointLights;i++)
00899         {
00900                 // set the light
00901                 _LightContribution.PointLight[i]= pointLight[i];
00902                 // Enable at max.
00903                 _LightContribution.Factor[i]= 255;
00904                 // Compute static AttFactor Later because don't have WorlPosition of the model here!!
00905                 setStateFlag(IsNeedUpdateFrozenStaticLightSetup, true);
00906 
00907                 // Do NOT set the iterator, because it is a staticLight.
00908         }
00909         // End the list
00910         if(i<NL3D_MAX_LIGHT_CONTRIBUTION)
00911                 _LightContribution.PointLight[i]= NULL;
00912 }
00913 
00914 // ***************************************************************************
00915 void                    CTransform::unfreezeStaticLightSetup()
00916 {
00917         // resetLighting() first.
00918         resetLighting();
00919 
00920         // Disable StaticLightSetup.
00921         _LightContribution.FrozenStaticLightSetup= false;
00922         _LightContribution.NumFrozenStaticLight= 0;
00923         // End the list
00924         _LightContribution.PointLight[0]= NULL;
00925         // No more FrozenAmbientLight
00926         _LightContribution.FrozenAmbientLight= NULL;
00927 
00928         // Don't need to update StaticLightSetup since no more exist.
00929         setStateFlag(IsNeedUpdateFrozenStaticLightSetup, false);
00930 }
00931 
00932 
00933 // ***************************************************************************
00934 void    CTransformLightObs::traverse(IObs *caller)
00935 {
00936         CTransform              *transform= (CTransform*)Model;
00937 
00938         // if the model do not need to update his lighting, just skip.
00939         if(!transform->isNeedUpdateLighting())
00940                 return;
00941 
00942 
00943         // If a freezeStaticLightSetup() has been called on this model recently.
00944         if(transform->isNeedUpdateFrozenStaticLightSetup())
00945         {
00946                 // Now, the correct matrix is computed.
00947                 // get the untransformed bbox from the model.
00948                 CAABBox         bbox;
00949                 transform->getAABBox(bbox);
00950                 // get transformed center pos of bbox
00951                 CVector worldModelPos= transform->getWorldMatrix() * bbox.getCenter();
00952 
00953                 // So we can compute AttFactor for each static light influencing this static object
00954                 uint    numPointLights= transform->_LightContribution.NumFrozenStaticLight;
00955                 for(uint i=0;i<numPointLights;i++)
00956                 {
00957                         const CPointLight       *pl= transform->_LightContribution.PointLight[i];
00958                         // don't worry about the precision of floor, because of *255.
00959                         float   distToModel= (pl->getPosition() - worldModelPos).norm();
00960                         sint    attFactor= OptFastFloor( 255 * pl->computeLinearAttenuation(worldModelPos, distToModel) );
00961                         transform->_LightContribution.AttFactor[i]= (uint8)attFactor;
00962                 }
00963 
00964                 // clean.
00965                 transform->setStateFlag(CTransform::IsNeedUpdateFrozenStaticLightSetup, false);
00966         }
00967 
00968 
00969         // see CTransformClipObs::clip(), here I am Lightable(), and I have no _AncestorSkeletonModel
00970         // So I am sure that I really need to recompute my ModelLightContributions.
00971         ((CLightTrav*)Trav)->LightingManager.computeModelLightContributions(transform,
00972                 transform->_LightContribution, transform->_LogicInfo);
00973 
00974         // done!
00975         transform->setStateFlag(CTransform::IsNeedUpdateLighting, false);
00976 }
00977 
00978 
00979 
00980 }