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

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