/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plSceneObject.h"
#include "plDrawInterface.h"
#include "plSimulationInterface.h"
#include "plCoordinateInterface.h"
#include "plAudioInterface.h"
#include "pnDispatch/plDispatch.h"
#include "pnModifier/plModifier.h"
#include "pnMessage/plMessage.h"
#include "pnMessage/plRefMsg.h"
#include "plDrawable.h"
#include "plPhysical.h"
#include "plAudible.h"
#include "pnMessage/plTimeMsg.h"
#include "pnMessage/plCorrectionMsg.h"
#include "pnMessage/plWarpMsg.h"
#include "pnMessage/plSoundMsg.h"
#include "pnMessage/plEnableMsg.h"
#include "pnMessage/plAttachMsg.h"
#include "pnMessage/plObjRefMsg.h"
#include "pnMessage/plNodeRefMsg.h"
#include "pnMessage/plIntRefMsg.h"
#include "pnMessage/plSimulationSynchMsg.h"
#include "pnMessage/plSimulationMsg.h"
#include "pnMessage/plNodeChangeMsg.h"
#include "pnMessage/plSelfDestructMsg.h"
#include "pnKeyedObject/plKey.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "plCreatableIndex.h" // For plLightInfo::Index(), so we don't have to include plLightInfo.h
int dbgCurrentTest = 0;
plSceneObject::plSceneObject()
: fDrawInterface(nil),
fSimulationInterface(nil),
fCoordinateInterface(nil),
fAudioInterface(nil),
fSceneNode(nil)
{
}
plSceneObject::~plSceneObject()
{
SetDrawInterface(nil);
SetSimulationInterface(nil);
SetCoordinateInterface(nil);
SetAudioInterface(nil);
IRemoveAllGenerics();
int i;
int knt;
knt = fModifiers.GetCount();
for( i = 0; i < knt; i++ )
{
if( fModifiers[i] )
fModifiers[i]->RemoveTarget(this);
}
}
void plSceneObject::Read(hsStream* stream, hsResMgr* mgr)
{
plSynchedObject::Read(stream, mgr);
// Interfaces will attach themselves to us on read.
// DI
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
// SI
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
// CI
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
// AI
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
int i;
int nGen = stream->ReadLE32();
fGenerics.SetCount(0);
for( i = 0; i < nGen; i++ )
{
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
}
plObjRefMsg* refMsg;
int nOldMods=fModifiers.GetCount(); // existng modifiers created during interface loading
int nNewMods = stream->ReadLE32();
fModifiers.ExpandAndZero(nOldMods+nNewMods); // reserve space for new modifiers+existing modifiers
for( i = nOldMods; i < nOldMods+nNewMods; i++ )
{
refMsg = TRACKED_NEW plObjRefMsg(GetKey(), plRefMsg::kOnCreate, i, plObjRefMsg::kModifier);
mgr->ReadKeyNotifyMe(stream,refMsg, plRefFlags::kActiveRef);
}
plKey nodeKey = mgr->ReadKey(stream);
// SetSceneNode(nodeKey);
fSceneNode = nodeKey;
}
void plSceneObject::Write(hsStream* stream, hsResMgr* mgr)
{
plSynchedObject::Write(stream, mgr);
mgr->WriteKey(stream, fDrawInterface);
mgr->WriteKey(stream, fSimulationInterface);
mgr->WriteKey(stream, fCoordinateInterface);
mgr->WriteKey(stream, fAudioInterface);
int i;
stream->WriteLE32(fGenerics.GetCount());
for( i = 0; i < fGenerics.GetCount(); i++ )
mgr->WriteKey(stream, fGenerics[i]);
for( i = fModifiers.GetCount() - 1; i >= 0; i--)
if (fModifiers[i]->GetKey() == nil)
RemoveModifier(fModifiers[i]);
stream->WriteLE32(fModifiers.GetCount());
for( i = 0; i < fModifiers.GetCount(); i++ )
mgr->WriteKey(stream,fModifiers[i]);
mgr->WriteKey(stream, fSceneNode);
}
//// ReleaseData //////////////////////////////////////////////////////////////
// Called by SceneViewer to release the data for this sceneObject (really
// just a switchboard).
void plSceneObject::ReleaseData( void )
{
if( fDrawInterface )
fDrawInterface->ReleaseData();
if( fSimulationInterface )
fSimulationInterface->ReleaseData();
if( fCoordinateInterface )
fCoordinateInterface->ReleaseData();
if( fAudioInterface )
fAudioInterface->ReleaseData();
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] )
fGenerics[i]->ReleaseData();
}
}
void plSceneObject::FlushTransform()
{
if( fCoordinateInterface )
fCoordinateInterface->FlushTransform();
}
#include "plProfile.h"
plProfile_CreateTimer("SOTrans", "Object", SOTrans);
plProfile_CreateTimer(" SODITrans", "Object", SODITrans);
plProfile_CreateTimer(" SOSITrans", "Object", SOSITrans);
plProfile_CreateTimer(" SOAITrans", "Object", SOAITrans);
plProfile_CreateTimer(" SOGITrans", "Object", SOGITrans);
plProfile_CreateTimer(" SOMOTrans", "Object", SOMOTrans);
void plSceneObject::ISetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
plProfile_BeginTiming(SOTrans);
plProfile_BeginTiming(SODITrans);
if( fDrawInterface )
fDrawInterface->SetTransform(l2w, w2l);
plProfile_EndTiming(SODITrans);
plProfile_BeginTiming(SOSITrans);
if( fSimulationInterface )
{
if(fCoordinateInterface)
{
UInt16 whyTransformed = fCoordinateInterface->GetReasons();
if(whyTransformed != plCoordinateInterface::kReasonPhysics)
{
// if we were transformed by anything but physics, let physics know
// otherwise we're not even going to tell physics
fSimulationInterface->SetTransform(l2w, w2l);
} else {
int moreSunshine = 10;
}
fCoordinateInterface->ClearReasons();
} else {
int somethingToBreakOn = 10;
// if there's not coordinate interface, there's no reason to move the simulation interface
}
}
plProfile_EndTiming(SOSITrans);
plProfile_BeginTiming(SOAITrans);
if( fAudioInterface )
fAudioInterface->SetTransform(l2w, w2l);
plProfile_EndTiming(SOAITrans);
plProfile_BeginTiming(SOGITrans);
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] )
fGenerics[i]->SetTransform(l2w, w2l);
}
plProfile_EndTiming(SOGITrans);
plProfile_BeginTiming(SOMOTrans);
for( i = 0; i < fModifiers.GetCount(); i++ )
{
if( fModifiers[i] )
fModifiers[i]->SetTransform(l2w, w2l);
}
plProfile_EndTiming(SOMOTrans);
plProfile_EndTiming(SOTrans);
}
void plSceneObject::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
if( fCoordinateInterface )
fCoordinateInterface->SetTransform(l2w, w2l);
}
hsMatrix44 plSceneObject::GetLocalToWorld() const
{
hsMatrix44 l2w;
if( fCoordinateInterface )
l2w = fCoordinateInterface->GetLocalToWorld();
else
l2w.Reset();
return l2w;
}
hsMatrix44 plSceneObject::GetWorldToLocal() const
{
hsMatrix44 w2l;
if( fCoordinateInterface )
w2l = fCoordinateInterface->GetWorldToLocal();
else
w2l.Reset();
return w2l;
}
hsMatrix44 plSceneObject::GetLocalToParent() const
{
hsMatrix44 l2p;
if( fCoordinateInterface )
l2p = fCoordinateInterface->GetLocalToParent();
else
l2p.Reset();
return l2p;
}
hsMatrix44 plSceneObject::GetParentToLocal() const
{
hsMatrix44 p2l;
if( fCoordinateInterface )
p2l = fCoordinateInterface->GetParentToLocal();
else
p2l.Reset();
return p2l;
}
void plSceneObject::IAddModifier(plModifier* mo, int i)
{
if( !mo )
return;
if( i < 0 )
i = fModifiers.GetCount();
fModifiers.ExpandAndZero(i+1);
fModifiers.Set(i, mo);
mo->AddTarget(this);
}
void plSceneObject::IRemoveModifier(plModifier* mo)
{
if( !mo )
return;
int idx = fModifiers.Find(mo);
if( idx != fModifiers.kMissingIndex )
{
mo->RemoveTarget(this);
fModifiers.Remove(idx);
}
}
void plSceneObject::ISetInterface(plObjInterface* iface)
{
hsAssert(iface, "Setting nil interface");
if( plDrawInterface::ConvertNoRef(iface) )
ISetDrawInterface(plDrawInterface::ConvertNoRef(iface));
else if( plSimulationInterface::ConvertNoRef(iface) )
ISetSimulationInterface(plSimulationInterface::ConvertNoRef(iface));
else if( plCoordinateInterface::ConvertNoRef(iface) )
ISetCoordinateInterface(plCoordinateInterface::ConvertNoRef(iface));
else if( plAudioInterface::ConvertNoRef(iface) )
ISetAudioInterface(plAudioInterface::ConvertNoRef(iface));
else
IAddGeneric(iface);
if( iface )
iface->ISetSceneNode(GetSceneNode());
}
void plSceneObject::IRemoveInterface(Int16 idx, plObjInterface* who)
{
if( plFactory::DerivesFrom(plDrawInterface::Index(), idx) )
ISetDrawInterface(nil);
else if( plFactory::DerivesFrom(plSimulationInterface::Index(), idx) )
ISetSimulationInterface(nil);
else if( plFactory::DerivesFrom(plCoordinateInterface::Index(), idx) )
ISetCoordinateInterface(nil);
else if( plFactory::DerivesFrom(plAudioInterface::Index(), idx) )
ISetAudioInterface(nil);
else
IRemoveGeneric(who);
}
hsBool plSceneObject::IPropagateToModifiers(plMessage* msg)
{
hsBool retVal = false;
int i;
int nMods = fModifiers.GetCount();
for( i = 0; i < nMods; i++ )
{
if( fModifiers[i] )
{
plModifier *mod = fModifiers[i];
hsBool modRet = mod->MsgReceive(msg);
retVal |= modRet;
}
}
return retVal;
}
hsBool plSceneObject::Eval(double secs, hsScalar delSecs)
{
UInt32 dirty = ~0L;
hsBool retVal = false;
int i;
for( i = 0; i < fModifiers.GetCount(); i++ )
{
if( fModifiers[i] )
retVal |= fModifiers[i]->IEval(secs, delSecs, dirty);
}
return retVal;
}
void plSceneObject::SetSceneNode(plKey newNode)
{
plKey curNode=GetSceneNode();
if( curNode == newNode )
return;
if( fDrawInterface )
fDrawInterface->ISetSceneNode(newNode);
if( fSimulationInterface )
fSimulationInterface->ISetSceneNode(newNode);
if( fAudioInterface )
fAudioInterface->ISetSceneNode(newNode);
if( fCoordinateInterface )
fCoordinateInterface->ISetSceneNode(newNode);
int i;
for( i = 0; i < GetNumGenerics(); i++ )
{
if( fGenerics[i] )
fGenerics[i]->ISetSceneNode(newNode);
}
if( newNode )
{
plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(newNode, plNodeRefMsg::kOnRequest, -1, plNodeRefMsg::kObject);
plKey key = GetKey(); // for linux build
hsgResMgr::ResMgr()->AddViaNotify(key, refMsg, plRefFlags::kActiveRef);
}
if( curNode)
{
curNode->Release(GetKey());
}
fSceneNode = newNode;
}
plKey plSceneObject::GetSceneNode() const
{
return fSceneNode;
}
void plSceneObject::SetNetGroup(plNetGroupId netGroup)
{
if( !fCoordinateInterface )
plSynchedObject::SetNetGroup(netGroup);
else
fCoordinateInterface->ISetNetGroupRecur(netGroup);
}
const plModifier* plSceneObject::GetModifierByType(UInt16 classIdx) const
{
int i;
for (i = 0; i < fModifiers.GetCount(); i++)
{
plModifier * mod = fModifiers[i];
if (mod && plFactory::DerivesFrom(classIdx, mod->ClassIndex()))
return mod;
}
return nil;
}
hsBool plSceneObject::MsgReceive(plMessage* msg)
{
#if 0 // objects are only in the nil room when they are being paged out
// TEMP - until we have another way to neutralize objects
// for an object in the 'nil' room, ignore most msgs
if (GetSceneNode()==nil && !plNodeChangeMsg::ConvertNoRef(msg) &&
!plRefMsg::ConvertNoRef(msg)&&
!plSelfDestructMsg::ConvertNoRef(msg))
return false;
#endif
hsBool retVal = false;
// If it's a bcast, let our own dispatcher find who's interested.
plTransformMsg* trans;
plEvalMsg* eval = plEvalMsg::ConvertNoRef(msg);
plAttachMsg* att = nil;
if( eval )
{
// Switched things over so that modifiers register for the eval message themselves,
// and can be smart about not evaluating if they know it's unneccessary.
//Eval(eval->DSeconds(), eval->DelSeconds());
return true;
}
else
if((trans = plTransformMsg::ConvertNoRef(msg))) // also catches the derived plDelayedTransformMsg
{
if( fCoordinateInterface )
{
// flush any dirty transforms
fCoordinateInterface->ITransformChanged(false, 0, trans->ClassIndex() == plTransformMsg::Index());
}
return true;
}
else
if((att = plAttachMsg::ConvertNoRef(msg)))
{
if( fCoordinateInterface )
{
plSceneObject *child = plSceneObject::ConvertNoRef(att->GetRef());
if( child )
{
if( !fCoordinateInterface )
{
// If we have no coordinate interface, we could make ourselves one here,
// but for now it's an error.
hsAssert(false, "Trying to attach a child when we have no coordinateInterface");
return true;
}
if( !child->GetVolatileCoordinateInterface() )
{
// If the child has no coordinate interface, we could add one to it here,
// but for now it's an error.
hsAssert(false, "Trying to attach a child who has no coordinateInterface");
return true;
}
plIntRefMsg* intRefMsg = TRACKED_NEW plIntRefMsg(fCoordinateInterface->GetKey(), att->GetContext(), -1, plIntRefMsg::kChildObject);
intRefMsg->SetRef(child);
hsgResMgr::ResMgr()->AddViaNotify(intRefMsg, plRefFlags::kPassiveRef);
}
}
}
else // Am I the final destination?
{
retVal = IMsgHandle(msg);
}
if( msg->HasBCastFlag(plMessage::kPropagateToModifiers) )
{
retVal |= IPropagateToModifiers(msg);
}
if (msg->HasBCastFlag(plMessage::kPropagateToChildren))
{
const plCoordinateInterface* ci = GetCoordinateInterface();
for (int i = 0; i < ci->GetNumChildren(); i++)
{
plSceneObject* child = (plSceneObject*)ci->GetChild(i)->GetOwner();
if (child)
{
hsBool modRet = child->MsgReceive(msg);
retVal |= modRet;
}
}
}
// Might want an option to propagate messages to children here.
return plSynchedObject::MsgReceive(msg);
}
hsBool plSceneObject::IMsgHandle(plMessage* msg)
{
// To start with, plSceneObject only handles messages to add or remove
// references. Current references are other plSceneObjects and plModifiers
plObjRefMsg* refMsg = plObjRefMsg::ConvertNoRef(msg);
if( refMsg )
{
switch( refMsg->fType )
{
case plObjRefMsg::kModifier:
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
plModifier* mod = plModifier::ConvertNoRef(refMsg->GetRef());
IAddModifier(mod, refMsg->fWhich);
}
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
plModifier* mod = (plModifier*)refMsg->GetRef();
IRemoveModifier(mod);
}
}
return true;
case plObjRefMsg::kInterface:
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
plObjInterface* oi = plObjInterface::ConvertNoRef(refMsg->GetRef());
ISetInterface(oi);
}
else
if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
plObjInterface* oi = (plObjInterface*)refMsg->GetRef();
// TODO - This will crash if oi's already been deleted
IRemoveInterface(oi->ClassIndex(), oi);
}
}
return true;
}
return false;
}
plNodeChangeMsg* nodeChange = plNodeChangeMsg::ConvertNoRef(msg);
if( nodeChange )
{
SetSceneNode(nodeChange->GetNodeKey());
return true;
}
if( plIntRefMsg::ConvertNoRef(msg) )
{
if (fCoordinateInterface)
fCoordinateInterface->MsgReceive(msg);
if (fAudioInterface)
fAudioInterface->MsgReceive(msg);
return true;
}
if (plCorrectionMsg::ConvertNoRef(msg))
{
hsAssert(fCoordinateInterface, "Unimplemented, also need to register this one we just made with the resource manager");
if (fCoordinateInterface)
fCoordinateInterface->MsgReceive(msg);
return true;
}
// check for generic enable/disable message (passed to interfaces)
plEnableMsg* pEnableMsg = plEnableMsg::ConvertNoRef( msg );
if (pEnableMsg)
{
if( pEnableMsg->Cmd(plEnableMsg::kDrawable) )
{
plDrawInterface* di = GetVolatileDrawInterface();
if( di )
di->MsgReceive(msg);
plObjInterface* li = GetVolatileGenericInterface(CLASS_INDEX_SCOPED(plLightInfo));
if( li )
li->MsgReceive(msg);
}
if ( pEnableMsg->Cmd(plEnableMsg::kAll) && GetDrawInterface() )
GetVolatileDrawInterface()->MsgReceive(msg);
if ( pEnableMsg->Cmd( plEnableMsg::kPhysical ) || pEnableMsg->Cmd( plEnableMsg::kAll) )
{
if ( GetSimulationInterface() )
{
GetVolatileSimulationInterface()->MsgReceive(msg);
}
else
{
// if someone is trying to disable the physics on a sceneobject that doesn't have a physics interface...
// they might be trying to disable the avatar when the PhysX controller is being used
// ...so, look to see if this is an avatar object, and tell the avatar to disable the physics
IPropagateToModifiers(msg);
}
}
if ( (pEnableMsg->Cmd( plEnableMsg::kAudible ) || pEnableMsg->Cmd( plEnableMsg::kAll )) && GetAudioInterface() )
GetVolatileAudioInterface()->MsgReceive(msg);
if( pEnableMsg->Cmd( plEnableMsg::kAll ) )
{
IPropagateToGenerics(pEnableMsg);
}
else if( pEnableMsg->Cmd( plEnableMsg::kByType ) )
{
IPropagateToGenerics(pEnableMsg->Types(), pEnableMsg);
}
return true;
}
// warp message
if( plWarpMsg::ConvertNoRef(msg) )
{
// if there's a simulation interface, it needs to know about the warp
// *** it would probably be better if it got this from the coordinate interface, as
// *** only the coordinate interface knows to propagate it to children.
// if(fSimulationInterface)
// {
// fSimulationInterface->MsgReceive(msg);
// }
// the coordinate interface always gets the warp
if (fCoordinateInterface)
{
fCoordinateInterface->MsgReceive(msg);
}
return true;
}
if ( plSimulationMsg::ConvertNoRef(msg) )
{
if(fSimulationInterface)
{
fSimulationInterface->MsgReceive(msg);
}
return true;
}
// audio message
if (plSoundMsg::ConvertNoRef(msg) )
{
if( fAudioInterface )
return(GetVolatileAudioInterface()->MsgReceive(msg));
return true;
}
return false;
}
void plSceneObject::IPropagateToGenerics(const hsBitVector& types, plMessage* msg)
{
hsBitIterator iter(types);
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] )
{
for( iter.Begin(); !iter.End(); iter.Advance() )
{
if( plFactory::DerivesFrom(iter.Current(), fGenerics[i]->ClassIndex()) )
{
fGenerics[i]->MsgReceive(msg);
break;
}
}
}
}
}
void plSceneObject::IPropagateToGenerics(plMessage* msg)
{
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] )
fGenerics[i]->MsgReceive(msg);
}
}
plObjInterface* plSceneObject::GetVolatileGenericInterface(UInt16 classIdx) const
{
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] && plFactory::DerivesFrom(classIdx, fGenerics[i]->ClassIndex()) )
return fGenerics[i];
}
return nil;
}
void plSceneObject::IAddGeneric(plObjInterface* gen)
{
if( gen )
{
if( fGenerics.kMissingIndex == fGenerics.Find(gen) )
{
fGenerics.Append(gen);
gen->ISetOwner(this);
}
}
}
void plSceneObject::IRemoveGeneric(plObjInterface* gen)
{
if( gen )
{
int idx = fGenerics.Find(gen);
if( fGenerics.kMissingIndex != idx )
{
gen->ISetOwner(nil);
fGenerics.Remove(idx);
}
}
}
void plSceneObject::IRemoveAllGenerics()
{
int i;
for( i = 0; i < fGenerics.GetCount(); i++ )
{
if( fGenerics[i] )
fGenerics[i]->ISetOwner(nil);
}
fGenerics.Reset();
}
void plSceneObject::ISetDrawInterface(plDrawInterface* di)
{
if( fDrawInterface != di )
{
if( fDrawInterface )
fDrawInterface->ISetOwner(nil);
fDrawInterface = di;
if( di )
di->ISetOwner(this);
}
}
void plSceneObject::ISetSimulationInterface(plSimulationInterface* si)
{
if( fSimulationInterface != si )
{
if( fSimulationInterface )
fSimulationInterface->ISetOwner(nil);
fSimulationInterface = si;
if( si )
si->ISetOwner(this);
}
}
void plSceneObject::ISetAudioInterface(plAudioInterface* ai)
{
if( fAudioInterface != ai )
{
if( fAudioInterface )
fAudioInterface->ISetOwner(nil);
fAudioInterface = ai;
if( ai )
ai->ISetOwner(this);
}
}
void plSceneObject::ISetCoordinateInterface(plCoordinateInterface* ci)
{
if( fCoordinateInterface != ci )
{
if( fCoordinateInterface )
fCoordinateInterface->ISetOwner(nil);
fCoordinateInterface = ci;
if( ci )
ci->ISetOwner(this);
}
}
//
// "is ready to process Loads"? Check base class and modifiers.
//
hsBool plSceneObject::IsFinal()
{
if (!plSynchedObject::IsFinal())
return false;
int i;
for(i=0;iIsFinal())
return false;
return true;
}
// Export only. Interfaces perm on object.
void plSceneObject::SetDrawInterface(plDrawInterface* di)
{
ISetDrawInterface(di);
}
void plSceneObject::SetSimulationInterface(plSimulationInterface* si)
{
ISetSimulationInterface(si);
}
void plSceneObject::SetAudioInterface(plAudioInterface* ai)
{
ISetAudioInterface(ai);
}
void plSceneObject::SetCoordinateInterface(plCoordinateInterface* ci)
{
ISetCoordinateInterface(ci);
}
void plSceneObject::AddModifier(plModifier* mo)
{
IAddModifier(mo, fModifiers.GetCount());
}
void plSceneObject::RemoveModifier(plModifier* mo)
{
IRemoveModifier(mo);
}