1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-18 11:19:10 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
jwplatt
2011-03-12 12:34:52 -05:00
commit b970ae4bad
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,361 @@
/*==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 "plAudioInterface.h"
#include "plAudible.h"
#include "../pnMessage/plAudioSysMsg.h"
#include "../pnMessage/plSoundMsg.h"
#include "hsBounds.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "../pnKeyedObject/plKey.h"
#include "plSceneObject.h"
#include "plgDispatch.h"
#include "../pnMessage/plEnableMsg.h"
#include "../pnMessage/plIntRefMsg.h"
#include "plCoordinateInterface.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../pnMessage/plProxyDrawMsg.h"
#include "../pnNetCommon/plNetApp.h"
#include "hsTimer.h"
plAudioInterface::plAudioInterface()
: fAudible(nil), fAudibleInited( false )
{
fRegisteredForASysMsg = false;
}
plAudioInterface::~plAudioInterface()
{
}
void plAudioInterface::SetProperty(int prop, hsBool on)
{
plObjInterface::SetProperty(prop, on);
if( fAudible )
fAudible->SetProperty(prop, on);
}
plSound* plAudioInterface::GetSound(int i) const
{
if( fAudible )
return fAudible->GetSound(i);
return nil;
}
int plAudioInterface::GetSoundIndex(const char *keyname)
{
if( fAudible )
return fAudible->GetSoundIndex(keyname);
else
return -1;
}
int plAudioInterface::GetNumSounds() const
{
if( fAudible )
return fAudible->GetNumSounds();
return 0;
}
// set the filename of sound[index] within the audible
void plAudioInterface::SetSoundFilename(int index, const char *filename, bool isCompressed)
{
if(fAudible)
fAudible->SetFilename(index, filename, isCompressed);
}
void plAudioInterface::ISetSceneNode(plKey key)
{
if( fAudible )
{
fAudible->SetSceneNode(key);
if( !fAudibleInited )
{
int isLocal = IsLocallyOwned();
plKey localKey = ( plNetClientApp::GetInstance() != nil ) ? plNetClientApp::GetInstance()->GetLocalPlayerKey() : nil;
if( fOwner && fOwner->GetKey() == localKey )
isLocal = true;
else
isLocal = false;
fAudible->Init( isLocal );//( isLocal == plSynchedObject::kYes ) );
fAudibleInited = true;
}
}
}
void plAudioInterface::ISetOwner(plSceneObject* owner)
{
plObjInterface::ISetOwner(owner);
if( owner && !fRegisteredForASysMsg )
{
plgDispatch::Dispatch()->RegisterForExactType(plAudioSysMsg::Index(), GetKey());
fRegisteredForASysMsg = true;
}
else if( owner == nil && fRegisteredForASysMsg )
{
plgDispatch::Dispatch()->UnRegisterForExactType(plAudioSysMsg::Index(), GetKey());
fRegisteredForASysMsg = false;
}
if (fAudible)
fAudible->SetSceneObject(owner ? owner->GetKey() : nil);
}
void plAudioInterface::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
if( fAudible )
fAudible->SetTransform(l2w, w2l);
}
void plAudioInterface::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
plIntRefMsg* refMsg = TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kAudible);
mgr->ReadKeyNotifyMe(s, refMsg, plRefFlags::kActiveRef);
}
void plAudioInterface::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
mgr->WriteKey(s,fAudible);
}
void plAudioInterface::ISetAudible(plAudible* aud)
{
fAudible = aud;
if( fAudible )
{
fAudible->SetSceneNode(GetSceneNode());
if (fOwner)
fAudible->SetSceneObject(fOwner->GetKey());
}
plAudioSysMsg* pMsg = TRACKED_NEW plAudioSysMsg( plAudioSysMsg::kPing );
pMsg->SetSender(GetKey());
// pMsg->SetBCastFlag(plMessage::kBCastByExactType, false);
plgDispatch::MsgSend( pMsg );
}
void plAudioInterface::IRemoveAudible(plAudible* aud)
{
hsAssert(aud == fAudible, "Removing Audible I don't have");
fAudible = nil;
}
hsBool plAudioInterface::MsgReceive(plMessage* msg)
{
plIntRefMsg* intRefMsg = plIntRefMsg::ConvertNoRef(msg);
if( intRefMsg )
{
switch( intRefMsg->fType )
{
case plIntRefMsg::kAudible:
if( intRefMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
IRemoveAudible(plAudible::ConvertNoRef(intRefMsg->GetRef()));
}
else
{
ISetAudible(plAudible::ConvertNoRef(intRefMsg->GetRef()));
}
return true;
default:
break;
}
}
plSoundMsg* pSoundMsg = plSoundMsg::ConvertNoRef( msg );
if (pSoundMsg)
{
if (!fAudible)
return false;
if (pSoundMsg->Cmd( plSoundMsg::kAddCallbacks))
fAudible->AddCallbacks( pSoundMsg );
if (pSoundMsg->Cmd( plSoundMsg::kRemoveCallbacks))
fAudible->RemoveCallbacks( pSoundMsg );
if (pSoundMsg->Cmd( plSoundMsg::kStop ) )
fAudible->Stop(pSoundMsg->fIndex);
if (pSoundMsg->Cmd( plSoundMsg::kGoToTime ) )
fAudible->SetTime(pSoundMsg->fTime, pSoundMsg->fIndex);
if (pSoundMsg->Cmd( plSoundMsg::kPlay ) )
fAudible->Play(pSoundMsg->fIndex);
if(pSoundMsg->Cmd( plSoundMsg::kSynchedPlay))
fAudible->SynchedPlay(pSoundMsg->fIndex);
if (pSoundMsg->Cmd( plSoundMsg::kSetLooping ) )
fAudible->SetLooping(true,pSoundMsg->fIndex);
if (pSoundMsg->Cmd( plSoundMsg::kUnSetLooping ) )
fAudible->SetLooping(false,pSoundMsg->fIndex);
if (pSoundMsg->Cmd( plSoundMsg::kToggleState ) )
{
if (fAudible->IsPlaying(pSoundMsg->fIndex))
fAudible->Stop(pSoundMsg->fIndex);
else
fAudible->Play(pSoundMsg->fIndex);
}
if (pSoundMsg->Cmd( plSoundMsg::kGetStatus ) )
{
fAudible->GetStatus(pSoundMsg);
}
if (pSoundMsg->Cmd( plSoundMsg::kGetNumSounds ) )
{
plSoundMsg* pReply = TRACKED_NEW plSoundMsg;
pReply->fIndex = fAudible->GetNumSounds();
pReply->AddReceiver(pSoundMsg->GetSender());
pReply->SetCmd( plSoundMsg::kGetNumSounds );
plgDispatch::MsgSend(pReply);
}
if( pSoundMsg->Cmd( plSoundMsg::kSetVolume ) )
{
fAudible->SetVolume( pSoundMsg->fVolume, pSoundMsg->fIndex );
}
if ( pSoundMsg->Cmd( plSoundMsg::kSetTalkIcon ) )
{
fAudible->SetTalkIcon(pSoundMsg->fIndex, pSoundMsg->fNameStr);
}
if ( pSoundMsg->Cmd( plSoundMsg::kClearTalkIcon ) )
{
fAudible->ClearTalkIcon();
}
if ( pSoundMsg->Cmd( plSoundMsg::kSetFadeIn ) )
{
fAudible->SetFadeIn( (int)pSoundMsg->fFadeType, pSoundMsg->fVolume, pSoundMsg->fIndex );
}
if ( pSoundMsg->Cmd( plSoundMsg::kSetFadeOut ) )
{
fAudible->SetFadeOut( (int)pSoundMsg->fFadeType, pSoundMsg->fVolume, pSoundMsg->fIndex );
}
if( pSoundMsg->Cmd( plSoundMsg::kFastForwardPlay ) )
{
fAudible->FastForwardPlay(pSoundMsg->fIndex);
}
if(pSoundMsg->Cmd(plSoundMsg::kFastForwardToggle) )
{
fAudible->FastForwardToggle(pSoundMsg->fIndex);
}
return true;
}
plAudioSysMsg* pASMsg = plAudioSysMsg::ConvertNoRef( msg );
if (pASMsg)
{
if (pASMsg->GetAudFlag() == plAudioSysMsg::kActivate)
{
if( fAudible )
{
if( !fAudibleInited )
{
int isLocal = IsLocallyOwned();
fAudible->Init( ( isLocal == plSynchedObject::kYes ) );
fAudibleInited = true;
}
if( !fAudibleInited )
{
// Arrgh, can't activate yet, so attempt to re-activate some time in the near future
pASMsg = TRACKED_NEW plAudioSysMsg( plAudioSysMsg::kActivate );
pASMsg->SetBCastFlag( plMessage::kBCastByExactType, false );
pASMsg->SetBCastFlag( plMessage::kNetPropagate, false );
pASMsg->SetTimeStamp( hsTimer::GetSysSeconds() + 1.f );
pASMsg->Send( GetKey() );
return true;
}
fAudible->Activate();
if (GetOwner() && GetOwner()->GetCoordinateInterface())
{
hsMatrix44 l2w = GetOwner()->GetCoordinateInterface()->GetLocalToWorld();
hsMatrix44 w2l = GetOwner()->GetCoordinateInterface()->GetWorldToLocal();;
fAudible->SetTransform(l2w,w2l);
}
}
}
if (pASMsg->GetAudFlag() == plAudioSysMsg::kDeActivate)
{
if( fAudible )
fAudible->DeActivate();
}
if( pASMsg->GetAudFlag() == plAudioSysMsg::kMuteAll )
{
if( fAudible )
fAudible->SetMuted( true );
}
else if( pASMsg->GetAudFlag() == plAudioSysMsg::kUnmuteAll )
{
if( fAudible )
fAudible->SetMuted( false );
}
else if( pASMsg->GetAudFlag() == plAudioSysMsg::kChannelVolChanged )
{
if( fAudible )
return fAudible->MsgReceive( msg );
}
}
plEnableMsg* pEnableMsg = plEnableMsg::ConvertNoRef( msg );
if (pEnableMsg)
{
SetProperty( kDisable, pEnableMsg->Cmd(kDisable) );
return true;
}
// proxyDrawMsg handling--just pass it on to the audible
plProxyDrawMsg *pdMsg = plProxyDrawMsg::ConvertNoRef( msg );
if( pdMsg != nil )
{
if( fAudible )
return fAudible->MsgReceive( pdMsg );
return true;
}
return plObjInterface::MsgReceive(msg);
}
void plAudioInterface::ReleaseData()
{
if (fAudible)
{
// To get rid of our data, we need to release our active ref and tell the SceneNode
// to dump it. It will autodestruct after those two active refs are released, unless
// someone else has a ref on it as well (in which case we don't want to be nuking it
// anyway).
fAudible->SetSceneNode(nil);
// Audible key is gone already, I guess the audioInterface doesn't have a ref -Colin
// GetKey()->Release(fAudible->GetKey());
}
}

View File

@ -0,0 +1,94 @@
/*==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==*/
#ifndef plAudioInterface_inc
#define plAudioInterface_inc
#include "plObjInterface.h"
class plSound;
class plAudible;
class hsStream;
class hsResMgr;
struct hsMatrix44;
class hsBounds3Ext;
class plAudioInterface : public plObjInterface
{
public:
// Props inc by 1 (bit shift in bitvector).
enum plAudioProperties {
kDisable = 0, // prop 0 is always disable, declared in plObjInterface
kNumProps // last in the list
};
protected:
plAudible* fAudible; // references into system pools
hsBool fRegisteredForASysMsg, fAudibleInited;
void ISetAudible(plAudible* aud);
void IRemoveAudible(plAudible* aud);
virtual void ISetOwner(plSceneObject* owner);
virtual void ISetSceneNode(plKey node);
friend class plSceneObject;
public:
plAudioInterface();
~plAudioInterface();
CLASSNAME_REGISTER( plAudioInterface );
GETINTERFACE_ANY( plAudioInterface, plObjInterface );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetProperty(int prop, hsBool on);
Int32 GetNumProperties() const { return kNumProps; }
plSound* GetSound(int i) const;
int GetNumSounds() const;
virtual hsBool MsgReceive(plMessage* msg);
// for export only!!!!!
plAudible* GetAudible() const { return fAudible; }
/// don't call this otherwise!
// Transform settable only, if you want it get it from the coordinate interface.
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual void ReleaseData( void );
void SetSoundFilename(int index, const char *filename, bool isCompressed);
int GetSoundIndex(const char *keyname);
};
#endif // plAudioInterface_inc

