1470 lines
44 KiB
C++
1470 lines
44 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
||
// Copyright (C) 2010 Winch Gate Property Limited
|
||
//
|
||
// This program is free software: you can redistribute it and/or modify
|
||
// it under the terms of the GNU Affero General Public License as
|
||
// published by the Free Software Foundation, either version 3 of the
|
||
// License, or (at your option) any later version.
|
||
//
|
||
// This program is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
// GNU Affero General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Affero General Public License
|
||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
#include "std3d.h"
|
||
|
||
#include "nel/3d/transform.h"
|
||
#include "nel/3d/skeleton_model.h"
|
||
#include "nel/3d/scene.h"
|
||
#include "nel/3d/scene_group.h"
|
||
#include "nel/3d/root_model.h"
|
||
#include "nel/3d/u_transform.h"
|
||
#include "nel/misc/fast_floor.h"
|
||
#include "nel/misc/hierarchical_timer.h"
|
||
|
||
|
||
using namespace NLMISC;
|
||
using namespace std;
|
||
|
||
namespace NL3D
|
||
{
|
||
|
||
|
||
// ***************************************************************************
|
||
#define NL3D_TRANSFORM_DEFAULT_SHADOW_MAP_DEPTH 8.f
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::registerBasic()
|
||
{
|
||
CScene::registerModel( TransformId, 0, CTransform::creator);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
CTransform::CTransform()
|
||
{
|
||
// important to reset for destructor to know if linked or not (CCluster !!)
|
||
_OwnerScene= NULL;
|
||
|
||
// Hrc/Graph hierarchy
|
||
_HrcParent= NULL;
|
||
_HrcParentUnfreeze= NULL;
|
||
|
||
_PrecModelToUpdate= NULL;
|
||
_NextModelToUpdate= NULL;
|
||
|
||
_TransformDirty= true;
|
||
|
||
Visibility= CHrcTrav::Herit;
|
||
|
||
_LastTransformableMatrixDate= 0;
|
||
|
||
_FatherSkeletonModel= NULL;
|
||
|
||
_ClusterSystem = NULL;
|
||
|
||
_FreezeHRCState= FreezeHRCStateDisabled;
|
||
|
||
_OrderingLayer = 2;
|
||
|
||
_TransparencyPriority = 0;
|
||
|
||
|
||
// No logicInfo by default
|
||
_LogicInfo= NULL;
|
||
|
||
_ForceCLodSticked= false;
|
||
|
||
// default MeanColor value
|
||
_MeanColor.set(255,255,255,255);
|
||
|
||
// Default ShadowMap direction
|
||
_ShadowMapDirectionZThreshold= -0.5f;
|
||
_ShadowMapMaxDepth= NL3D_TRANSFORM_DEFAULT_SHADOW_MAP_DEPTH;
|
||
|
||
// Setup some state.
|
||
|
||
/*
|
||
Default are:
|
||
IsAnimDetailable= 0
|
||
IsLoadBalancable= 0
|
||
IsLightable= 0
|
||
IsRenderable= 0
|
||
IsTransparent= 0
|
||
IsOpaque= 1
|
||
QuadGridClipEnabled= 0.
|
||
|
||
IsUserLightable= 1 // default, the model may be lighted.
|
||
IsFinalLightable= 0
|
||
IsNeedUpdateLighting= 0
|
||
ISNeedUpdateFrozenStaticLightSetup= 0
|
||
|
||
IsSkeleton= 0
|
||
IsTransformShape=0
|
||
IsCluster= 0
|
||
IsMeshBaseInstance= 0
|
||
|
||
IsDeleteChannelMixer = 0;
|
||
*/
|
||
_StateFlags= IsOpaque | IsUserLightable;
|
||
|
||
// By default, always allow rendering of Transform Models.
|
||
_RenderFilterType= ~0;
|
||
|
||
// By default, don't suport fast intersection detection
|
||
_SupportFastIntersect= false;
|
||
|
||
|
||
// **** HRC Init Traversal Computed Data.
|
||
_LocalVis= CHrcTrav::Herit; _LocalMatrix.identity(); _LocalDate=0;
|
||
_WorldVis= true; _WorldMatrix.identity();
|
||
// Init the _WorldDate to -1 so at first pass, _LocalDate>_WorldDate, and so
|
||
// the model will be processed and so it'll may be inserted in LightingManager (for example)
|
||
_WorldDate=-1;
|
||
_Frozen = false;
|
||
_DontUnfreezeChildren = false;
|
||
_AncestorSkeletonModel= NULL;
|
||
_ClipLinkedInSonsOfAncestorSkeletonModelGroup= false;
|
||
|
||
// **** Clip Init Traversal Computed Data.
|
||
_ClipDate= 0;
|
||
_Visible=false;
|
||
_IndexInVisibleList= -1;
|
||
|
||
// **** AnimDetail Init Traversal Computed Data.
|
||
// none
|
||
|
||
// **** LoadBalancing Init Traversal Computed Data.
|
||
_LoadBalancingGroup= NULL;
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
CTransform::~CTransform()
|
||
{
|
||
// If still binded to a father skeleton
|
||
if( _FatherSkeletonModel )
|
||
{
|
||
/* If skinned, cannot detach me from skeleton here because detachSkeletonSon()
|
||
use some virtual calls of transform: setApplySkin().
|
||
Hence, It is the deriver job to detach himself from the skeleton.
|
||
|
||
NB: test isSkinned(), not isSkinnable(), since isSkinned() is not virtual ....
|
||
This means that if a Mesh isSkinnable(), but never skinned, it is not asserted here.
|
||
*/
|
||
if( isSkinned() )
|
||
{
|
||
nlstop;
|
||
}
|
||
else
|
||
// Can detach Me. Important for UTransform sticked
|
||
_FatherSkeletonModel->detachSkeletonSon(this);
|
||
}
|
||
|
||
// resetLighting, removing me from PointLight Transform list.
|
||
// NB: not done for FrozenStaticLightSetup, because those lights don't owns me.
|
||
resetLighting();
|
||
|
||
// Must also remove me from the lightingManager.
|
||
// must test getOwnerScene() because of CCluster usage out of CScene (thanks to mat!! :) )
|
||
if(getOwnerScene())
|
||
{
|
||
CLightTrav &lightTrav= getOwnerScene()->getLightTrav();
|
||
_LightedModelIt= lightTrav.LightingManager.eraseStaticLightedModel(_LightedModelIt);
|
||
}
|
||
|
||
if (getChannelMixerOwnerShip()) delete (CChannelMixer *) _ChannelMixer;
|
||
|
||
// ensure the model is no more linked to the UpdateList.
|
||
unlinkFromUpdateList();
|
||
|
||
// I must remove me from _VisibleList.
|
||
if(_IndexInVisibleList>=0)
|
||
{
|
||
CClipTrav &clipTrav= getOwnerScene()->getClipTrav();
|
||
nlassert(_IndexInVisibleList < (sint)clipTrav._CurrentNumVisibleModels );
|
||
// Mark NULL. NB: faster than a CRefPtr.
|
||
clipTrav._VisibleList[_IndexInVisibleList]= NULL;
|
||
_IndexInVisibleList= -1;
|
||
}
|
||
|
||
// remove me from parents in Hrc and Clip
|
||
setStateFlag(ForceClipRoot, false); // ensure that not 'glued' to the root so that the following call will succeed
|
||
hrcUnlink();
|
||
clipUnlinkFromAll();
|
||
|
||
// remove mys sons.
|
||
while(hrcGetNumChildren())
|
||
{
|
||
hrcGetChild(0)->hrcUnlink();
|
||
}
|
||
while(clipGetNumChildren())
|
||
{
|
||
clipDelChild(clipGetChild(0));
|
||
}
|
||
|
||
nlassert(_HrcSons.empty());
|
||
nlassert(_HrcParent==NULL);
|
||
nlassert(_ClipSons.empty());
|
||
nlassert(_ClipParents.empty());
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::initModel()
|
||
{
|
||
// assign me to the default group
|
||
_LoadBalancingGroup= getOwnerScene()->getLoadBalancingTrav().getDefaultGroup();
|
||
}
|
||
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::hide()
|
||
{
|
||
// Optim: do nothing if already set
|
||
if(Visibility!= CHrcTrav::Hide)
|
||
{
|
||
_TransformDirty= true;
|
||
Visibility= CHrcTrav::Hide;
|
||
// If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setTransparency(bool v)
|
||
{
|
||
bool bTmp = getStateFlag(IsTransparent) == 0 ? false : true;
|
||
if (bTmp != v)
|
||
{
|
||
setStateFlag(IsTransparent, v);
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setBypassLODOpacityFlag(bool bypass)
|
||
{
|
||
setStateFlag(BypassLODOpacity, bypass);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setOpacity(bool v)
|
||
{
|
||
bool bTmp = getStateFlag(IsOpaque) == 0 ? false : true;
|
||
if (bTmp != v)
|
||
{
|
||
setStateFlag(IsOpaque, v);
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::show()
|
||
{
|
||
// Optim: do nothing if already set
|
||
if(Visibility!= CHrcTrav::Show)
|
||
{
|
||
_TransformDirty= true;
|
||
Visibility= CHrcTrav::Show;
|
||
// If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
}
|
||
// ***************************************************************************
|
||
void CTransform::heritVisibility()
|
||
{
|
||
// Optim: do nothing if already set
|
||
if(Visibility!= CHrcTrav::Herit)
|
||
{
|
||
_TransformDirty= true;
|
||
Visibility= CHrcTrav::Herit;
|
||
// If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
CTrackDefaultVector CTransform::DefaultPos( CVector::Null );
|
||
CTrackDefaultVector CTransform::DefaultRotEuler( CVector::Null );
|
||
CTrackDefaultQuat CTransform::DefaultRotQuat( NLMISC::CQuat::Identity );
|
||
CTrackDefaultVector CTransform::DefaultScale( CVector(1,1,1) );
|
||
CTrackDefaultVector CTransform::DefaultPivot( CVector::Null );
|
||
|
||
ITrack* CTransform::getDefaultTrack (uint valueId)
|
||
{
|
||
// Cyril: prefer do it here in CTransform, because of CCamera, CLight etc... (which may not need a default value too!!)
|
||
|
||
// what value ?
|
||
switch (valueId)
|
||
{
|
||
case PosValue: return &DefaultPos;
|
||
case RotEulerValue: return &DefaultRotEuler;
|
||
case RotQuatValue: return &DefaultRotQuat;
|
||
case ScaleValue: return &DefaultScale;
|
||
case PivotValue: return &DefaultPivot;
|
||
}
|
||
|
||
// No, only ITrnasformable values!
|
||
nlstop;
|
||
// Deriver note: else call BaseClass::getDefaultTrack(valueId);
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
|
||
{
|
||
if (getChannelMixerOwnerShip() && chanMixer != _ChannelMixer)
|
||
{
|
||
delete _ChannelMixer;
|
||
setChannelMixerOwnerShip(false);
|
||
}
|
||
|
||
// Hey!! we are animated!!
|
||
_ChannelMixer= chanMixer;
|
||
|
||
// Update flag, if we must be inserted in AnimDetail
|
||
setStateFlag(IsAnimDetailable, _ChannelMixer || getStateFlag(IsForceAnimDetail) );
|
||
|
||
// If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
|
||
// For CTransfom, channels are not detailled.
|
||
addValue(chanMixer, PosValue, OwnerBit, prefix, false);
|
||
addValue(chanMixer, RotEulerValue, OwnerBit, prefix, false);
|
||
addValue(chanMixer, RotQuatValue, OwnerBit, prefix, false);
|
||
addValue(chanMixer, ScaleValue, OwnerBit, prefix, false);
|
||
addValue(chanMixer, PivotValue, OwnerBit, prefix, false);
|
||
|
||
// Deriver note: if necessary, call BaseClass::registerToChannelMixer(chanMixer, prefix);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::freeze()
|
||
{
|
||
// First, update the model
|
||
// _Frozen state is disabled here (in CTransform::update()).
|
||
update();
|
||
|
||
// Then flag the frozen state.
|
||
_Frozen= true;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setDontUnfreezeChildren(bool val)
|
||
{
|
||
_DontUnfreezeChildren = val;
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::freezeHRC()
|
||
{
|
||
// if disabled, say we are ready to validate our worldMatrix for long.
|
||
if(_FreezeHRCState==FreezeHRCStateDisabled)
|
||
{
|
||
_FreezeHRCState= FreezeHRCStateRequest;
|
||
setStateFlag(QuadGridClipEnabled, true);
|
||
|
||
/* If the transform is not frozen (ie staticaly inserted in a cluster),
|
||
We must be sure it will be tested against QuadGridClipManager at next ClipTrav pass.
|
||
=> must make this object a "moving object" at next render=> dirt _LocalMatrixDate.
|
||
*/
|
||
if(!_Frozen)
|
||
{
|
||
_TransformDirty= true;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::unfreezeHRC()
|
||
{
|
||
// if this model is no HRC frozen disabled
|
||
if(_FreezeHRCState!=FreezeHRCStateDisabled)
|
||
{
|
||
// if model correctly frozen.
|
||
if(_FreezeHRCState == CTransform::FreezeHRCStateEnabled )
|
||
{
|
||
// Should not be linked : can't link after a freezeHRC
|
||
nlassert (_HrcParent == NULL);
|
||
|
||
// Set as unfreeze else, hrcLinkSon doesn't work
|
||
_FreezeHRCState= FreezeHRCStateDisabled;
|
||
|
||
// Link this model to the previous HRC parent.
|
||
if (_HrcParentUnfreeze)
|
||
_HrcParentUnfreeze->hrcLinkSon( this );
|
||
else
|
||
getOwnerScene()->getRoot()->hrcLinkSon( this );
|
||
|
||
// Link this object to the validateList.
|
||
linkToUpdateList();
|
||
|
||
// if lightable()
|
||
if( isLightable() )
|
||
{
|
||
CLightTrav &lightTrav= getOwnerScene()->getLightTrav();
|
||
// Lighting: must remove the object from the quadGrid.
|
||
// NB: works if _LightedModelIt==NULL. result is that _LightedModelIt= NULL.
|
||
_LightedModelIt= lightTrav.LightingManager.eraseStaticLightedModel(_LightedModelIt);
|
||
}
|
||
|
||
}
|
||
else
|
||
_FreezeHRCState= FreezeHRCStateDisabled;
|
||
|
||
// unlink me from any QuadCluster, and disable QuadCluster
|
||
unlinkFromQuadCluster();
|
||
setStateFlag(QuadGridClipEnabled, false);
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::update()
|
||
{
|
||
// test if the matrix has been changed in ITransformable.
|
||
if(ITransformable::compareMatrixDate(_LastTransformableMatrixDate))
|
||
{
|
||
_LastTransformableMatrixDate= ITransformable::getMatrixDate();
|
||
_TransformDirty= true;
|
||
}
|
||
|
||
// update the freezeHRC state.
|
||
if(_FreezeHRCState != CTransform::FreezeHRCStateDisabled)
|
||
{
|
||
// if the model request to be frozen in HRC
|
||
if(_FreezeHRCState == CTransform::FreezeHRCStateRequest )
|
||
{
|
||
// Wait for next Hrc traversal to compute good _WorldMatrix for this model and his sons.
|
||
// Also, next Hrc traversal will insert the model in the LightingManager quadGrid (if lightable)
|
||
_FreezeHRCState = CTransform::FreezeHRCStateReady;
|
||
}
|
||
// if the model is ready to be frozen in HRC, then do it!!
|
||
else if( _FreezeHRCState == CTransform::FreezeHRCStateReady )
|
||
{
|
||
// Unlink this model.
|
||
hrcUnlink();
|
||
|
||
// unLink this object from the validateList. NB: the list will still be correclty parsed.
|
||
unlinkFromUpdateList();
|
||
|
||
// if lightable, the model is inserted in a quadgrid to update his lighting only when
|
||
// dynamicLights touch him (since himself is static).
|
||
if( isLightable() )
|
||
{
|
||
CLightTrav &lightTrav= getOwnerScene()->getLightTrav();
|
||
// Lighting: must reinsert the object from the quadGrid.
|
||
// NB: works if _LightedModelIt==NULL. result is that _LightedModelIt= NULL.
|
||
_LightedModelIt= lightTrav.LightingManager.eraseStaticLightedModel(_LightedModelIt);
|
||
// insert in the quadgrid.
|
||
_LightedModelIt= lightTrav.LightingManager.insertStaticLightedModel(this);
|
||
}
|
||
|
||
// Now this model won't be tested for validation nor for worldMatrix update. End!!
|
||
_FreezeHRCState = CTransform::FreezeHRCStateEnabled;
|
||
}
|
||
}
|
||
|
||
// update _LocalMatrix
|
||
if(_TransformDirty)
|
||
{
|
||
// update the local matrix.
|
||
_LocalMatrix= getMatrix();
|
||
_LocalVis= Visibility;
|
||
// update the date of the local matrix.
|
||
_LocalDate= getOwnerScene()->getHrcTrav().CurrentDate;
|
||
|
||
// The transform has been modified. Hence, it is no more frozen.
|
||
_Frozen= false;
|
||
|
||
// ok!
|
||
_TransformDirty= false;
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::getAABBox(NLMISC::CAABBox &bbox) const
|
||
{
|
||
bbox.setCenter(CVector::Null);
|
||
bbox.setHalfSize(CVector::Null);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setLoadBalancingGroup(const std::string &group)
|
||
{
|
||
// Get the traversal.
|
||
CLoadBalancingTrav &trav= getOwnerScene()->getLoadBalancingTrav();
|
||
// get the group from trav (create if needed), and set it.
|
||
_LoadBalancingGroup= trav.getOrCreateGroup(group);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
const std::string &CTransform::getLoadBalancingGroup() const
|
||
{
|
||
// get the group name
|
||
return _LoadBalancingGroup->Name;
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setMeanColor(CRGBA color)
|
||
{
|
||
// if the color is different from prec
|
||
if(color!=_MeanColor)
|
||
{
|
||
// change it.
|
||
_MeanColor= color;
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setIsLightable(bool val)
|
||
{
|
||
setStateFlag(IsLightable, val);
|
||
// update IsFinalLightable
|
||
setStateFlag(IsFinalLightable, (getStateFlag(IsLightable) && getStateFlag(IsUserLightable)) );
|
||
}
|
||
// ***************************************************************************
|
||
void CTransform::setUserLightable(bool enable)
|
||
{
|
||
setStateFlag(IsUserLightable, enable);
|
||
// update IsFinalLightable
|
||
setStateFlag(IsFinalLightable, (getStateFlag(IsLightable) && getStateFlag(IsUserLightable)) );
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setIsRenderable(bool val)
|
||
{
|
||
setStateFlag(IsRenderable, val);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setIsBigLightable(bool val)
|
||
{
|
||
setStateFlag(IsBigLightable, val);
|
||
}
|
||
// ***************************************************************************
|
||
void CTransform::setIsSkeleton(bool val)
|
||
{
|
||
setStateFlag(IsSkeleton, val);
|
||
}
|
||
// ***************************************************************************
|
||
void CTransform::setApplySkin(bool state)
|
||
{
|
||
setStateFlag(IsSkinned, state);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setIsForceAnimDetail(bool val)
|
||
{
|
||
setStateFlag(IsForceAnimDetail, val );
|
||
|
||
// Update flag, if we must be inserted in AnimDetail
|
||
setStateFlag(IsAnimDetailable, _ChannelMixer || getStateFlag(IsForceAnimDetail) );
|
||
|
||
// If skinned, then must inform skeleton parent that it must recompute skin render/animDetail lists
|
||
if(isSkinned())
|
||
{
|
||
nlassert(_FatherSkeletonModel);
|
||
_FatherSkeletonModel->dirtSkinRenderLists();
|
||
}
|
||
}
|
||
// ***************************************************************************
|
||
void CTransform::setIsLoadbalancable(bool val)
|
||
{
|
||
setStateFlag(IsLoadBalancable, val );
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::linkToUpdateList()
|
||
{
|
||
if(!_OwnerScene)
|
||
return;
|
||
|
||
// If the model is not already inserted.
|
||
if( ! (_PrecModelToUpdate!=NULL || _OwnerScene->_UpdateModelList==this) )
|
||
{
|
||
// insert it.
|
||
_NextModelToUpdate= _OwnerScene->_UpdateModelList;
|
||
_PrecModelToUpdate= NULL;
|
||
if(_NextModelToUpdate)
|
||
_NextModelToUpdate->_PrecModelToUpdate= this;
|
||
_OwnerScene->_UpdateModelList= this;
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::unlinkFromUpdateList()
|
||
{
|
||
if(!_OwnerScene)
|
||
return;
|
||
|
||
// If the model is inserted.
|
||
if( _PrecModelToUpdate!=NULL || _OwnerScene->_UpdateModelList==this )
|
||
{
|
||
// update prec.
|
||
if(_PrecModelToUpdate)
|
||
_PrecModelToUpdate->_NextModelToUpdate= _NextModelToUpdate;
|
||
else
|
||
_OwnerScene->_UpdateModelList= _NextModelToUpdate;
|
||
|
||
// update next.
|
||
if(_NextModelToUpdate)
|
||
_NextModelToUpdate->_PrecModelToUpdate= _PrecModelToUpdate;
|
||
|
||
// End.
|
||
_PrecModelToUpdate= NULL;
|
||
_NextModelToUpdate= NULL;
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Hrc Trav
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::updateWorld()
|
||
{
|
||
const CMatrix *pFatherWM;
|
||
bool visFather;
|
||
|
||
// If not root case, link to Fahter.
|
||
if(_HrcParent)
|
||
{
|
||
pFatherWM= &(_HrcParent->_WorldMatrix);
|
||
visFather= _HrcParent->_WorldVis;
|
||
|
||
// if _HrcParent is not frozen (for any reason), disable us!
|
||
|
||
if (!_HrcParent->_Frozen && !_HrcParent->_DontUnfreezeChildren)
|
||
_Frozen= false;
|
||
|
||
// herit _AncestorSkeletonModel
|
||
if (_HrcParent->_AncestorSkeletonModel)
|
||
// If my father has an _AncestorSkeletonModel, get it.
|
||
_AncestorSkeletonModel= _HrcParent->_AncestorSkeletonModel;
|
||
else
|
||
// else I have an ancestor skel model if I am sticked/binded directly to a skeleton model.
|
||
_AncestorSkeletonModel= _FatherSkeletonModel;
|
||
}
|
||
// else, default!!
|
||
else
|
||
{
|
||
pFatherWM= &(CMatrix::Identity);
|
||
visFather= true;
|
||
|
||
// at the root of the hierarchy, we have no parent, hence no FatherSkeletonModel nor _AncestorSkeletonModel.
|
||
_AncestorSkeletonModel= NULL;
|
||
|
||
// NB: Root is Frozen by essence :), so don't modify the frozen state here.
|
||
}
|
||
|
||
// Combine matrix
|
||
if(_LocalDate>_WorldDate || (_HrcParent && _HrcParent->_WorldDate>_WorldDate) )
|
||
{
|
||
// Must recompute the world matrix. ONLY IF I AM NOT SKINNED/STICKED TO A SKELETON in the hierarchy!
|
||
if( _AncestorSkeletonModel==NULL )
|
||
{
|
||
_WorldMatrix= *pFatherWM * _LocalMatrix;
|
||
_WorldDate= getOwnerScene()->getHrcTrav().CurrentDate;
|
||
|
||
// Add the model to the moving object list, only if I am a transform shape
|
||
if (!_Frozen && isTransformShape() && !getStateFlag(ForceClipRoot))
|
||
getOwnerScene()->getHrcTrav()._MovingObjects.push_back (static_cast<CTransformShape*>(this));
|
||
}
|
||
}
|
||
|
||
// Update dynamic lighting.
|
||
/*
|
||
If the model is not frozen in StaticLight, then must update lighting each frame.
|
||
Even if the object doesn't move, a new dynamic light may enter in its aera. Hence we must test
|
||
it in the light quadrid. StaticLight-ed Objects don't need it because they are inserted in a special quadgrid,
|
||
where dynamics lights touch all StaticLight-ed object to force their computing
|
||
|
||
NB: not done if _AncestorSkeletonModel!=NULL. no need because in this case,
|
||
result is driven by the _LightContribution of the _AncestorSkeletonModel.
|
||
*/
|
||
if( !_LightContribution.FrozenStaticLightSetup && _AncestorSkeletonModel==NULL )
|
||
{
|
||
// if the model is lightable reset lighting
|
||
if( isLightable() )
|
||
resetLighting();
|
||
}
|
||
|
||
// Combine visibility.
|
||
switch(_LocalVis)
|
||
{
|
||
case CHrcTrav::Herit: _WorldVis= visFather; break;
|
||
case CHrcTrav::Hide: _WorldVis= false; break;
|
||
case CHrcTrav::Show: _WorldVis= true; break;
|
||
default: break;
|
||
}
|
||
|
||
|
||
// If I have an ancestor Skeleton Model, I must be binded in ClipTrav to the SonsOfAncestorSkeletonModelGroup
|
||
updateClipTravForAncestorSkeleton();
|
||
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::updateClipTravForAncestorSkeleton()
|
||
{
|
||
// If I have an ancestor Skeleton Model, I must be binded in ClipTrav to the SonsOfAncestorSkeletonModelGroup
|
||
if(_AncestorSkeletonModel && !_ClipLinkedInSonsOfAncestorSkeletonModelGroup)
|
||
{
|
||
// must unlink from ALL olds models.
|
||
clipUnlinkFromAll();
|
||
|
||
// And link to SonsOfAncestorSkeletonModelGroup.
|
||
getOwnerScene()->SonsOfAncestorSkeletonModelGroup->clipAddChild(this);
|
||
|
||
// update the flag.
|
||
_ClipLinkedInSonsOfAncestorSkeletonModelGroup= true;
|
||
}
|
||
|
||
|
||
// else I must be binded to the standard Root.
|
||
if(!_AncestorSkeletonModel && _ClipLinkedInSonsOfAncestorSkeletonModelGroup)
|
||
{
|
||
// verify first I am really still linked to the SonsOfAncestorSkeletonModelGroup.
|
||
// This test is important, because link may have changed for any reason (portals, clipManager....).
|
||
if( clipGetNumParents() == 1 && clipGetParent(0)==getOwnerScene()->SonsOfAncestorSkeletonModelGroup )
|
||
{
|
||
// must unlink from ALL olds models.
|
||
clipUnlinkFromAll();
|
||
// and now, link to std root.
|
||
getOwnerScene()->getRoot()->clipAddChild(this);
|
||
}
|
||
|
||
// update the flag
|
||
_ClipLinkedInSonsOfAncestorSkeletonModelGroup= false;
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseHrc()
|
||
{
|
||
// Recompute the matrix, according to _HrcParent matrix mode, and local matrix.
|
||
updateWorld();
|
||
|
||
// Traverse the Hrc sons.
|
||
uint num= hrcGetNumChildren();
|
||
for(uint i=0;i<num;i++)
|
||
hrcGetChild(i)->traverseHrc();
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Clip Trav
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setClusterSystem(CInstanceGroup *pCS)
|
||
{
|
||
if (pCS != NULL)
|
||
{
|
||
nlassert(!getStateFlag(ForceClipRoot)); // the transform must be linked to the root, and have not cluster system when this flag is set
|
||
}
|
||
// Special case for the "AutoClusterSystem" when pCS==-1
|
||
if(pCS==(CInstanceGroup*)-1)
|
||
{
|
||
_ClusterSystem = NULL;
|
||
setStateFlag(ClusterSystemAuto, true);
|
||
}
|
||
else
|
||
{
|
||
_ClusterSystem = pCS;
|
||
setStateFlag(ClusterSystemAuto, false);
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
CInstanceGroup* CTransform::getClusterSystem ()
|
||
{
|
||
if(getStateFlag(ClusterSystemAuto))
|
||
return (CInstanceGroup*)-1;
|
||
else
|
||
return _ClusterSystem;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseClip()
|
||
{
|
||
// disable H_AUTO, because slowdown when lot of models (eg 1000-2000 tested in forest)
|
||
//H_AUTO( NL3D_TransformClip );
|
||
|
||
CScene *scene= getOwnerScene();
|
||
CClipTrav &clipTrav= scene->getClipTrav();
|
||
|
||
if ((_ClipDate == clipTrav.CurrentDate) && _Visible)
|
||
return;
|
||
_ClipDate = clipTrav.CurrentDate;
|
||
|
||
// clip: update Visible flag.
|
||
_Visible= false;
|
||
// if at least visible.
|
||
if(_WorldVis)
|
||
{
|
||
// If linked to a SkeletonModel anywhere in the hierarchy, don't clip, and use skeleton model clip result.
|
||
// This works because we are sons of a special node which is not in the clip traversal, and
|
||
// which is traversed at end of the traversal.
|
||
if( _AncestorSkeletonModel!=NULL )
|
||
{
|
||
_Visible= _AncestorSkeletonModel->isClipVisible();
|
||
// Special test: if we are sticked to a skeletonModel, and if we are still visible, maybe we don't have to
|
||
if(_Visible && _FatherSkeletonModel)
|
||
{
|
||
// if our skeletonModel father is displayed with a Lod, maybe we are not to be displayed
|
||
if(_FatherSkeletonModel->isDisplayedAsLodCharacter())
|
||
{
|
||
// We are visible only if we where sticked to the skeleton with forceCLod==true.
|
||
// This is also true if we are actually a skeletonModel
|
||
if(!_ForceCLodSticked)
|
||
// otherWise we are not visible. eg: this is the case of skins and some sticked object
|
||
_Visible= false;
|
||
}
|
||
}
|
||
}
|
||
// else, clip.
|
||
else
|
||
{
|
||
// If the instance is not filtered
|
||
if(scene->getFilterRenderFlags() & _RenderFilterType)
|
||
{
|
||
// User cliping enabled ?
|
||
if (_StateFlags & UserClipping)
|
||
_Visible= true;
|
||
else
|
||
_Visible= clip();
|
||
}
|
||
}
|
||
}
|
||
|
||
// if visible, add to list.
|
||
if(_Visible)
|
||
{
|
||
// add this model to the visibility list.
|
||
clipTrav.addVisibleModel(this);
|
||
|
||
// Has not an ancestor skeleton model?
|
||
if( _AncestorSkeletonModel==NULL )
|
||
{
|
||
// If needed, insert the model in the lighted list.
|
||
// don't insert if has an ancestorSkeletonModel, because in this case, result is driven by
|
||
// the _LightContribution of the _AncestorSkeletonModel.
|
||
if( isLightable() )
|
||
scene->getLightTrav().addLightedModel(this);
|
||
|
||
// If needed, insert the model in the animDetail list.
|
||
// don't insert if has an ancestoreSkeletonModel, because in this case, this ancestore will
|
||
// animDetail through the hierarchy...
|
||
if( isAnimDetailable() )
|
||
scene->getAnimDetailTrav().addVisibleModel(this);
|
||
}
|
||
|
||
// If needed, Add it to the loadBalancing trav
|
||
if( isLoadBalancable() )
|
||
scene->getLoadBalancingTrav().addVisibleModel(this);
|
||
|
||
// If needed, insert the model in the render list.
|
||
if( isRenderable() )
|
||
scene->getRenderTrav().addRenderModel(this);
|
||
}
|
||
|
||
// Traverse the Clip sons.
|
||
uint num= clipGetNumChildren();
|
||
for(uint i=0;i<num;i++)
|
||
clipGetChild(i)->traverseClip();
|
||
}
|
||
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// AnimDetail Trav
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::updateWorldMatrixFromFather()
|
||
{
|
||
// If I am not skinned, and If I have a skeleton ancestor
|
||
if(!isSkinned() && _AncestorSkeletonModel )
|
||
{
|
||
// Compute the HRC _WorldMatrix.
|
||
// if I am not sticked.
|
||
if(!_FatherSkeletonModel)
|
||
{
|
||
// get the normal father worldMatrix in Hrc.
|
||
CTransform *fatherTransform= hrcGetParent();
|
||
// if exist
|
||
if(fatherTransform)
|
||
{
|
||
const CMatrix &parentWM= fatherTransform->_WorldMatrix;
|
||
// combine worldMatrix
|
||
_WorldMatrix= parentWM * _LocalMatrix;
|
||
}
|
||
else
|
||
_WorldMatrix= _LocalMatrix;
|
||
}
|
||
else
|
||
{
|
||
// get the worldMatrix of the bone if I am sticked (standard stick)
|
||
if(!getStateFlag(SSSWO))
|
||
{
|
||
const CMatrix &parentWM= _FatherSkeletonModel->Bones[_FatherBoneId].getWorldMatrix();
|
||
// combine worldMatrix
|
||
_WorldMatrix= parentWM * _LocalMatrix;
|
||
}
|
||
// Special SkeletonSpawnScript stick
|
||
else
|
||
{
|
||
// The parent matrix must be computed from a special matrix given to the skeleton model
|
||
CMatrix parentWM;
|
||
parentWM.setRot(CVector::I, _FatherSkeletonModel->getSSSWODir(), CVector::K);
|
||
parentWM.normalize(CMatrix::YZX);
|
||
parentWM.setPos(_FatherSkeletonModel->getSSSWOPos());
|
||
// combine worldMatrix
|
||
_WorldMatrix= parentWM * _LocalMatrix;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseAnimDetailWithoutUpdateWorldMatrix()
|
||
{
|
||
// AnimDetail behavior: animate only if not clipped.
|
||
// NB: no need to test because of VisibilityList use.
|
||
|
||
// test if the refptr is NULL or not (RefPtr).
|
||
CChannelMixer *chanmix= _ChannelMixer;
|
||
if(chanmix)
|
||
{
|
||
// eval detail!!
|
||
chanmix->eval(true, getOwnerScene()->getAnimDetailTrav().CurrentDate);
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseAnimDetail()
|
||
{
|
||
// First, test if I must update my worldMatrix because of the ancestorSkeleton scheme
|
||
updateWorldMatrixFromFather();
|
||
|
||
// eval channelMixer.
|
||
traverseAnimDetailWithoutUpdateWorldMatrix();
|
||
|
||
// NB: if want to add something, do it in traverseAnimDetailWithoutUpdateWorldMatrix(), because
|
||
// CSkeletonModel doesn't call CTransform::traverseAnimDetail()
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// LoadBalancing
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseLoadBalancing()
|
||
{
|
||
// noop
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Lighting.
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::resetLighting()
|
||
{
|
||
// if the model is already isNeedUpdateLighting, his light setup is reseted.
|
||
// so no need to reset again
|
||
|
||
if(isNeedUpdateLighting())
|
||
return;
|
||
|
||
|
||
// For all light not in FrozenStaticLightSetup, remove me from their list
|
||
uint startLight= 0;
|
||
if(_LightContribution.FrozenStaticLightSetup)
|
||
{
|
||
startLight= _LightContribution.NumFrozenStaticLight;
|
||
}
|
||
|
||
// for all light in the list, remove me from their list.
|
||
for(uint i=startLight; i<NL3D_MAX_LIGHT_CONTRIBUTION; i++)
|
||
{
|
||
CPointLight *pl= _LightContribution.PointLight[i];
|
||
// if end of list, break.
|
||
if(!pl)
|
||
break;
|
||
else
|
||
{
|
||
// remove me from this light.
|
||
pl->removeLightedModel(_LightContribution.TransformIterator[i]);
|
||
}
|
||
}
|
||
// empty the list.
|
||
if(startLight<NL3D_MAX_LIGHT_CONTRIBUTION)
|
||
_LightContribution.PointLight[startLight]= NULL;
|
||
|
||
|
||
// the model needs to update his lighting.
|
||
setStateFlag(IsNeedUpdateLighting, true);
|
||
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::freezeStaticLightSetup(CPointLight *pointLight[NL3D_MAX_LIGHT_CONTRIBUTION],
|
||
uint numPointLights, uint8 sunContribution, CPointLight *frozenAmbientlight)
|
||
{
|
||
nlassert(numPointLights <= NL3D_MAX_LIGHT_CONTRIBUTION);
|
||
|
||
// resetLighting() first.
|
||
resetLighting();
|
||
|
||
// Enable StaticLightSetup.
|
||
_LightContribution.FrozenStaticLightSetup= true;
|
||
_LightContribution.NumFrozenStaticLight= uint8(numPointLights);
|
||
_LightContribution.SunContribution= sunContribution;
|
||
// setup the FrozenAmbientLight
|
||
_LightContribution.FrozenAmbientLight= frozenAmbientlight;
|
||
// Setup other pointLights
|
||
uint i;
|
||
for(i=0;i<numPointLights;i++)
|
||
{
|
||
// set the light
|
||
_LightContribution.PointLight[i]= pointLight[i];
|
||
// Enable at max.
|
||
_LightContribution.Factor[i]= 255;
|
||
// Compute static AttFactor Later because don't have WorlPosition of the model here!!
|
||
setStateFlag(IsNeedUpdateFrozenStaticLightSetup, true);
|
||
|
||
// Do NOT set the iterator, because it is a staticLight.
|
||
}
|
||
// End the list
|
||
if(i<NL3D_MAX_LIGHT_CONTRIBUTION)
|
||
_LightContribution.PointLight[i]= NULL;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::unfreezeStaticLightSetup()
|
||
{
|
||
// resetLighting() first.
|
||
resetLighting();
|
||
|
||
// Disable StaticLightSetup.
|
||
_LightContribution.FrozenStaticLightSetup= false;
|
||
_LightContribution.NumFrozenStaticLight= 0;
|
||
// End the list
|
||
_LightContribution.PointLight[0]= NULL;
|
||
// No more FrozenAmbientLight
|
||
_LightContribution.FrozenAmbientLight= NULL;
|
||
|
||
// Don't need to update StaticLightSetup since no more exist.
|
||
setStateFlag(IsNeedUpdateFrozenStaticLightSetup, false);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseLight()
|
||
{
|
||
// if the model do not need to update his lighting, just skip.
|
||
if(!isNeedUpdateLighting())
|
||
return;
|
||
|
||
|
||
// If a freezeStaticLightSetup() has been called on this model recently.
|
||
if(isNeedUpdateFrozenStaticLightSetup())
|
||
{
|
||
// Now, the correct matrix is computed.
|
||
// get the untransformed bbox from the model.
|
||
CAABBox bbox;
|
||
getAABBox(bbox);
|
||
// get transformed center pos of bbox
|
||
CVector worldModelPos= getWorldMatrix() * bbox.getCenter();
|
||
|
||
// So we can compute AttFactor for each static light influencing this static object
|
||
uint numPointLights= _LightContribution.NumFrozenStaticLight;
|
||
for(uint i=0;i<numPointLights;i++)
|
||
{
|
||
const CPointLight *pl= _LightContribution.PointLight[i];
|
||
// don't worry about the precision of floor, because of *255.
|
||
float distToModel= (pl->getPosition() - worldModelPos).norm();
|
||
sint attFactor= NLMISC::OptFastFloor( 255 * pl->computeLinearAttenuation(worldModelPos, distToModel) );
|
||
_LightContribution.AttFactor[i]= (uint8)attFactor;
|
||
}
|
||
|
||
// clean.
|
||
setStateFlag(CTransform::IsNeedUpdateFrozenStaticLightSetup, false);
|
||
}
|
||
|
||
|
||
// see CTransform::clip(), here I am Lightable(), and I have no _AncestorSkeletonModel
|
||
// So I am sure that I really need to recompute my ModelLightContributions.
|
||
CScene *scene= getOwnerScene();
|
||
scene->getLightTrav().LightingManager.computeModelLightContributions(scene->getSunAmbient(), this,
|
||
_LightContribution, _LogicInfo);
|
||
|
||
// done!
|
||
setStateFlag(CTransform::IsNeedUpdateLighting, false);
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Rendering
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::traverseRender()
|
||
{
|
||
// no-op
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::profileRender()
|
||
{
|
||
// no-op
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Hrc Linking
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::hrcLinkSon(CTransform *son)
|
||
{
|
||
if(!son)
|
||
return;
|
||
|
||
// If not unfrozen, can't link
|
||
if (son->_FreezeHRCState != CTransform::FreezeHRCStateDisabled)
|
||
return;
|
||
|
||
// no-op if already me.
|
||
if(son->_HrcParent==this)
|
||
return;
|
||
|
||
// unlink from anyone
|
||
son->hrcUnlink();
|
||
|
||
// link son to me
|
||
_HrcSons.insert(son, &son->_HrcNode);
|
||
|
||
// link me to son
|
||
son->_HrcParent= this;
|
||
|
||
// Backup parent
|
||
son->_HrcParentUnfreeze= this;
|
||
|
||
// my son should recompute his worldMatrix!
|
||
son->_WorldDate= -1;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::hrcUnlink()
|
||
{
|
||
// no-op if already NULL
|
||
if(_HrcParent==NULL)
|
||
return;
|
||
|
||
// if ForceClipRoot flag is set, then the fx can't be linked elsewhere in the hierarchy
|
||
nlassert(!getStateFlag(ForceClipRoot));
|
||
|
||
// unlink my parent from me.
|
||
_HrcNode.unlink();
|
||
|
||
// unlink me from parent
|
||
_HrcParent= NULL;
|
||
_HrcParentUnfreeze= NULL;
|
||
|
||
// I should recompute my worldMatrix (well not useful since not linked, but still do it...)
|
||
_WorldDate= -1;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
CTransform *CTransform::hrcGetChild(uint index) const
|
||
{
|
||
nlassert(index < _HrcSons.size());
|
||
return (const_cast<CTransform*>(this))->_HrcSons.begin()[index];
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// Clip Linking
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
|
||
// ***************************************************************************
|
||
void CTransform::clipAddChild(CTransform *son)
|
||
{
|
||
if(!son)
|
||
return;
|
||
|
||
// if already linked, no-op.
|
||
if(son->clipHasParent(this))
|
||
return;
|
||
|
||
// add a new parent entry for our son.
|
||
CClipNode *clipNode= new CClipNode;
|
||
son->_ClipParents.push_back(clipNode);
|
||
|
||
// link the son to us
|
||
clipNode->Parent= this;
|
||
|
||
// link us to the son
|
||
_ClipSons.insert(son, &clipNode->ClipNode);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::clipDelChild(CTransform *son)
|
||
{
|
||
if(!son)
|
||
return;
|
||
|
||
// try to remove from me from my parent
|
||
son->clipDelFromParent(this);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::clipUnlinkFromAll()
|
||
{
|
||
// unlink from all parent clip
|
||
while( clipGetNumParents() )
|
||
{
|
||
clipDelFromParent( clipGetParent(0) );
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
CTransform *CTransform::clipGetParent(uint index) const
|
||
{
|
||
nlassert(index < _ClipParents.size());
|
||
return _ClipParents[index]->Parent;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
CTransform *CTransform::clipGetChild(uint index) const
|
||
{
|
||
nlassert(index < _ClipSons.size());
|
||
return (const_cast<CTransform*>(this))->_ClipSons.begin()[index];
|
||
}
|
||
|
||
|
||
// ***************************************************************************
|
||
bool CTransform::clipHasParent(CTransform *parent)
|
||
{
|
||
// search O(n) for all parents
|
||
for(uint i=0;i<_ClipParents.size();i++)
|
||
{
|
||
if(_ClipParents[i]->Parent==parent)
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::clipDelFromParent(CTransform *parent)
|
||
{
|
||
// search O(n) for all Parents
|
||
uint numParents= (uint)_ClipParents.size();
|
||
for(uint i=0;i<numParents;i++)
|
||
{
|
||
if(_ClipParents[i]->Parent==parent)
|
||
{
|
||
// found! remove me from my parent list
|
||
_ClipParents[i]->ClipNode.unlink();
|
||
|
||
// remove this parent entry. swap with last
|
||
swap(_ClipParents[i], _ClipParents[numParents-1]);
|
||
|
||
// and delete last.
|
||
delete _ClipParents[numParents-1];
|
||
_ClipParents.resize(numParents-1);
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setUserClipping(bool enable)
|
||
{
|
||
setStateFlag (UserClipping, enable);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
bool CTransform::getUserClipping() const
|
||
{
|
||
return getStateFlag(UserClipping) != 0;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
// ShadowMap
|
||
// ***************************************************************************
|
||
// ***************************************************************************
|
||
|
||
// ***************************************************************************
|
||
void CTransform::getReceiverBBox(CAABBox &bbox)
|
||
{
|
||
bbox.setCenter(CVector::Null);
|
||
bbox.setHalfSize(CVector::Null);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::enableCastShadowMap(bool state)
|
||
{
|
||
bool precState= canCastShadowMap();
|
||
|
||
if(modelCanCastShadowMap())
|
||
setStateFlag(IsFinalShadowMapCaster, state);
|
||
else
|
||
setStateFlag(IsFinalShadowMapCaster, false);
|
||
|
||
// if just enabled, create the shadowMap
|
||
if(canCastShadowMap() && !precState)
|
||
{
|
||
createShadowMap();
|
||
// The user must have created it.
|
||
nlassert(getShadowMap());
|
||
}
|
||
// if just disabled, free ressource
|
||
else if(!canCastShadowMap() && precState)
|
||
{
|
||
deleteShadowMap();
|
||
}
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::forceCompute()
|
||
{
|
||
// if father is a skeleton, force to compute the bone we are sticked to
|
||
if (_FatherSkeletonModel)
|
||
{
|
||
_FatherSkeletonModel->forceComputeBone(_FatherBoneId);
|
||
}
|
||
else
|
||
{
|
||
// force to comp<6D>te the father
|
||
if (_HrcParent)
|
||
{
|
||
_HrcParent->forceCompute();
|
||
}
|
||
}
|
||
// compute
|
||
update();
|
||
updateWorldMatrixFromFather();
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setForceClipRoot(bool forceClipRoot)
|
||
{
|
||
if (forceClipRoot == (getStateFlag(ForceClipRoot) != 0)) return;
|
||
if (forceClipRoot)
|
||
{
|
||
// unlink from previous father and link to the root
|
||
hrcUnlink();
|
||
if (_OwnerScene)
|
||
{
|
||
_OwnerScene->getRoot()->hrcLinkSon(this);
|
||
}
|
||
setClusterSystem(NULL);
|
||
}
|
||
setStateFlag(ForceClipRoot, forceClipRoot);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
UTransform *CTransform::buildMatchingUserInterfaceObject()
|
||
{
|
||
return new UTransform(this);
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setShadowMapDirectionZThreshold(float zthre)
|
||
{
|
||
clamp(zthre, -1.f, 1.f);
|
||
_ShadowMapDirectionZThreshold= zthre;
|
||
}
|
||
|
||
// ***************************************************************************
|
||
void CTransform::setShadowMapMaxDepth(float depth)
|
||
{
|
||
depth= max(0.f, depth);
|
||
_ShadowMapMaxDepth= depth;
|
||
}
|
||
|
||
|
||
}
|