|
|
|
/*==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/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|