View File

@ -0,0 +1,644 @@
/*==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 "plCoordinateInterface.h"
#include "plDrawInterface.h"
#include "plSimulationInterface.h"
#include "plAudioInterface.h"
#include "../pnMessage/plWarpMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnMessage/plCorrectionMsg.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnNetCommon/plSDLTypes.h"
#include "plSceneObject.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
#include "../pnKeyedObject/plKey.h"
#include "hsStream.h"
#include "plProfile.h"
UInt8 plCoordinateInterface::fTransformPhase = plCoordinateInterface::kTransformPhaseNormal;
hsBool plCoordinateInterface::fDelayedTransformsEnabled = true;
plCoordinateInterface::plCoordinateInterface()
: fParent(nil),
fReason(kReasonUnknown)
{
fLocalToParent.Reset();
fParentToLocal.Reset();
fLocalToWorld.Reset();
fWorldToLocal.Reset();
fState = 0;
}
plCoordinateInterface::~plCoordinateInterface()
{
if( fParent )
fParent->IRemoveChild(IGetOwner());
int i;
for( i = fChildren.GetCount()-1; i >= 0; i-- )
IRemoveChild(i);
}
void plCoordinateInterface::ISetSceneNode(plKey newNode)
{
int i;
for( i = 0; i < fChildren.GetCount(); i++ )
{
if( fChildren[i] )
fChildren[i]->SetSceneNode(newNode);
}
}
void plCoordinateInterface::ISetOwner(plSceneObject* so)
{
plObjInterface::ISetOwner(so);
IDirtyTransform();
fReason |= kReasonUnknown;
}
void plCoordinateInterface::ISetParent(plCoordinateInterface* par)
{
fParent = par;
// This won't have any effect if my owner is NetGroupConstant
if( fParent )
ISetNetGroupRecur(fParent->GetNetGroup());
IDirtyTransform();
fReason |= kReasonUnknown;
}
plCoordinateInterface* plCoordinateInterface::GetChild(int i) const
{
return fChildren[i] ? fChildren[i]->GetVolatileCoordinateInterface() : nil;
}
void plCoordinateInterface::IRemoveChild(int i)
{
if( fChildren[i] )
{
plCoordinateInterface* childCI = fChildren[i]->GetVolatileCoordinateInterface();
if( childCI )
childCI->ISetParent(nil);
}
fChildren.Remove(i);
}
void plCoordinateInterface::IRemoveChild(plSceneObject* child)
{
int idx = fChildren.Find(child);
if( idx != fChildren.kMissingIndex )
IRemoveChild(idx);
}
void plCoordinateInterface::ISetChild(plSceneObject* child, int which)
{
hsAssert(child, "Setting a nil child");
plCoordinateInterface* childCI = child->GetVolatileCoordinateInterface();
hsAssert(childCI, "Child with no coordinate interface");
childCI->ISetParent(this);
if( which < 0 )
which = fChildren.GetCount();
fChildren.ExpandAndZero(which+1);
fChildren[which] = child;
// If we can't delay our transform update, neither can any of our parents.
if (!childCI->GetProperty(kDelayedTransformEval))
{
plCoordinateInterface *current = childCI->GetParent();
while (current)
{
current->SetProperty(kDelayedTransformEval, false);
current = current->GetParent();
}
}
}
void plCoordinateInterface::IAddChild(plSceneObject* child)
{
ISetChild(child, -1);
}
void plCoordinateInterface::IAttachChild(plSceneObject* child, UInt8 flags)
{
hsAssert(child, "Attaching a nil child");
plCoordinateInterface* childCI = child->GetVolatileCoordinateInterface();
hsAssert(childCI, "Owner without CoordinateInterface being attached");
if (childCI->GetParent() == this)
return; // We're already attached! Who told us to do this?
hsMatrix44 l2w = childCI->GetLocalToWorld();
hsMatrix44 w2l = childCI->GetWorldToLocal();
if( childCI->GetParent() )
childCI->GetParent()->IDetachChild(child, flags | kAboutToAttach);
childCI->IUnRegisterForTransformMessage();
IAddChild(child);
if( flags & kMaintainWorldPosition )
childCI->WarpToWorld(l2w,w2l);
}
void plCoordinateInterface::IDetachChild(plSceneObject* child, UInt8 flags)
{
hsAssert(child, "Detaching a nil child");
plCoordinateInterface* childCI = child->GetVolatileCoordinateInterface();
hsAssert(childCI, "Owner without CoordinateInterface being attached");
hsMatrix44 l2w = childCI->GetLocalToWorld();
hsMatrix44 w2l = childCI->GetWorldToLocal();
GetKey()->Release(child->GetKey());
if( IGetOwner() && IGetOwner()->GetKey() )
IGetOwner()->GetKey()->Release(child->GetKey());
IRemoveChild(child);
if( flags & kMaintainWorldPosition )
childCI->WarpToWorld(l2w,w2l);
// If the child was keeping us from delaying our transform,
// maybe we can, now that it's gone.
if (!childCI->GetProperty(kDelayedTransformEval))
IUpdateDelayProp();
}
/*
* A few notes on the delay transform properties...
*
* The kCanEverDelayTransform prop is independent of any parents/children.
* It means this particular node must always update its transform in response
* to a plTransformMsg. It is intended for objects with physics, because they
* need to be up-to-date before the simulationMgr updates the physical world.
*
* The kDelayedTransformEval prop is for nodes that are free of physics. (So no
* physical descendants either). If the property is set, we won't update our
* transform until AFTER the simulationMgr does its work.
*
* When we attach a child that can't delay its eval (at the moment), we recurse
* up to the root, turning off the kDelayedTransformEval prop as we go. When we
* remove such a child, we check if that child was the only reason we weren't
* delaying our transform. If so, we update ourself and tell our parent to check.
*
* BTW: The POINT of all this is that when we update our l2w transforms because
* we're animated, and then we update AGAIN after a parent node of ours involved
* in physics gets a slight nudge, the first update becomes pointless. The
* delay prop bookkeeping keeps us from doing the wasted calculations. And since
* nearly all bones on the avatar are in this exact situation, it's worth doing.
*/
void plCoordinateInterface::IUpdateDelayProp()
{
int i;
if (!GetProperty(kCanEverDelayTransform))
return;
for (i = 0; i < GetNumChildren(); i++)
{
// If we still have a child that needs the delay...
if (!GetChild(i)->GetProperty(kDelayedTransformEval))
return;
}
// Cool, we can delay now, which means maybe our parent can too.
SetProperty(kDelayedTransformEval, true);
if (GetParent())
GetParent()->IUpdateDelayProp();
}
plCoordinateInterface* plCoordinateInterface::IGetRoot()
{
return fParent ? fParent->IGetRoot() : this;
}
void plCoordinateInterface::IRegisterForTransformMessage(hsBool delayed)
{
if( IGetOwner() )
{
if ((delayed || fTransformPhase == kTransformPhaseDelayed) && fDelayedTransformsEnabled)
plgDispatch::Dispatch()->RegisterForExactType(plDelayedTransformMsg::Index(), IGetOwner()->GetKey());
else
plgDispatch::Dispatch()->RegisterForExactType(plTransformMsg::Index(), IGetOwner()->GetKey());
}
}
void plCoordinateInterface::IUnRegisterForTransformMessage()
{
if( IGetOwner() )
plgDispatch::Dispatch()->UnRegisterForExactType(plTransformMsg::Index(), IGetOwner()->GetKey());
}
void plCoordinateInterface::IDirtyTransform()
{
fState |= kTransformDirty;
IGetRoot()->IRegisterForTransformMessage(GetProperty(kDelayedTransformEval));
}
void plCoordinateInterface::MultTransformLocal(const hsMatrix44& move, const hsMatrix44& invMove)
{
fReason |= kReasonUnknown;
fLocalToParent = move * fLocalToParent;
fParentToLocal = fParentToLocal * invMove;
IDirtyTransform();
}
void plCoordinateInterface::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
fReason |= kReasonUnknown;
if( fParent )
{
SetLocalToParent(fParent->GetWorldToLocal() * l2w, w2l * fParent->GetLocalToWorld());
}
else
{
SetLocalToParent(l2w, w2l);
}
}
void plCoordinateInterface::SetTransformPhysical(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
// since we use public interfaces to do the details
// AND those public interfaces could be called by anyone
// AND those public interfaces therefore have to set their own "reason" for the transform change
// THEREFORE: we need to preserve the "reason" flags before we call the public interfaces
// so that we don't get reasonPhysics + reasonUnknown, just reasonPhysics
UInt16 oldReason = fReason;
if( fParent )
{
SetLocalToParent(fParent->GetWorldToLocal() * l2w, w2l * fParent->GetLocalToWorld());
}
else
{
SetLocalToParent(l2w, w2l);
}
fReason = oldReason | kReasonPhysics;
}
UInt16 plCoordinateInterface::GetReasons()
{
return fReason;
}
void plCoordinateInterface::ClearReasons()
{
fReason = nil;
}
void plCoordinateInterface::SetLocalToParent(const hsMatrix44& l2p, const hsMatrix44& p2l)
{
fReason |= kReasonUnknown;
fLocalToParent = l2p;
fParentToLocal = p2l;
IDirtyTransform();
}
void plCoordinateInterface::WarpToLocal(const hsMatrix44& l2p, const hsMatrix44& p2l)
{
fReason |= kReasonUnknown;
SetLocalToParent(l2p, p2l);
// update physical state when an object is warped
if (IGetOwner())
IGetOwner()->DirtySynchState(kSDLPhysical, 0);
}
void plCoordinateInterface::WarpToWorld(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
fReason |= kReasonUnknown;
if( fParent )
{
hsMatrix44 l2p = fParent->GetWorldToLocal() * l2w;
hsMatrix44 p2l = w2l * fParent->GetLocalToWorld();
WarpToLocal(l2p, p2l);
}
else
{
WarpToLocal(l2w, w2l);
}
}
plProfile_CreateCounter("CITrans", "Object", CITrans);
plProfile_CreateCounter(" CIRecalc", "Object", CIRecalc);
plProfile_CreateCounter(" CIDirty", "Object", CIDirty);
plProfile_CreateCounter(" CISet", "Object", CISet);
plProfile_CreateTimer("CITransT", "Object", CITransT);
plProfile_CreateTimer(" CIRecalcT", "Object", CIRecalcT);
plProfile_CreateTimer(" CIDirtyT", "Object", CIDirtyT);
plProfile_CreateTimer(" CISetT", "Object", CISetT);
static inline hsMatrix44 IMatrixMul34(const hsMatrix44& lhs, const hsMatrix44& rhs)
{
hsMatrix44 ret;
ret.NotIdentity();
ret.fMap[3][0] = ret.fMap[3][1] = ret.fMap[3][2] = 0;
ret.fMap[3][3] = 1.f;
ret.fMap[0][0] = lhs.fMap[0][0] * rhs.fMap[0][0]
+ lhs.fMap[0][1] * rhs.fMap[1][0]
+ lhs.fMap[0][2] * rhs.fMap[2][0];
ret.fMap[0][1] = lhs.fMap[0][0] * rhs.fMap[0][1]
+ lhs.fMap[0][1] * rhs.fMap[1][1]
+ lhs.fMap[0][2] * rhs.fMap[2][1];
ret.fMap[0][2] = lhs.fMap[0][0] * rhs.fMap[0][2]
+ lhs.fMap[0][1] * rhs.fMap[1][2]
+ lhs.fMap[0][2] * rhs.fMap[2][2];
ret.fMap[0][3] = lhs.fMap[0][0] * rhs.fMap[0][3]
+ lhs.fMap[0][1] * rhs.fMap[1][3]
+ lhs.fMap[0][2] * rhs.fMap[2][3]
+ lhs.fMap[0][3];
ret.fMap[1][0] = lhs.fMap[1][0] * rhs.fMap[0][0]
+ lhs.fMap[1][1] * rhs.fMap[1][0]
+ lhs.fMap[1][2] * rhs.fMap[2][0];
ret.fMap[1][1] = lhs.fMap[1][0] * rhs.fMap[0][1]
+ lhs.fMap[1][1] * rhs.fMap[1][1]
+ lhs.fMap[1][2] * rhs.fMap[2][1];
ret.fMap[1][2] = lhs.fMap[1][0] * rhs.fMap[0][2]
+ lhs.fMap[1][1] * rhs.fMap[1][2]
+ lhs.fMap[1][2] * rhs.fMap[2][2];
ret.fMap[1][3] = lhs.fMap[1][0] * rhs.fMap[0][3]
+ lhs.fMap[1][1] * rhs.fMap[1][3]
+ lhs.fMap[1][2] * rhs.fMap[2][3]
+ lhs.fMap[1][3];
ret.fMap[2][0] = lhs.fMap[2][0] * rhs.fMap[0][0]
+ lhs.fMap[2][1] * rhs.fMap[1][0]
+ lhs.fMap[2][2] * rhs.fMap[2][0];
ret.fMap[2][1] = lhs.fMap[2][0] * rhs.fMap[0][1]
+ lhs.fMap[2][1] * rhs.fMap[1][1]
+ lhs.fMap[2][2] * rhs.fMap[2][1];
ret.fMap[2][2] = lhs.fMap[2][0] * rhs.fMap[0][2]
+ lhs.fMap[2][1] * rhs.fMap[1][2]
+ lhs.fMap[2][2] * rhs.fMap[2][2];
ret.fMap[2][3] = lhs.fMap[2][0] * rhs.fMap[0][3]
+ lhs.fMap[2][1] * rhs.fMap[1][3]
+ lhs.fMap[2][2] * rhs.fMap[2][3]
+ lhs.fMap[2][3];
return ret;
}
void plCoordinateInterface::IRecalcTransforms()
{
plProfile_IncCount(CIRecalc, 1);
plProfile_BeginTiming(CIRecalcT);
if( fParent )
{
#if 0
fLocalToWorld = fParent->GetLocalToWorld() * fLocalToParent;
fWorldToLocal = fParentToLocal * fParent->GetWorldToLocal();
#else
fLocalToWorld = IMatrixMul34(fParent->GetLocalToWorld(), fLocalToParent);
fWorldToLocal = IMatrixMul34(fParentToLocal, fParent->GetWorldToLocal());
#endif
}
else
{
fLocalToWorld = fLocalToParent;
fWorldToLocal = fParentToLocal;
}
plProfile_EndTiming(CIRecalcT);
}
void plCoordinateInterface::ITransformChanged(hsBool force, UInt16 reasons, hsBool checkForDelay)
{
plProfile_IncCount(CITrans, 1);
plProfile_BeginTiming(CITransT);
// inherit reasons for transform change from our parents
fReason |= reasons;
UInt16 propagateReasons = fReason;
hsBool process = !(checkForDelay && GetProperty(kDelayedTransformEval)) || !fDelayedTransformsEnabled;
if (process)
{
if( fState & kTransformDirty )
force = true;
}
if( force )
{
IRecalcTransforms();
plProfile_IncCount(CISet, 1);
plProfile_BeginTiming(CISetT);
if( IGetOwner() )
{
IGetOwner()->ISetTransform(fLocalToWorld, fWorldToLocal);
}
plProfile_EndTiming(CISetT);
fState &= ~kTransformDirty;
}
plProfile_EndTiming(CITransT);
if (process)
{
int i;
for( i = 0; i < fChildren.GetCount(); i++ )
{
if( fChildren[i] && fChildren[i]->GetVolatileCoordinateInterface() )
fChildren[i]->GetVolatileCoordinateInterface()->ITransformChanged(force, propagateReasons, checkForDelay);
}
}
else if (force)
{
plProfile_IncCount(CIDirty, 1);
plProfile_BeginTiming(CITransT);
// Our parent is dirty and we're bailing out on evaluating right now.
// Need to ensure we'll be evaluated in the delay pass
plProfile_BeginTiming(CIDirtyT);
IDirtyTransform();
plProfile_EndTiming(CIDirtyT);
plProfile_EndTiming(CITransT);
}
}
void plCoordinateInterface::FlushTransform(hsBool fromRoot)
{
if( fromRoot )
IGetRoot()->ITransformChanged(false, 0, false);
else
ITransformChanged(false, 0, false);
}
void plCoordinateInterface::ISetNetGroupRecur(plNetGroupId netGroup)
{
if( !IGetOwner() )
return;
if( IGetOwner()->GetSynchFlags() & kHasConstantNetGroup )
return;
IGetOwner()->plSynchedObject::SetNetGroup(netGroup);
int i;
for( i = 0; i < GetNumChildren(); i++ )
{
if( GetChild(i) )
{
GetChild(i)->ISetNetGroupRecur(netGroup);
}
}
}
void plCoordinateInterface::Read(hsStream* stream, hsResMgr* mgr)
{
plObjInterface::Read(stream, mgr);
fLocalToParent.Read(stream);
fParentToLocal.Read(stream);
fLocalToWorld.Read(stream);
fWorldToLocal.Read(stream);
int n = stream->ReadSwap32();
int i;
for( i = 0; i < n; i++ )
{
plIntRefMsg* refMsg = TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, -1, plIntRefMsg::kChildObject);
mgr->ReadKeyNotifyMe(stream,refMsg, plRefFlags::kPassiveRef);
}
}
void plCoordinateInterface::Write(hsStream* stream, hsResMgr* mgr)
{
plObjInterface::Write(stream, mgr);
fLocalToParent.Write(stream);
fParentToLocal.Write(stream);
fLocalToWorld.Write(stream);
fWorldToLocal.Write(stream);
stream->WriteSwap32(fChildren.GetCount());
int i;
for( i = 0; i < fChildren.GetCount(); i++ )
mgr->WriteKey(stream, fChildren[i]);
}
hsBool plCoordinateInterface::MsgReceive(plMessage* msg)
{
hsBool retVal = false;
plIntRefMsg* intRefMsg;
plCorrectionMsg* corrMsg;
// warp message
plWarpMsg* pWarpMsg = plWarpMsg::ConvertNoRef(msg);
if (pWarpMsg)
{
hsMatrix44 l2w = pWarpMsg->GetTransform();
hsMatrix44 inv;
l2w.GetInverse(&inv);
WarpToWorld(l2w,inv);
if (pWarpMsg->GetWarpFlags() & plWarpMsg::kFlushTransform)
ITransformChanged(false, kReasonUnknown, false);
return true;
}
else if( intRefMsg = plIntRefMsg::ConvertNoRef(msg) )
{
switch( intRefMsg->fType )
{
case plIntRefMsg::kChildObject:
case plIntRefMsg::kChild:
{
plSceneObject* co = nil;
if( intRefMsg->fType == plIntRefMsg::kChildObject )
{
co = plSceneObject::ConvertNoRef(intRefMsg->GetRef());
}
else
{
plCoordinateInterface* ci = plCoordinateInterface::ConvertNoRef(intRefMsg->GetRef());
co = ci ? ci->IGetOwner() : nil;
}
if( intRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnReplace) )
{
ISetChild(co, intRefMsg->fWhich);
}
else if( intRefMsg->GetContext() & plRefMsg::kOnDestroy )
{
IRemoveChild(co);
}
else if( intRefMsg->GetContext() & plRefMsg::kOnRequest )
{
IAttachChild(co, kMaintainWorldPosition|kMaintainSceneNode);
}
else if( intRefMsg->GetContext() & plRefMsg::kOnRemove )
{
IDetachChild(co, kMaintainWorldPosition|kMaintainSceneNode);
}
}
return true;
default:
break;
}
}
else if( corrMsg = plCorrectionMsg::ConvertNoRef(msg) )
{
SetTransformPhysical(corrMsg->fLocalToWorld, corrMsg->fWorldToLocal);
if(corrMsg->fDirtySynch)
{
if (IGetOwner())
IGetOwner()->DirtySynchState(kSDLPhysical, 0);
}
return true;
}
return plObjInterface::MsgReceive(msg);
}

