You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

870 lines
24 KiB

/*==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 <http://www.gnu.org/licenses/>.
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->ReadSwap32();
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->ReadSwap32();
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->WriteSwap32(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->WriteSwap32(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;i<GetNumModifiers(); i++)
if (fModifiers[i] && !fModifiers[i]->IsFinal())
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);
}