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.

590 lines
16 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==*/
/////////////////////////////////////////////////////////////////////////////////////////
//
// INCLUDES
//
/////////////////////////////////////////////////////////////////////////////////////////
// singular
#include "plScalarChannel.h"
// global
#include "hsResMgr.h"
// other
#include "plGLight/plLightInfo.h"
#include "plInterp/plController.h"
#include "plInterp/plAnimTimeConvert.h"
#include "plSDL/plSDL.h"
/////////////////////////////////////////////////////////////////////////////////////////
//
// plScalarChannel
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------------
// -----
plScalarChannel::plScalarChannel()
: plAGChannel()
{
}
// dtor ---------------------------
// -----
plScalarChannel::~plScalarChannel()
{
}
// value --------------------------------------------------------
// ------
const hsScalar & plScalarChannel::Value(double time, hsBool peek)
{
return fResult;
}
// value --------------------------------------------------------------
// ------
void plScalarChannel::Value(hsScalar &scalar, double time, hsBool peek)
{
scalar = Value(time, peek);
}
// MakeCombine -----------------------------------------------
// ------------
plAGChannel * plScalarChannel::MakeCombine(plAGChannel *other)
{
return nil;
}
// MakeBlend ---------------------------------------------------
// ----------
plAGChannel * plScalarChannel::MakeBlend(plAGChannel * channelB,
plScalarChannel * channelBias,
int blendPriority)
{
plScalarChannel * chanB = plScalarChannel::ConvertNoRef(channelB);
plScalarChannel * chanBias = plScalarChannel::ConvertNoRef(channelBias);
plAGChannel * result = this;
if (chanB)
{
result = TRACKED_NEW plScalarBlend(this, chanB, chanBias);
} else {
hsStatusMessage("Blend operation failed.");
}
return result;
}
// MakeZeroState -----------------------------
// --------------
plAGChannel * plScalarChannel::MakeZeroState()
{
return TRACKED_NEW plScalarConstant(Value(0));
}
// MakeTimeScale --------------------------------------------------------
// --------------
plAGChannel * plScalarChannel::MakeTimeScale(plScalarChannel *timeSource)
{
return TRACKED_NEW plScalarTimeScale(this, timeSource);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plScalarConstant
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor ----------------------------
// -----
plScalarConstant::plScalarConstant()
{
}
// ctor ------------------------------------------
// -----
plScalarConstant::plScalarConstant(hsScalar value)
{
fResult = value;
}
// dtor -----------------------------
// -----
plScalarConstant::~plScalarConstant()
{
}
void plScalarConstant::Read(hsStream *stream, hsResMgr *mgr)
{
plScalarChannel::Read(stream, mgr);
fResult = stream->ReadSwapScalar();
}
void plScalarConstant::Write(hsStream *stream, hsResMgr *mgr)
{
plScalarChannel::Write(stream, mgr);
stream->WriteSwapScalar(fResult);
}
////////////////////
// PLSCALARTIMESCALE
////////////////////
// Insert into the graph when you need to change the speed or direction of time
// Also serves as a handy instancing node, since it just passes its data through.
// CTOR
plScalarTimeScale::plScalarTimeScale()
: fTimeSource(nil),
fChannelIn(nil)
{
}
// CTOR (channel, converter)
plScalarTimeScale::plScalarTimeScale(plScalarChannel *channel, plScalarChannel *timeSource)
: fChannelIn(channel),
fTimeSource(timeSource)
{
}
// DTOR
plScalarTimeScale::~plScalarTimeScale()
{
}
hsBool plScalarTimeScale::IsStoppedAt(double time)
{
return fTimeSource->IsStoppedAt(time);
}
// VALUE
const hsScalar & plScalarTimeScale::Value(double time, hsBool peek)
{
fResult = fChannelIn->Value(fTimeSource->Value(time, peek));
return fResult;
}
// DETACH
plAGChannel * plScalarTimeScale::Detach(plAGChannel * detach)
{
plAGChannel *result = this;
fChannelIn = plScalarChannel::ConvertNoRef(fChannelIn->Detach(detach));
if(!fChannelIn || detach == this)
result = nil;
if(result != this)
delete this;
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plScalarBlend
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor ----------------------
// -----
plScalarBlend::plScalarBlend()
: fChannelA(nil),
fChannelB(nil),
fChannelBias(nil)
{
}
// ctor ----------------------------------------------------------------------------
// -----
plScalarBlend::plScalarBlend(plScalarChannel * channelA, plScalarChannel * channelB,
plScalarChannel * channelBias)
: fChannelA(channelA),
fChannelB(channelB),
fChannelBias(channelBias)
{
}
// dtor -----------------------
// -----
plScalarBlend::~plScalarBlend()
{
fChannelA = nil;
fChannelB = nil;
fChannelBias = nil;
}
// IsStoppedAt -------------------------------
// ------------
hsBool plScalarBlend::IsStoppedAt(double time)
{
hsScalar blend = fChannelBias->Value(time);
if (blend == 0)
return fChannelA->IsStoppedAt(time);
if (blend == 1)
return fChannelB->IsStoppedAt(time);
return (fChannelA->IsStoppedAt(time) && fChannelB->IsStoppedAt(time));
}
// Value ------------------------------------------------------
// ------
const hsScalar & plScalarBlend::Value(double time, hsBool peek)
{
hsScalar curBlend = fChannelBias->Value(time, peek);
if(curBlend == 0) {
fChannelA->Value(fResult, time, peek);
} else {
if(curBlend == 1) {
fChannelB->Value(fResult, time, peek);
} else {
const hsScalar &scalarA = fChannelA->Value(time, peek);
const hsScalar &scalarB = fChannelB->Value(time, peek);
fResult = scalarA + curBlend * (scalarB - scalarA);
}
}
return fResult;
}
// Detach ----------------------------------------------
// -------
plAGChannel * plScalarBlend::Detach(plAGChannel *remove)
{
plAGChannel *result = this;
// it's possible that the incoming channel could reside down *all* of our
// branches (it's a graph, not a tree,) so we always pass down all limbs
fChannelBias = plScalarChannel::ConvertNoRef(fChannelBias->Detach(remove));
fChannelA = plScalarChannel::ConvertNoRef(fChannelA->Detach(remove));
fChannelB = plScalarChannel::ConvertNoRef(fChannelB->Detach(remove));
if(!fChannelBias)
result = fChannelA;
else if(fChannelA && !fChannelB)
result = fChannelA;
else if(fChannelB && !fChannelA)
result = fChannelB;
else if(!fChannelA && !fChannelB)
result = nil;
if(result != this)
delete this;
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// PLSCALARCONTROLLERCHANNEL
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor ----------------------------------------------
// -----
plScalarControllerChannel::plScalarControllerChannel()
: fController(nil)
{
}
// ctor ----------------------------------------------------------------------------
// -----
plScalarControllerChannel::plScalarControllerChannel(plController *controller)
: fController(controller)
{
}
// dtor -----------------------------------------------
// -----
plScalarControllerChannel::~plScalarControllerChannel()
{
if(fController) {
delete fController;
fController = nil;
}
}
// Value ------------------------------------------------------------------
// ------
const hsScalar & plScalarControllerChannel::Value(double time, hsBool peek)
{
return Value(time, peek, nil);
}
// Value ------------------------------------------------------------------
// ------
const hsScalar & plScalarControllerChannel::Value(double time, hsBool peek,
plControllerCacheInfo *cache)
{
fController->Interp((hsScalar)time, &fResult, cache);
return fResult;
}
// MakeCacheChannel ------------------------------------------------------------
// -----------------
plAGChannel *plScalarControllerChannel::MakeCacheChannel(plAnimTimeConvert *atc)
{
plControllerCacheInfo *cache = fController->CreateCache();
cache->SetATC(atc);
return TRACKED_NEW plScalarControllerCacheChannel(this, cache);
}
// Write -------------------------------------------------------------
// ------
void plScalarControllerChannel::Write(hsStream *stream, hsResMgr *mgr)
{
plScalarChannel::Write(stream, mgr);
hsAssert(fController, "Trying to write plScalarControllerChannel with nil controller. File will not be importable.");
mgr->WriteCreatable(stream, fController);
}
// Read -------------------------------------------------------------
// -----
void plScalarControllerChannel::Read(hsStream *stream, hsResMgr *mgr)
{
plScalarChannel::Read(stream, mgr);
fController = plController::ConvertNoRef(mgr->ReadCreatable(stream));
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// PLSCALARCONTROLLERCACHECHANNEL
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------------------------------------------
// -----
plScalarControllerCacheChannel::plScalarControllerCacheChannel()
: fControllerChannel(nil),
fCache(nil)
{
}
// ctor ---------------------------------------------------------------------------------------------
// -----
plScalarControllerCacheChannel::plScalarControllerCacheChannel(plScalarControllerChannel *controller,
plControllerCacheInfo *cache)
: fControllerChannel(controller),
fCache(cache)
{
}
// dtor ---------------------------------------------------------
// -----
plScalarControllerCacheChannel::~plScalarControllerCacheChannel()
{
delete fCache;
fControllerChannel = nil;
}
// Value ---------------------------------------------------------------------
// ------
const hsScalar & plScalarControllerCacheChannel::Value(double time, bool peek)
{
return fControllerChannel->Value(time, peek, fCache);
}
// Detach -----------------------------------------------------------------
// -------
plAGChannel * plScalarControllerCacheChannel::Detach(plAGChannel * channel)
{
plAGChannel *result = this;
if(channel == this)
{
result = nil;
} else {
fControllerChannel = plScalarControllerChannel::ConvertNoRef(fControllerChannel->Detach(channel));
if(!fControllerChannel)
result = nil;
}
if(result != this)
delete this;
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// PLATCCHANNEL
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------
plATCChannel::plATCChannel()
: fConvert(nil)
{
}
// ctor ----------------------------------------------
plATCChannel::plATCChannel(plAnimTimeConvert *convert)
: fConvert(convert)
{
}
// dtor ---------------------
plATCChannel::~plATCChannel()
{
}
// IsStoppedAt ------------------------------
// ------------
hsBool plATCChannel::IsStoppedAt(double time)
{
return fConvert->IsStoppedAt(time);
}
// Value -----------------------------------------------------
// ------
const hsScalar & plATCChannel::Value(double time, hsBool peek)
{
fResult = (peek ? fConvert->WorldToAnimTimeNoUpdate(time) : fConvert->WorldToAnimTime(time));
return fResult;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// PLSCALARSDLCHANNEL
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------------------
// -----
plScalarSDLChannel::plScalarSDLChannel()
: fLength(1), fVar(nil)
{
fResult = 0;
}
plScalarSDLChannel::plScalarSDLChannel(hsScalar length)
: fLength(length), fVar(nil)
{
fResult = 0;
}
// dtor ---------------------------------
plScalarSDLChannel::~plScalarSDLChannel()
{
}
// IsStoppedAt ------------------------------------
// ------------
hsBool plScalarSDLChannel::IsStoppedAt(double time)
{
return false;
}
// Value -----------------------------------------------------------
// ------
const hsScalar & plScalarSDLChannel::Value(double time, hsBool peek)
{
if (fVar)
fVar->Get(&fResult);
// the var will return a 0-1 value, scale to match our anim length.
fResult *= fLength;
return fResult;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// APPLICATORS
//
/////////////////////////////////////////////////////////////////////////////////////////
// IApply ------------------------------------------------------------------
// -------
void plScalarChannelApplicator::IApply(const plAGModifier *mod, double time)
{
}
// IApply --------------------------------------------------------------
// -------
void plSpotInnerApplicator::IApply(const plAGModifier *mod, double time)
{
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
hsAssert(scalarChan, "Invalid channel given to plSpotInnerApplicator");
plSpotLightInfo *sli = plSpotLightInfo::ConvertNoRef(IGetGI(mod, plSpotLightInfo::Index()));
const hsScalar &scalar = scalarChan->Value(time);
sli->SetSpotInner(hsScalarDegToRad(scalar)*0.5f);
}
// IApply --------------------------------------------------------------
// -------
void plSpotOuterApplicator::IApply(const plAGModifier *mod, double time)
{
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
hsAssert(scalarChan, "Invalid channel given to plSpotInnerApplicator");
plSpotLightInfo *sli = plSpotLightInfo::ConvertNoRef(IGetGI(mod, plSpotLightInfo::Index()));
const hsScalar &scalar = scalarChan->Value(time);
sli->SetSpotOuter(hsScalarDegToRad(scalar)*0.5f);
}
void plOmniApplicator::IApply(const plAGModifier *modifier, double time)
{
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
hsAssert(scalarChan, "Invalid channel given to plLightOmniApplicator");
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
oli->SetLinearAttenuation(scalarChan->Value(time));
}
void plOmniSqApplicator::IApply(const plAGModifier *modifier, double time)
{
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
hsAssert(scalarChan, "Invalid channel given to plLightOmniApplicator");
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
oli->SetQuadraticAttenuation(scalarChan->Value(time));
}
void plOmniCutoffApplicator::IApply(const plAGModifier *modifier, double time)
{
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
hsAssert(scalarChan, "Invalid channel given to plOmniCutoffApplicator");
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
oli->SetCutoffAttenuation( scalarChan->Value( time ) );
}