|
|
|
/*==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/>.
|
|
|
|
|
|
|
|
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->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);
|
|
|
|
}
|