View File

@ -0,0 +1,187 @@
/*==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==*/
#ifndef plCoordinateInterface_inc
#define plCoordinateInterface_inc
#include "plObjInterface.h"
#include "hsTemplates.h"
#include "hsMatrix44.h"
#include "../pnNetCommon/plSynchedValue.h"
class hsStream;
class hsResMgr;
class plCoordinateInterface : public plObjInterface
{
public:
enum plCoordinateProperties {
kDisable = 0, // prop 0 is always disable, declared in plObjInterface
kCanEverDelayTransform = 1, // we can sometimes delay our transform eval (i.e. we're on a physics object)
kDelayedTransformEval = 2, // we're currently registering for the DelayedTransformMsg (we, and all our
// descendants, have the kCanEverDelayTransform prop)
kNumProps // last in the list
};
enum plCoordinateTransformPhases
{
kTransformPhaseNormal,
kTransformPhaseDelayed,
};
protected:
enum {
kTransformDirty = 0x1,
kWarp = 0x2,
kMaxState = 0xffff
};
enum plAttachFlags {
kMaintainWorldPosition = 0x1,
kMaintainSceneNode = 0x2,
kAboutToAttach = 0x4
};
enum Reason {
kReasonUnknown = 0x1, // somebody moved us
kReasonPhysics = 0x2, // physics moved us
kMaxReasons = 0xffff // sixteen bits
};
// Set by the client in IUpdate(). This tells us where we are in the update loop so that we know
// which transform message to register for when our transform is dirtied.
static UInt8 fTransformPhase;
// Temp debugging tool, so we can quickly (dis/en)able delayed transforms at runtime.
static hsBool fDelayedTransformsEnabled;
UInt16 fState;
UInt16 fReason; // why we've changed position (if we have)
hsTArray<plSceneObject*> fChildren;
plCoordinateInterface* fParent; // if this changes, marks us as dirty
hsMatrix44 fLocalToParent;
hsMatrix44 fParentToLocal;
hsMatrix44 fLocalToWorld;
hsMatrix44 fWorldToLocal;
virtual void ISetOwner(plSceneObject* so);
virtual void ISetParent(plCoordinateInterface* par); // don't use, use AddChild on parent
virtual void ISetSceneNode(plKey newNode);
// objectToo moves the sceneObject to the new room, else just move the data and remove
// the object from whatever room he's in.
// Network only strange functions. Do not emulate or generalize this functionality.
void ISetNetGroupRecur(plNetGroupId netGroup);
virtual void ISetChild(plSceneObject* child, int which); // sets parent on child
virtual void IAddChild(plSceneObject* child); // sets parent on child
virtual void IRemoveChild(plSceneObject* child); // removes this as parent of child
virtual void IRemoveChild(int i); // removes this as parent of child
virtual void IAttachChild(plSceneObject* child, UInt8 flags); // physically attaches child to us
virtual void IDetachChild(plSceneObject* child, UInt8 flags); // physically detach this child from us
virtual void IUpdateDelayProp(); // Called whenever a child is added/removed
virtual void IRecalcTransforms(); // Called by ITransformChanged when we need to re-examine our relationship with our parent.
virtual void ITransformChanged(hsBool force, UInt16 reasons, hsBool checkForDelay); // called by SceneObject on TransformChanged messsage
void IDirtyTransform();
void IRegisterForTransformMessage(hsBool delayed);
void IUnRegisterForTransformMessage();
plCoordinateInterface* IGetRoot();
friend class plSceneObject;
public:
plCoordinateInterface();
~plCoordinateInterface();
CLASSNAME_REGISTER( plCoordinateInterface );
GETINTERFACE_ANY( plCoordinateInterface, plObjInterface );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual void SetLocalToParent(const hsMatrix44& l2p, const hsMatrix44& p2l);
// special version for setting transform from physics.
// separate to keep from changing interface to add "reason" parameter
virtual void SetTransformPhysical(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual void MultTransformLocal(const hsMatrix44& move, const hsMatrix44& invMove);
virtual void WarpToWorld(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual void WarpToLocal(const hsMatrix44& l2p, const hsMatrix44& p2l);
// Force an immediate re-sync of the transforms in the hierarchy this object belongs to,
// as opposed to waiting for the plTransformMsg to resync.
// There are two uses for this:
// a) You need the transforms for this object to be valid NOW, can't wait till after a TransforMsg
// In this case, you want to flush from the root, because something higher up the hierarchy
// may be dirty, which invalidates this object's transforms
// b) You've just dirtied this object's transform, and need it to propagate downward from here NOW
// In this case, fromRoot should be false, because you haven't dirtied anything higher up
// the hierarchy.
// Another way to look at it is, if the transforms for the tree were correct before you messed with
// this object, you only need to flush the transforms for this object and its recursive children,
// so fromRoot=false.
// If the entire tree is potentially dirty and you need to read from it, you want the entire tree
// synced up, so fromRoot=true.
// fromRoot=true is always safe, just potentially wasteful, so if you don't know, use fromRoot=true or
// preferably, don't use this function.
void FlushTransform(hsBool fromRoot=true);
virtual const hsMatrix44& GetLocalToParent() const { return fLocalToParent; }
virtual const hsMatrix44& GetParentToLocal() const { return fParentToLocal; }
virtual const hsMatrix44& GetLocalToWorld() const { return fLocalToWorld; }
virtual const hsMatrix44& GetWorldToLocal() const { return fWorldToLocal; }
virtual const hsPoint3 GetWorldPos() const { return fLocalToWorld.GetTranslate(); }
virtual int GetNumChildren() const { return fChildren.GetCount(); }
virtual plCoordinateInterface* GetChild(int i) const;
virtual plCoordinateInterface* GetParent() const { return fParent; }
virtual hsBool MsgReceive(plMessage* msg);
UInt16 GetReasons();
void ClearReasons();
Int32 GetNumProperties() const { return kNumProps; }
static UInt8 GetTransformPhase() { return fTransformPhase; }
static void SetTransformPhase(UInt8 phase) { fTransformPhase = phase; }
static hsBool GetDelayedTransformsEnabled() { return fDelayedTransformsEnabled; }
static void SetDelayedTransformsEnabled(hsBool val) { fDelayedTransformsEnabled = val; }
};
#endif // plCoordinateInterface_inc

View File

@ -0,0 +1,371 @@
/*==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 "plDrawInterface.h"
#include "plDrawable.h"
#include "hsBounds.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
#include "plSceneObject.h"
#include "../pnMessage/plEnableMsg.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plDISpansMsg.h"
plDrawInterface::plDrawInterface()
{
}
plDrawInterface::~plDrawInterface()
{
}
void plDrawInterface::SetDrawableMeshIndex( UInt8 which, UInt32 index )
{
ICheckDrawableIndex(which);
fDrawableIndices[which] = index;
}
void plDrawInterface::SetProperty(int prop, hsBool on)
{
plObjInterface::SetProperty(prop, on);
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
fDrawables[i]->SetProperty(fDrawableIndices[i], prop, on);
}
}
void plDrawInterface::ISetSceneNode(plKey newNode)
{
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
fDrawables[i]->SetSceneNode(newNode);
}
}
void plDrawInterface::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
if( !GetProperty(kDisable) )
{
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
fDrawables[i]->SetTransform( fDrawableIndices[i], l2w, w2l );
}
}
}
const hsBounds3Ext plDrawInterface::GetLocalBounds() const
{
hsBounds3Ext retVal;
retVal.MakeEmpty();
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
retVal.Union(&fDrawables[i]->GetLocalBounds(fDrawableIndices[i]));
}
return retVal;
}
const hsBounds3Ext plDrawInterface::GetWorldBounds() const
{
hsBounds3Ext retVal;
retVal.MakeEmpty();
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
retVal.Union(&fDrawables[i]->GetWorldBounds(fDrawableIndices[i]));
}
return retVal;
}
const hsBounds3Ext plDrawInterface::GetMaxWorldBounds() const
{
hsBounds3Ext retVal;
retVal.MakeEmpty();
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] )
retVal.Union(&fDrawables[i]->GetMaxWorldBounds(fDrawableIndices[i]));
}
return retVal;
}
void plDrawInterface::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
int nDrawables = s->ReadSwap32();
if (nDrawables > 0)
ICheckDrawableIndex(nDrawables-1);
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
fDrawableIndices[i] = s->ReadSwap32();
plIntRefMsg* refMsg = TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, i, plIntRefMsg::kDrawable);
mgr->ReadKeyNotifyMe(s,refMsg, plRefFlags::kActiveRef);
}
int nReg = s->ReadSwap32();
fRegions.SetCountAndZero(nReg);
for( i = 0; i < nReg; i++ )
{
plGenRefMsg* refMsg = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kRefVisRegion);
mgr->ReadKeyNotifyMe(s, refMsg, plRefFlags::kActiveRef);
}
}
void plDrawInterface::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
s->WriteSwap32(fDrawables.GetCount());
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
s->WriteSwap32(fDrawableIndices[i]);
mgr->WriteKey(s, fDrawables[i]);
}
s->WriteSwap32(fRegions.GetCount());
for( i = 0; i < fRegions.GetCount(); i++ )
{
mgr->WriteKey(s, fRegions[i]);
}
}
//// ReleaseData //////////////////////////////////////////////////////////////
// Called by SceneViewer to release the data for this given object (when
// its parent sceneObject is deleted).
void plDrawInterface::ReleaseData( void )
{
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] && (fDrawableIndices[i] != UInt32(-1)) )
{
plDISpansMsg* diMsg = TRACKED_NEW plDISpansMsg(fDrawables[i]->GetKey(), plDISpansMsg::kRemovingSpan, fDrawableIndices[i], 0);
diMsg->SetSender(GetKey());
diMsg->Send();
}
//fDrawableIndices[i] = UInt32(-1);
fDrawables.Reset();
fDrawableIndices.Reset();
}
}
void plDrawInterface::ICheckDrawableIndex(UInt8 which)
{
if( which >= fDrawableIndices.GetCount() )
{
fDrawables.ExpandAndZero(which+1);
int n = fDrawableIndices.GetCount();
fDrawableIndices.ExpandAndZero(which+1);
int i;
for( i = n; i <= which; i++ )
fDrawableIndices[i] = UInt32(-1);
}
}
void plDrawInterface::ISetDrawable(UInt8 which, plDrawable* dr)
{
ICheckDrawableIndex(which);
fDrawables[which] = dr;
if( dr )
dr->SetSceneNode(GetSceneNode());
// We might read the vis regions before the drawables, so
// we have to check for any already loaded.
ISetVisRegions(which);
#ifdef HS_DEBUGGING
if( fDrawableIndices[which] != (UInt32)-1 )
{
plDISpansMsg* diMsg = TRACKED_NEW plDISpansMsg(dr->GetKey(), plDISpansMsg::kAddingSpan, fDrawableIndices[which], 0);
diMsg->SetSender(GetKey());
diMsg->Send();
}
#endif
}
void plDrawInterface::IRemoveDrawable(plDrawable *dr)
{
int idx = fDrawables.Find(dr);
if( fDrawables.kMissingIndex != idx )
{
fDrawables[idx] = nil;
fDrawableIndices[idx] = UInt32(-1);
}
else
{
hsAssert(false, "Trying to remove a drawable that doesn't belong to us");
}
}
void plDrawInterface::ISetVisRegion(hsKeyedObject* reg, hsBool on)
{
int i;
for( i = 0; i < fDrawables.GetCount(); i++ )
{
if( fDrawables[i] && (fDrawableIndices[i] != UInt32(-1)) )
{
fDrawables[i]->SetDISpanVisSet(fDrawableIndices[i], reg, on);
}
}
int idx = fRegions.Find(reg);
if( on )
{
if( idx == fRegions.kMissingIndex )
fRegions.Append(reg);
}
else
{
if( idx != fRegions.kMissingIndex )
fRegions.Remove(idx);
}
}
void plDrawInterface::ISetVisRegions(int iDraw)
{
if( fDrawables[iDraw] && (fDrawableIndices[iDraw] != UInt32(-1)) )
{
int i;
for( i = 0; i < fRegions.GetCount(); i++ )
{
fDrawables[iDraw]->SetDISpanVisSet(fDrawableIndices[iDraw], fRegions[i], true);
}
}
}
// Export only. Use messages for runtime
void plDrawInterface::SetDrawable(UInt8 which, plDrawable *dr)
{
if( dr )
{
// This is a little convoluted, but it makes GCC happy and doesn't hurt anybody.
plIntRefMsg* intRefMsg = TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, which, plIntRefMsg::kDrawable);
plRefMsg* refMsg = intRefMsg;
// hsgResMgr::ResMgr()->SendRef(dr->GetKey(), intRefMsg, plRefFlags::kActiveRef); // THIS WON'T COMPILE UNDER GCC
hsgResMgr::ResMgr()->SendRef(dr, refMsg, plRefFlags::kActiveRef);
}
else
{
ISetDrawable(which, nil);
}
}
hsBool plDrawInterface::MsgReceive(plMessage* msg)
{
plIntRefMsg* intRefMsg = plIntRefMsg::ConvertNoRef(msg);
if( intRefMsg )
{
switch( intRefMsg->fType )
{
case plIntRefMsg::kDrawable:
if( intRefMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
IRemoveDrawable(plDrawable::ConvertNoRef(intRefMsg->GetRef()));
}
else
{
ISetDrawable((UInt8)intRefMsg->fWhich, plDrawable::ConvertNoRef(intRefMsg->GetRef()));
}
return true;
default:
break;
}
}
plGenRefMsg* genRefMsg = plGenRefMsg::ConvertNoRef(msg);
if( genRefMsg )
{
switch( genRefMsg->fType )
{
case kRefVisRegion:
if( genRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
ISetVisRegion(genRefMsg->GetRef(), true);
else
ISetVisRegion(genRefMsg->GetRef(), false);
break;
default:
break;
}
return true;
}
plEnableMsg* pEnableMsg = plEnableMsg::ConvertNoRef( msg );
if (pEnableMsg)
{
SetProperty(kDisable, pEnableMsg->Cmd(plEnableMsg::kDisable));
if( GetOwner() )
SetTransform(GetOwner()->GetLocalToWorld(), GetOwner()->GetWorldToLocal());
return true;
}
return plObjInterface::MsgReceive(msg);
}
void plDrawInterface::SetUpForParticleSystem( UInt32 maxNumEmitters, UInt32 maxNumParticles, hsGMaterial *material, hsTArray<plKey>& lights )
{
hsAssert( fDrawables[0] != nil, "No drawable to use for particle system!" );
SetDrawableMeshIndex( 0, fDrawables[0]->CreateParticleSystem( maxNumEmitters, maxNumParticles, material ) );
int i;
for( i = 0; i < lights.GetCount(); i++ )
{
hsgResMgr::ResMgr()->AddViaNotify(lights[i], TRACKED_NEW plGenRefMsg(fDrawables[0]->GetKey(), plRefMsg::kOnCreate, fDrawableIndices[0], plDrawable::kMsgPermaLightDI), plRefFlags::kPassiveRef);
}
ISetVisRegions(0);
}
void plDrawInterface::ResetParticleSystem( void )
{
hsAssert( fDrawables[0] != nil, "No drawable to use for particle system!" );
fDrawables[0]->ResetParticleSystem( fDrawableIndices[0] );
}
void plDrawInterface::AssignEmitterToParticleSystem( plParticleEmitter *emitter )
{
hsAssert( fDrawables[0] != nil, "No drawable to use for particle system!" );
fDrawables[0]->AssignEmitterToParticleSystem( fDrawableIndices[0], emitter );
}

View File

@ -0,0 +1,108 @@
/*==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==*/
#ifndef plDrawInterface_inc
#define plDrawInterface_inc
#include "plObjInterface.h"
class plDrawable;
class hsStream;
class hsResMgr;
struct hsMatrix44;
class hsBounds3Ext;
class hsGMaterial;
class plParticleEmitter;
class plDrawInterface : public plObjInterface
{
public:
// Props inc by 1 (bit shift in bitvector).
enum plDrawProperties {
kDisable = 0,
kNumProps // last in the list
};
enum {
kRefVisRegion
};
protected:
hsTArray<plDrawable*> fDrawables;
hsTArray<UInt32> fDrawableIndices;
hsTArray<hsKeyedObject*> fRegions;
void ISetVisRegions(int iDraw);
void ISetVisRegion(hsKeyedObject* ref, hsBool on);
void ISetDrawable(UInt8 which, plDrawable* dr);
void IRemoveDrawable(plDrawable* dr);
void ISetSceneNode(plKey newNode);
virtual void ICheckDrawableIndex(UInt8 which);
friend class plSceneObject;
public:
plDrawInterface();
virtual ~plDrawInterface();
CLASSNAME_REGISTER( plDrawInterface );
GETINTERFACE_ANY( plDrawInterface, plObjInterface );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetProperty(int prop, hsBool on);
Int32 GetNumProperties() const { return kNumProps; }
// Transform settable only, if you want it get it from the coordinate interface.
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
// Bounds are gettable only, they are computed on the drawable.
const hsBounds3Ext GetLocalBounds() const;
const hsBounds3Ext GetWorldBounds() const;
const hsBounds3Ext GetMaxWorldBounds() const;
virtual hsBool MsgReceive(plMessage* msg);
virtual void ReleaseData( void );
/// Funky particle system functions
void SetUpForParticleSystem( UInt32 maxNumEmitters, UInt32 maxNumParticles, hsGMaterial *material, hsTArray<plKey>& lights );
void ResetParticleSystem( void );
void AssignEmitterToParticleSystem( plParticleEmitter *emitter );
/// EXPORT-ONLY
void SetDrawable(UInt8 which, plDrawable* dr);
plDrawable* GetDrawable( UInt8 which ) const { return which < fDrawables.GetCount() ? fDrawables[which] : nil; }
UInt32 GetNumDrawables() const { return fDrawables.GetCount(); }
// Sets the triMesh index to be used when referring to our spans in the drawable
void SetDrawableMeshIndex( UInt8 which, UInt32 index );
UInt32 GetDrawableMeshIndex( UInt8 which ) const { return which < fDrawableIndices.GetCount() ? fDrawableIndices[which] : UInt32(-1); }
};
#endif // plDrawInterface_inc

View File

@ -0,0 +1,116 @@
/*==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 "plObjInterface.h"
#include "hsResMgr.h"
#include "../pnKeyedObject/plKey.h"
#include "plSceneObject.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plEnableMsg.h"
plObjInterface::plObjInterface()
: fOwner(nil)
{
}
plObjInterface::~plObjInterface()
{
}
void plObjInterface::ISetOwner(plSceneObject* owner)
{
if( fOwner != owner )
{
fOwner = owner;
if( fOwner )
fOwner->ISetInterface(this);
}
}
void plObjInterface::Read(hsStream* s, hsResMgr* mgr)
{
plSynchedObject::Read(s, mgr);
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kOwner), plRefFlags::kPassiveRef);
fProps.Read(s);
}
void plObjInterface::Write(hsStream* s, hsResMgr* mgr)
{
plSynchedObject::Write(s, mgr);
mgr->WriteKey(s, fOwner);
fProps.Write(s);
}
hsBool plObjInterface::MsgReceive(plMessage* msg)
{
hsBool retVal = false;
plEnableMsg* enaMsg = plEnableMsg::ConvertNoRef(msg);
if( enaMsg )
{
SetProperty(kDisable, enaMsg->Cmd(plEnableMsg::kDisable));
return true;
}
plIntRefMsg* intRefMsg = plIntRefMsg::ConvertNoRef(msg);
if( intRefMsg )
{
switch( intRefMsg->fType )
{
case plIntRefMsg::kOwner:
if( intRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
plSceneObject* owner = plSceneObject::ConvertNoRef(intRefMsg->GetRef());
ISetOwner(owner);
}
else if( intRefMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
ISetOwner(nil);
}
break;
}
}
return plSynchedObject::MsgReceive(msg);
}
//
// assign and update my properties from the bitVector passed in
//
void plObjInterface::ISetAllProperties(const hsBitVector& b)
{
// if (&b != &fProps) // don't copy if they are the same variable
fProps = b;
int i;
for(i=0;i<GetNumProperties(); i++)
SetProperty(i, GetProperty(i));
}

View File

@ -0,0 +1,103 @@
/*==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==*/
#ifndef plInterface_inc
#define plInterface_inc
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../pnMessage/plRefMsg.h"
#include "plSceneObject.h"
#include "hsStream.h"
#include "../pnNetCommon/plSynchedObject.h"
#include "../pnNetCommon/plSynchedValue.h"
#include "hsBitVector.h"
class hsResMgr;
class plDrawInterface;
class plSimulationInterface;
class plCoordinateInterface;
class plAudioInterface;
//
// Since interfaces are keyed objects with valid uoids and
// may have dynamic data (coordinate interface), they are
// synched (saved) objects
//
class plObjInterface : public plSynchedObject
{
protected:
enum {
kDisable = 0x0 // Derived interfaces duplicate this, so if you add more here, they need to know.
};
friend class plSynchedValueBase;
friend class plSceneObject;
protected:
plSceneObject* fOwner;
hsBitVector fProps;
// SetSceneNode just called by owner. If we're an interface to external data,
// we need to pass the change on. Otherwise, do nothing.
virtual void ISetSceneNode(plKey node) {}
plSceneObject* IGetOwner() const { return fOwner; }
virtual void ISetOwner(plSceneObject* owner);
void ISetAllProperties(const hsBitVector& b);
plDrawInterface* IGetOwnerDrawInterface() { return fOwner ? fOwner->GetVolatileDrawInterface() : nil; }
plSimulationInterface* IGetOwnerSimulationInterface() { return fOwner ? fOwner->GetVolatileSimulationInterface() : nil; }
plCoordinateInterface* IGetOwnerCoordinateInterface() { return fOwner ? fOwner->GetVolatileCoordinateInterface() : nil; }
plAudioInterface* IGetOwnerAudioInterface() { return fOwner ? fOwner->GetVolatileAudioInterface() : nil; }
public:
plObjInterface();
~plObjInterface();
CLASSNAME_REGISTER( plObjInterface );
GETINTERFACE_ANY( plObjInterface, plSynchedObject );
virtual hsBool MsgReceive(plMessage* msg);
const plSceneObject* GetOwner() const { return IGetOwner(); }
plKey GetOwnerKey() const { return IGetOwner() ? IGetOwner()->GetKey() : nil; }
virtual plKey GetSceneNode() const { return IGetOwner() ? IGetOwner()->GetSceneNode() : nil; }
// override SetProperty to pass the prop down to the pool objects
virtual void SetProperty(int prop, hsBool on) { fProps.SetBit(prop, on); }
// shouldn't need to override GetProperty()
hsBool GetProperty(int prop) const { return fProps.IsBitSet(prop); }
virtual Int32 GetNumProperties() const = 0;
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) = 0;
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual void ReleaseData( void ) { }
};
#endif // plInterface_inc

View File

@ -0,0 +1,870 @@
/*==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);
}

View File

@ -0,0 +1,165 @@
/*==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==*/
#ifndef plSceneObject_inc
#define plSceneObject_inc
#include "hsBitVector.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include "../pnMessage/plRefMsg.h"
#include "../pnNetCommon/plSynchedObject.h"
#include "../pnNetCommon/plSynchedValue.h"
#include "../pnModifier/plModifier.h"
#include "hsStream.h"
class plObjInterface;
class plDrawInterface;
class plSimulationInterface;
class plCoordinateInterface;
class plAudioInterface;
class plMessage;
class hsStream;
class hsResMgr;
class plMessage;
class plDispatchBase;
struct hsMatrix44;
// The following two aren't dragging the Conversion side into the runtime.
// They are just to let the converter do things we don't want done at runtime.
// Nice that we can make friends with these opaque classes.
class plMaxNode;
class plMaxNodeBase;
class plSceneObject : public plSynchedObject {
friend class plSynchedValueBase;
private:
plDrawInterface* GetVolatileDrawInterface() { return fDrawInterface; }
plSimulationInterface* GetVolatileSimulationInterface() { return fSimulationInterface; }
plCoordinateInterface* GetVolatileCoordinateInterface() { return fCoordinateInterface; }
plAudioInterface* GetVolatileAudioInterface() { return fAudioInterface; }
plObjInterface* GetVolatileGenericInterface(UInt16 classIdx) const;
plModifier* GetVolatileModifier(int i) { return fModifiers[i]; }
plKey fSceneNode;
friend class plModifier;
friend class plCoordinateInterface;
friend class plObjInterface;
friend class plMaxNode;
friend class plMaxNodeBase;
hsBool IMsgHandle(plMessage* msg);
protected:
plDrawInterface* fDrawInterface;
plSimulationInterface* fSimulationInterface;
plCoordinateInterface* fCoordinateInterface;
plAudioInterface* fAudioInterface;
hsTArray<plModifier*> fModifiers;
hsTArray<plObjInterface*> fGenerics;
void ISetDrawInterface(plDrawInterface* di);
void ISetSimulationInterface(plSimulationInterface* si);
void ISetAudioInterface(plAudioInterface* ai);
void ISetCoordinateInterface(plCoordinateInterface* ci);
void IAddGeneric(plObjInterface* gen);
void IRemoveGeneric(plObjInterface* gen);
void IRemoveAllGenerics();
void IPropagateToGenerics(plMessage* msg);
void IPropagateToGenerics(const hsBitVector& types, plMessage* msg);
void IAddModifier(plModifier* mo, int i);
void IRemoveModifier(plModifier* mo);
hsBool IPropagateToModifiers(plMessage* msg);
void ISetInterface(plObjInterface* iface);
void IRemoveInterface(plObjInterface* iface);
void IRemoveInterface(Int16 idx, plObjInterface* iface=nil);
void ISetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
public:
plSceneObject();
virtual ~plSceneObject();
CLASSNAME_REGISTER( plSceneObject );
GETINTERFACE_ANY( plSceneObject, plSynchedObject );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
virtual const plDrawInterface* GetDrawInterface() const { return fDrawInterface; }
virtual const plSimulationInterface* GetSimulationInterface() const { return fSimulationInterface; }
virtual const plCoordinateInterface* GetCoordinateInterface() const { return fCoordinateInterface; }
virtual const plAudioInterface* GetAudioInterface() const { return fAudioInterface; }
int GetNumGenerics() const { return fGenerics.GetCount(); }
const plObjInterface* GetGeneric(int i) const { return fGenerics[i]; }
plObjInterface* GetGenericInterface(UInt16 classIdx) const { return GetVolatileGenericInterface(classIdx); }
int GetNumModifiers() const { return fModifiers.GetCount(); }
const plModifier* GetModifier(int i) const { return fModifiers[i]; }
const plModifier* GetModifierByType(UInt16 classIdx) const;
virtual hsBool MsgReceive(plMessage* msg);
virtual hsBool Eval(double secs, hsScalar del);
void SetSceneNode(plKey newNode);
plKey GetSceneNode() const;
// Network only strange function. Do not emulate or generalize this functionality.
virtual void SetNetGroup(plNetGroupId netGroup);
virtual void ReleaseData( void );
// Force an immediate re-sync of the transforms in the hierarchy this object belongs to,
// as opposed to waiting for the plTransformMsg to resync.
void FlushTransform();
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
hsMatrix44 GetLocalToWorld() const;
hsMatrix44 GetWorldToLocal() const;
hsMatrix44 GetLocalToParent() const;
hsMatrix44 GetParentToLocal() const;
hsBool IsFinal(); // "is ready to process Loads"
// Export only
virtual void SetDrawInterface(plDrawInterface* di);
virtual void SetSimulationInterface(plSimulationInterface* si);
virtual void SetAudioInterface(plAudioInterface* ai);
virtual void SetCoordinateInterface(plCoordinateInterface* ci);
virtual void AddModifier(plModifier* mo);
virtual void RemoveModifier(plModifier* mo);
};
#endif // plSceneObject_inc

View File

@ -0,0 +1,193 @@
/*==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 "plSimulationInterface.h"
#include "plgDispatch.h"
#include "plPhysical.h"
#include "hsBounds.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "plSceneObject.h"
#include "../pnMessage/plEnableMsg.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plWarpMsg.h"
#include "../pnMessage/plSimulationSynchMsg.h"
#include "../pnMessage/plSimulationMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../pnKeyedObject/plKey.h"
plSimulationInterface::plSimulationInterface() : fPhysical(nil)
{
}
plSimulationInterface::~plSimulationInterface()
{
}
void plSimulationInterface::ISetSceneNode(plKey newNode)
{
if (fPhysical)
fPhysical->SetSceneNode(newNode);
}
void plSimulationInterface::SetProperty(int prop, hsBool on)
{
plObjInterface::SetProperty(prop, on); // set the property locally
if (fPhysical)
fPhysical->SetProperty(prop, on ? true : false);
}
void plSimulationInterface::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
if (fPhysical)
fPhysical->SetTransform(l2w, w2l);
}
void plSimulationInterface::ClearLinearVelocity()
{
if (fPhysical)
fPhysical->ClearLinearVelocity();
}
void plSimulationInterface::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
// fProps is already read by plObjInterface, but we'll do it again here to
// avoid breaking the format
fProps.Read(s);
// Also unnecessary
int poop = s->ReadSwap32();
plIntRefMsg* refMsg = TRACKED_NEW plIntRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kPhysical, 0);
mgr->ReadKeyNotifyMe(s, refMsg, plRefFlags::kActiveRef);
}
void plSimulationInterface::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
// Legacy crap
fProps.Write(s);
s->WriteSwap32(0);
mgr->WriteKey(s, fPhysical);
}
void plSimulationInterface::ReleaseData()
{
plPhysical *physical = fPhysical;
if (physical)
{
// To get rid of our data, we need to release our active ref and tell the SceneNode
// to dump it. It will autodestruct after those two active refs are released, unless
// someone else has a ref on it as well (in which case we don't want to be nuking it
// anyway).
if (physical->GetSceneNode())
{
plKey nodeKey = physical->GetSceneNode();
nodeKey->Release(physical->GetKey());
}
GetKey()->Release(physical->GetKey());
}
}
hsBool plSimulationInterface::MsgReceive(plMessage* msg)
{
plIntRefMsg* intRefMsg = plIntRefMsg::ConvertNoRef(msg);
if (intRefMsg)
{
switch (intRefMsg->fType)
{
case plIntRefMsg::kPhysical:
if (intRefMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove))
{
plPhysical* phys = plPhysical::ConvertNoRef(intRefMsg->GetRef());
// *** for some reason, we sometimes get a null pointer here
// *** if we do, we're just going to ignore it for now
if (phys)
{
hsAssert(phys == fPhysical, "Removing Physical I don't have");
fPhysical = nil;
}
}
else
{
fPhysical = plPhysical::ConvertNoRef(intRefMsg->GetRef());
}
return true;
}
}
plEnableMsg* pEnableMsg = plEnableMsg::ConvertNoRef(msg);
if (pEnableMsg)
{
SetProperty(kDisable, pEnableMsg->Cmd(kDisable));
SetProperty(kPinned, pEnableMsg->Cmd(kDisable));
return true;
}
plWarpMsg* pWarpMsg = plWarpMsg::ConvertNoRef(msg);
if (pWarpMsg)
{
if (fPhysical)
{
hsMatrix44 l2w = pWarpMsg->GetTransform();
hsMatrix44 inv;
l2w.GetInverse(&inv);
SetTransform(l2w, inv);
if (pWarpMsg->GetWarpFlags() & plWarpMsg::kZeroVelocity)
{
ClearLinearVelocity();
}
}
}
plSimulationMsg* pSimMsg = plSimulationMsg::ConvertNoRef(msg);
if (pSimMsg)
{
if (fPhysical)
fPhysical->MsgReceive(pSimMsg);
}
return plObjInterface::MsgReceive(msg);
}
// Export only. Use messages for runtime.
void plSimulationInterface::SetPhysical(plPhysical* ph)
{
fPhysical = ph;
}
plPhysical* plSimulationInterface::GetPhysical() const
{
return fPhysical;
}

View File

@ -0,0 +1,97 @@
/*==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==*/
#ifndef plSimulationInterface_inc
#define plSimulationInterface_inc
#include "plObjInterface.h"
class plPhysical;
struct hsMatrix44;
class hsBounds3Ext;
class plSimulationInterface : public plObjInterface
{
public:
// Props inc by 1 (bit shift in bitvector).
enum plSimulationProperties {
// prop 0 is always disable, , declared in plObjInterface
kDisable = 0, // no more interaction. no interference detection
kWeightless_DEAD, // unaffected by gravity, but not massless
kPinned, // stop moving. keep colliding.
kWarp_DEAD, // keep moving, no colliding (a pattern is emerging here...)
kUpright_DEAD, // stand upright (mainly for the player)
kPassive, // don't push new positions to sceneobject
kRotationForces_DEAD, // rotate using forces
kCameraAvoidObject_DEAD, // camera will try and fly around this obsticle
kPhysAnim, // this object is animated, and the animation can apply force
kStartInactive, // deactive this object at start time. will reactivate when hit
kNoSynchronize, // don't synchronize this physical
kSuppressed_DEAD, // physical still exists but is not in simulation: no forces, contact, or reports
kNoOwnershipChange, // Don't automatically change net ownership on this physical when it is collided with
kAvAnimPushable, // Something the avatar should react to and push against
kNumProps
};
protected:
plPhysical* fPhysical;
friend class plSceneObject;
virtual void ISetSceneNode(plKey newNode);
public:
plSimulationInterface();
~plSimulationInterface();
CLASSNAME_REGISTER( plSimulationInterface );
GETINTERFACE_ANY( plSimulationInterface, plObjInterface );
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetProperty(int prop, hsBool on);
Int32 GetNumProperties() const { return kNumProps; }
// Transform settable only, if you want it get it from the coordinate interface.
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
// Bounds are gettable only, they are computed on the physical.
const hsBounds3Ext GetLocalBounds();
const hsBounds3Ext GetWorldBounds() const;
const hsBounds3Ext GetMaxWorldBounds();
void ClearLinearVelocity();
virtual hsBool MsgReceive(plMessage* msg);
// Export only.
void SetPhysical(plPhysical* phys);
void ReleaseData();
plPhysical* GetPhysical() const;
};
#endif // plSimulationInterface_inc

View File

@ -0,0 +1,57 @@
/*==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==*/
#ifndef plSceneObjectCreatable_inc
#define plSceneObjectCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plObjInterface.h"
REGISTER_NONCREATABLE( plObjInterface );
#include "plAudioInterface.h"
REGISTER_CREATABLE( plAudioInterface );
#include "plCoordinateInterface.h"
REGISTER_CREATABLE( plCoordinateInterface );
#include "plDrawInterface.h"
REGISTER_CREATABLE( plDrawInterface );
#include "plSimulationInterface.h"
REGISTER_CREATABLE( plSimulationInterface );
#include "plSceneObject.h"
REGISTER_CREATABLE( plSceneObject );
#endif // plSceneObjectCreatable_inc