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.

486 lines
12 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 "plPointChannel.h"
#include "plScalarChannel.h"
#include "hsResMgr.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plSimulationInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnSceneObject/plAudioInterface.h"
#include "../plInterp/plController.h"
#include "../plInterp/plAnimTimeConvert.h"
#include "../plGLight/plLightInfo.h"
//////////////
// PLPOINTSRCE
//////////////
// CTOR
plPointChannel::plPointChannel()
: plAGChannel(), fResult(0, 0, 0)
{
}
// DTOR
plPointChannel::~plPointChannel()
{
}
// VALUE
// default behaviour is just to return our result (constant value)
const hsPoint3 & plPointChannel::Value(double time)
{
return fResult;
}
// VALUE(point, time)
void plPointChannel::Value(hsPoint3 &point, double time)
{
point = Value(time);
}
// MAKECOMBINE
plAGChannel * plPointChannel::MakeCombine(plAGChannel *channelA)
{
return nil;
}
// MAKEBLEND
plAGChannel * plPointChannel::MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority)
{
return TRACKED_NEW plPointBlend(this, (plPointChannel *)channelB, channelBias);
}
// MAKEZEROSTATE
plAGChannel * plPointChannel::MakeZeroState()
{
return TRACKED_NEW plPointConstant(Value(0));
}
// MAKETIMESCALE
plAGChannel * plPointChannel::MakeTimeScale(plScalarChannel *timeSource)
{
return TRACKED_NEW plPointTimeScale(this, timeSource);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plPointConstant
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------------
// -----
plPointConstant::plPointConstant()
: plPointChannel()
{
}
// ctor -----------------------------------------------
// -----
plPointConstant::plPointConstant(const hsPoint3 &point)
{
fResult = point;
}
// dtor ---------------------------
// -----
plPointConstant::~plPointConstant()
{
}
void plPointConstant::Read(hsStream *stream, hsResMgr *mgr)
{
plPointChannel::Read(stream, mgr);
fResult.Read(stream);
}
void plPointConstant::Write(hsStream *stream, hsResMgr *mgr)
{
plPointChannel::Write(stream, mgr);
fResult.Write(stream);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// PLPOINTTIMESCALE
//
// 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 ----------------------------
// -----
plPointTimeScale::plPointTimeScale()
: fTimeSource(nil), fChannelIn(nil)
{
}
// ctor --------------------------------------------------------------------------------
// -----
plPointTimeScale::plPointTimeScale(plPointChannel *channel, plScalarChannel *timeSource)
: fChannelIn(channel),
fTimeSource(timeSource)
{
}
// dtor -----------------------------
// -----
plPointTimeScale::~plPointTimeScale()
{
}
// IsStoppedAt ---------------------------
// ------------
hsBool plPointTimeScale::IsStoppedAt(double time)
{
return fTimeSource->IsStoppedAt(time);
}
// Value --------------------------------------------
// ------
const hsPoint3 & plPointTimeScale::Value(double time)
{
fResult = fChannelIn->Value(fTimeSource->Value(time));
return fResult;
}
// Detach ---------------------------------------------------
// -------
plAGChannel * plPointTimeScale::Detach(plAGChannel * channel)
{
plAGChannel *result = this;
fChannelIn = plPointChannel::ConvertNoRef(fChannelIn->Detach(channel));
if(!fChannelIn || channel == this)
result = nil;
if(result != this)
delete this;
return result;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plPointBlend
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------------
// -----
plPointBlend::plPointBlend()
: fPointA(nil),
fPointB(nil)
{
}
// ctor ---------------------------------------------------------------------------------
// -----
plPointBlend::plPointBlend(plPointChannel *channelA, plPointChannel *channelB,
plScalarChannel *channelBias)
: fPointA(channelA),
fPointB(channelB),
fChannelBias(channelBias)
{
}
// dtor ---------------------
// -----
plPointBlend::~plPointBlend()
{
fPointA = nil;
fPointB = nil;
fChannelBias = nil;
}
// IsStoppedAt ------------------------------
// ------------
hsBool plPointBlend::IsStoppedAt(double time)
{
hsScalar blend = fChannelBias->Value(time);
if (blend == 0)
return fPointA->IsStoppedAt(time);
if (blend == 1)
return fPointB->IsStoppedAt(time);
return (fPointA->IsStoppedAt(time) && fPointB->IsStoppedAt(time));
}
// Value ---------------------------------------
// ------
const hsPoint3 &plPointBlend::Value(double time)
{
if (fPointA && fPointB)
{
hsScalar curBlend = fChannelBias->Value(time);
if(curBlend == 0) {
fPointA->Value(fResult, time);
} else {
if(curBlend == 1) {
fPointB->Value(fResult, time);
} else {
const hsPoint3 &pointA = fPointA->Value(time);
const hsPoint3 &pointB = fPointB->Value(time);
hsPoint3 difference = pointB - pointA;
difference *= curBlend;
fResult = pointA + difference;
}
}
} else {
if (fPointA)
{
fResult = fPointA->Value(time);
} else {
if (fPointB)
{
fResult = fPointA->Value(time);
}
}
}
return fResult;
}
// Detach ------------------------------------------------------
// -------
plAGChannel * plPointBlend::Detach(plAGChannel *remove)
{
plAGChannel *result = this;
if (remove == this)
{
result = nil;
} else {
// 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));
fPointA = plPointChannel::ConvertNoRef(fPointA->Detach(remove));
fPointB = plPointChannel::ConvertNoRef(fPointB->Detach(remove));
if (!fChannelBias)
{
// No more bias channel, assume it's zero from now on, (a.k.a. We just want channelA)
result = fPointA;
}
else
{
if(!fChannelBias)
result = fPointA;
else if(fPointA && !fPointB)
result = fPointA;
else if(fPointB && !fPointA)
result = fPointB;
else if(!fPointA && !fPointB)
result = nil;
if(result != this)
{
delete this;
}
}
}
return result;
}
///////////////////////////
// PLPOINTCONTROLLERCHANNEL
///////////////////////////
// CTOR
plPointControllerChannel::plPointControllerChannel()
: fController(nil)
{
}
// CTOR(name, controller)
plPointControllerChannel::plPointControllerChannel(plController *controller)
: fController(controller)
{
}
// ~DTOR()
plPointControllerChannel::~plPointControllerChannel()
{
if(fController) {
delete fController;
fController = nil;
}
}
// VALUE(time)
const hsPoint3 & plPointControllerChannel::Value(double time)
{
return Value(time, nil);
}
// VALUE(time)
const hsPoint3 & plPointControllerChannel::Value(double time, plControllerCacheInfo *cache)
{
fController->Interp((hsScalar)time, &fResult, cache);
return fResult;
}
plAGChannel *plPointControllerChannel::MakeCacheChannel(plAnimTimeConvert *atc)
{
plControllerCacheInfo *cache = fController->CreateCache();
cache->SetATC(atc);
return TRACKED_NEW plPointControllerCacheChannel(this, cache);
}
// WRITE(stream, mgr)
void plPointControllerChannel::Write(hsStream *stream, hsResMgr *mgr)
{
plPointChannel::Write(stream, mgr);
hsAssert(fController, "Trying to write plPointControllerChannel with nil controller. File will not be importable.");
mgr->WriteCreatable(stream, fController);
}
// READ(stream, mgr)
void plPointControllerChannel::Read(hsStream *stream, hsResMgr *mgr)
{
plPointChannel::Read(stream, mgr);
fController = plController::ConvertNoRef(mgr->ReadCreatable(stream));
}
/////////////////////////////////
// PLPOINTCONTROLLERCACHECHANNEL
/////////////////////////////////
// CTOR
plPointControllerCacheChannel::plPointControllerCacheChannel()
: fControllerChannel(nil),
fCache(nil)
{
}
// CTOR(name, controller)
plPointControllerCacheChannel::plPointControllerCacheChannel(plPointControllerChannel *controller, plControllerCacheInfo *cache)
: fControllerChannel(controller),
fCache(cache)
{
}
// ~DTOR()
plPointControllerCacheChannel::~plPointControllerCacheChannel()
{
delete fCache;
fControllerChannel = nil;
}
// VALUE(time)
const hsPoint3 & plPointControllerCacheChannel::Value(double time, bool peek)
{
return fControllerChannel->Value(time, fCache);
}
// DETACH
plAGChannel * plPointControllerCacheChannel::Detach(plAGChannel * channel)
{
if(channel == this)
{
return nil;
} else {
plAGChannel *result = fControllerChannel->Detach(channel);
if(result == fControllerChannel)
{
return this;
} else {
// if our controller channel has been detached, then detach ourselves as well.
return result;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Channel applicators
void plPointChannelApplicator::IApply(const plAGModifier *modifier, double time)
{
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
hsAssert(pointChan, "Invalid channel given to plPointChannelApplicator");
plCoordinateInterface *CI = IGetCI(modifier);
hsMatrix44 l2p = CI->GetLocalToParent();
const hsPoint3 &point = pointChan->Value(time);
l2p.SetTranslate(&point);
hsMatrix44 p2l;
l2p.GetInverse(&p2l);
CI->SetLocalToParent(l2p, p2l);
}
void plLightDiffuseApplicator::IApply(const plAGModifier *modifier, double time)
{
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
hsAssert(pointChan, "Invalid channel given to plLightDiffuseApplicator");
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
const hsPoint3 &point = pointChan->Value(time);
hsColorRGBA color;
color.Set(point.fX, point.fY, point.fZ, 1.0f);
li->SetDiffuse(color);
}
void plLightAmbientApplicator::IApply(const plAGModifier *modifier, double time)
{
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
hsAssert(pointChan, "Invalid channel given to plLightAmbientApplicator");
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
const hsPoint3 &point = pointChan->Value(time);
hsColorRGBA color;
color.Set(point.fX, point.fY, point.fZ, 1.0f);
li->SetAmbient(color);
}
void plLightSpecularApplicator::IApply(const plAGModifier *modifier, double time)
{
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
hsAssert(pointChan, "Invalid channel given to plLightSpecularApplicator");
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
const hsPoint3 &point = pointChan->Value(time);
hsColorRGBA color;
color.Set(point.fX, point.fY, point.fZ, 1.0f);
li->SetSpecular(color);
}