You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
9.1 KiB
359 lines
9.1 KiB
14 years ago
|
/*==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 "plLayerInterface.h"
|
||
|
#include "../plMessage/plLayRefMsg.h"
|
||
|
#include "plLayer.h"
|
||
|
#include "hsMatrix44.h"
|
||
|
#include "hsGMatState.h"
|
||
|
#include "hsResMgr.h"
|
||
|
#include "../pnNetCommon/plSDLTypes.h"
|
||
|
|
||
|
plLayerInterface::plLayerInterface()
|
||
|
: fUnderLay(nil),
|
||
|
fOverLay(nil),
|
||
|
fState(nil),
|
||
|
fTransform(nil),
|
||
|
fPreshadeColor(nil),
|
||
|
fRuntimeColor(nil),
|
||
|
fAmbientColor(nil),
|
||
|
fOpacity(nil),
|
||
|
fTexture(nil),
|
||
|
fUVWSrc(nil),
|
||
|
fLODBias(nil),
|
||
|
fSpecularColor(nil),
|
||
|
fSpecularPower(nil),
|
||
|
fOwnedChannels(0),
|
||
|
fPassThruChannels(0),
|
||
|
fVertexShader(nil),
|
||
|
fPixelShader(nil),
|
||
|
fBumpEnvXfm(nil)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
plLayerInterface::~plLayerInterface()
|
||
|
{
|
||
|
if( fUnderLay )
|
||
|
Detach(fUnderLay);
|
||
|
|
||
|
delete fState;
|
||
|
delete fPreshadeColor;
|
||
|
delete fRuntimeColor;
|
||
|
delete fAmbientColor;
|
||
|
delete fSpecularColor;
|
||
|
delete fOpacity;
|
||
|
delete fTransform;
|
||
|
|
||
|
delete fTexture;
|
||
|
|
||
|
delete fUVWSrc;
|
||
|
delete fLODBias;
|
||
|
delete fSpecularPower;
|
||
|
|
||
|
delete fVertexShader;
|
||
|
delete fPixelShader;
|
||
|
|
||
|
delete fBumpEnvXfm;
|
||
|
}
|
||
|
|
||
|
void plLayerInterface::ISetPassThru(UInt32 chans)
|
||
|
{
|
||
|
fPassThruChannels |= chans;
|
||
|
if( fOverLay )
|
||
|
fOverLay->ISetPassThru(chans);
|
||
|
|
||
|
// Since plLayerAnimation is the only derived class that uses its
|
||
|
// fPassThruChannels info, it's the only one that actually saves
|
||
|
// it to state.
|
||
|
DirtySynchState(kSDLLayer, 0);
|
||
|
}
|
||
|
|
||
|
// The arbitration rules for different layers on the same stack
|
||
|
// wanting to control the same channel are currently:
|
||
|
// 1) Only one write-only value setter can be active at a time,
|
||
|
// otherwise results are undefined.
|
||
|
// 2) A layer will only become active due to receiving a message.
|
||
|
// 3) A channel value for the stack is the value as set by the
|
||
|
// last layer that was active. If no layers have ever been
|
||
|
// active, the value is the static value of the bottom of the stack.
|
||
|
// 4) Since the stack is only Eval'd when visible, the third rule
|
||
|
// must appear to be true when different layers become active
|
||
|
// and inactive without ever having been Eval'd.
|
||
|
// 5) Taking advantage of rules 1) and 2), it follows that the last
|
||
|
// layer to have become active on response to a message is also
|
||
|
// the last layer to have been active.
|
||
|
// 6) So when a layer becomes active in it's MsgReceive(), it notifies
|
||
|
// all channels above it that it now owns its channels, and they
|
||
|
// should just pass through those channel values.
|
||
|
// Note that a layer may claim ownership of its channels but then lose
|
||
|
// ownership (because another layer went active) before ever having
|
||
|
// been Eval'd.
|
||
|
void plLayerInterface::ClaimChannels(UInt32 chans)
|
||
|
{
|
||
|
if( fOverLay )
|
||
|
fOverLay->ISetPassThru(chans);
|
||
|
fPassThruChannels &= ~chans;
|
||
|
DirtySynchState(kSDLLayer, 0);
|
||
|
}
|
||
|
|
||
|
UInt32 plLayerInterface::Eval(double secs, UInt32 frame, UInt32 ignore)
|
||
|
{
|
||
|
if( fUnderLay )
|
||
|
return fUnderLay->Eval(secs, frame, ignore);
|
||
|
|
||
|
return UInt32(0);
|
||
|
}
|
||
|
|
||
|
// Export Only
|
||
|
void plLayerInterface::AttachViaNotify(plLayerInterface *prev)
|
||
|
{
|
||
|
plLayRefMsg* refMsg = TRACKED_NEW plLayRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kUnderLay);
|
||
|
hsgResMgr::ResMgr()->AddViaNotify(prev->GetKey(), refMsg, plRefFlags::kActiveRef);
|
||
|
}
|
||
|
|
||
|
plLayerInterface* plLayerInterface::Attach(plLayerInterface* prev)
|
||
|
{
|
||
|
if( !prev )
|
||
|
return this;
|
||
|
|
||
|
if( fUnderLay == prev )
|
||
|
return this;
|
||
|
|
||
|
if( fUnderLay )
|
||
|
{
|
||
|
fUnderLay->Attach(prev);
|
||
|
prev = fUnderLay;
|
||
|
}
|
||
|
|
||
|
if( !OwnChannel(kState) )
|
||
|
fState = prev->fState;
|
||
|
|
||
|
if( !OwnChannel(kPreshadeColor) )
|
||
|
fPreshadeColor = prev->fPreshadeColor;
|
||
|
|
||
|
if( !OwnChannel( kRuntimeColor ) )
|
||
|
fRuntimeColor = prev->fRuntimeColor;
|
||
|
|
||
|
if( !OwnChannel(kAmbientColor) )
|
||
|
fAmbientColor = prev->fAmbientColor;
|
||
|
|
||
|
if( !OwnChannel( kSpecularColor ) )
|
||
|
fSpecularColor = prev->fSpecularColor;
|
||
|
|
||
|
if( !OwnChannel(kOpacity) )
|
||
|
fOpacity = prev->fOpacity;
|
||
|
|
||
|
if( !OwnChannel(kTransform) )
|
||
|
fTransform = prev->fTransform;
|
||
|
|
||
|
if( !OwnChannel(kTexture) )
|
||
|
fTexture = prev->fTexture;
|
||
|
|
||
|
if( !OwnChannel(kUVWSrc) )
|
||
|
fUVWSrc = prev->fUVWSrc;
|
||
|
|
||
|
if( !OwnChannel(kLODBias) )
|
||
|
fLODBias = prev->fLODBias;
|
||
|
|
||
|
if( !OwnChannel(kSpecularPower) )
|
||
|
fSpecularPower = prev->fSpecularPower;
|
||
|
|
||
|
if( !OwnChannel(kVertexShader) )
|
||
|
fVertexShader = prev->fVertexShader;
|
||
|
|
||
|
if( !OwnChannel(kPixelShader) )
|
||
|
fPixelShader = prev->fPixelShader;
|
||
|
|
||
|
if( !OwnChannel(kBumpEnvXfm) )
|
||
|
fBumpEnvXfm = prev->fBumpEnvXfm;
|
||
|
|
||
|
fUnderLay = prev;
|
||
|
prev->fOverLay = this;
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
void plLayerInterface::IUnthread()
|
||
|
{
|
||
|
if( fUnderLay )
|
||
|
{
|
||
|
if( !OwnChannel(kState) )
|
||
|
fState = nil;
|
||
|
if( !OwnChannel(kPreshadeColor) )
|
||
|
fPreshadeColor = nil;
|
||
|
if( !OwnChannel( kRuntimeColor ) )
|
||
|
fRuntimeColor = nil;
|
||
|
if( !OwnChannel(kAmbientColor) )
|
||
|
fAmbientColor = nil;
|
||
|
if( !OwnChannel( kSpecularColor ) )
|
||
|
fSpecularColor = nil;
|
||
|
if( !OwnChannel(kOpacity) )
|
||
|
fOpacity = nil;
|
||
|
if( !OwnChannel(kTransform) )
|
||
|
fTransform = nil;
|
||
|
if( !OwnChannel(kTexture) )
|
||
|
fTexture = nil;
|
||
|
|
||
|
if( !OwnChannel(kUVWSrc) )
|
||
|
fUVWSrc = nil;
|
||
|
if( !OwnChannel(kLODBias) )
|
||
|
fLODBias = nil;
|
||
|
if( !OwnChannel(kSpecularPower) )
|
||
|
fSpecularPower = nil;
|
||
|
|
||
|
if( !OwnChannel(kVertexShader) )
|
||
|
fVertexShader = nil;
|
||
|
if( !OwnChannel(kPixelShader) )
|
||
|
fPixelShader = nil;
|
||
|
|
||
|
if( !OwnChannel(kBumpEnvXfm) )
|
||
|
fBumpEnvXfm = nil;
|
||
|
|
||
|
fUnderLay->fOverLay = nil;
|
||
|
fUnderLay = nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Detach:
|
||
|
// If we are the one being detached, break our links to underlay
|
||
|
// and then return nil, since everything has just been detached
|
||
|
// from the stack.
|
||
|
// If our underlay is the one being detached, we need to unthread from it
|
||
|
// and return ourselves.
|
||
|
// If it's not us, and not our underlay, just pass it to our underlay and let
|
||
|
// it deal.
|
||
|
//
|
||
|
// Return value is new TOP of stack. li is now top of a separate stack.
|
||
|
plLayerInterface* plLayerInterface::Detach(plLayerInterface* li)
|
||
|
{
|
||
|
if( li == this )
|
||
|
return nil;
|
||
|
|
||
|
if( li == fUnderLay )
|
||
|
{
|
||
|
IUnthread();
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
fUnderLay->Detach(li);
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
// Remove:
|
||
|
// If we are the one being removed, break our links to underlay
|
||
|
// and then just return underlay, since it doesn't even know
|
||
|
// about our existence (so it doesn't need to know about the remove).
|
||
|
// If our underlay is the one being removed, we need to unthread it from
|
||
|
// its underlay (if any), and then thread ourselves onto the underlay's
|
||
|
// former underlay.
|
||
|
// If it's not us, and not our underlay, just pass it to our underlay and let
|
||
|
// it deal.
|
||
|
//
|
||
|
// Return value is new TOP of stack.
|
||
|
plLayerInterface* plLayerInterface::Remove(plLayerInterface* li)
|
||
|
{
|
||
|
plLayerInterface* under = fUnderLay;
|
||
|
|
||
|
if( li == this )
|
||
|
{
|
||
|
|
||
|
IUnthread();
|
||
|
|
||
|
return under;
|
||
|
}
|
||
|
|
||
|
// This is an error, because it means we're being asked
|
||
|
// to detach from something we aren't attached to.
|
||
|
if( !under )
|
||
|
{
|
||
|
hsAssert(false, "Detaching from unknown layerinterface");
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
IUnthread();
|
||
|
|
||
|
plLayerInterface* newUnderLay = under->Remove(li);
|
||
|
|
||
|
Attach(newUnderLay);
|
||
|
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
plLayerInterface *plLayerInterface::GetAttached()
|
||
|
{
|
||
|
return fUnderLay;
|
||
|
}
|
||
|
|
||
|
void plLayerInterface::Read(hsStream* s, hsResMgr* mgr)
|
||
|
{
|
||
|
plSynchedObject::Read(s, mgr);
|
||
|
|
||
|
plLayRefMsg* refMsg = TRACKED_NEW plLayRefMsg(GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kUnderLay);
|
||
|
plKey key = mgr->ReadKeyNotifyMe(s,refMsg, plRefFlags::kActiveRef);
|
||
|
if( key && !fUnderLay )
|
||
|
Attach(plLayer::DefaultLayer());
|
||
|
|
||
|
// Temporary setting default netgroup by our key.
|
||
|
SetNetGroup(SelectNetGroup(GetKey()));
|
||
|
}
|
||
|
|
||
|
void plLayerInterface::Write(hsStream* s, hsResMgr* mgr)
|
||
|
{
|
||
|
plSynchedObject::Write(s, mgr);
|
||
|
|
||
|
mgr->WriteKey(s, fUnderLay);
|
||
|
}
|
||
|
|
||
|
hsBool plLayerInterface::MsgReceive(plMessage* msg)
|
||
|
{
|
||
|
plLayRefMsg* refMsg = plLayRefMsg::ConvertNoRef(msg);
|
||
|
if( refMsg )
|
||
|
{
|
||
|
switch( refMsg->fType )
|
||
|
{
|
||
|
case plLayRefMsg::kUnderLay:
|
||
|
{
|
||
|
plLayerInterface* underLay = plLayerInterface::ConvertNoRef(refMsg->GetRef());
|
||
|
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
|
||
|
{
|
||
|
if( fUnderLay )
|
||
|
Detach(fUnderLay);
|
||
|
|
||
|
Attach(underLay);
|
||
|
}
|
||
|
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
|
||
|
{
|
||
|
Detach(fUnderLay);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return plSynchedObject::MsgReceive(msg);
|
||
|
}
|