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.

315 lines
7.0 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 "plQuatChannel.h"
#include "plPointChannel.h"
#include "plMatrixChannel.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plSimulationInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnSceneObject/plAudioInterface.h"
#include "../plInterp/plAnimTimeConvert.h"
#include "hsMatrix44.h"
////////////////
// PLQUATCHANNEL
////////////////
// CTOR
plQuatChannel::plQuatChannel()
: plAGChannel()
{
fResult.Identity();
}
// DTOR
plQuatChannel::~plQuatChannel()
{
}
// VALUE (time)
const hsQuat &plQuatChannel::Value(double time)
{
return fResult;
}
// VALUE (quaternion, time)
void plQuatChannel::Value(hsQuat &quat, double time)
{
quat = Value(time);
}
// CANCOMBINE
hsBool plQuatChannel::CanCombine(plAGChannel *channelA)
{
return false;
if(plPointChannel::ConvertNoRef(channelA))
{
return true;
} else {
return false;
}
}
// MAKECOMBINE
plAGChannel * plQuatChannel::MakeCombine(plAGChannel *channelA)
{
if(plPointChannel::ConvertNoRef(channelA))
{
return TRACKED_NEW plQuatPointCombine(this, (plPointChannel *)channelA);
} else {
return nil;
}
}
// MAKEBLEND
plAGChannel *plQuatChannel::MakeBlend(plAGChannel *channelB, plScalarChannel *channelBias, int blendPriority)
{
plQuatChannel *chanB = plQuatChannel::ConvertNoRef(channelB);
plScalarChannel *chanBias = plScalarChannel::ConvertNoRef(channelBias);
if(chanB && chanBias)
{
return TRACKED_NEW plQuatBlend(this, chanB, chanBias);
} else {
hsStatusMessageF("Blend operation failed.");
return this;
}
}
// MAKEZEROSTATE
plAGChannel * plQuatChannel::MakeZeroState()
{
return TRACKED_NEW plQuatConstant(Value(0));
}
// MAKETIMESCALE
plAGChannel * plQuatChannel::MakeTimeScale(plScalarChannel *timeSource)
{
return TRACKED_NEW plQuatTimeScale(this, timeSource);
}
/////////////////
// PLQUATCONSTANT
/////////////////
// CTOR
plQuatConstant::plQuatConstant()
: plQuatChannel()
{
}
// CTOR(name, quaternion)
plQuatConstant::plQuatConstant(const hsQuat &quaternion)
{
fResult = quaternion;
}
// DTOR
plQuatConstant::~plQuatConstant()
{
}
void plQuatConstant::Read(hsStream *stream, hsResMgr *mgr)
{
plQuatChannel::Read(stream, mgr);
fResult.Read(stream);
}
void plQuatConstant::Write(hsStream *stream, hsResMgr *mgr)
{
plQuatChannel::Write(stream, mgr);
fResult.Write(stream);
}
////////////////////
// PLQUATTIMESCALE
////////////////////
// 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
plQuatTimeScale::plQuatTimeScale()
: fTimeSource(nil),
fChannelIn(nil)
{
}
// CTOR (channel, converter)
plQuatTimeScale::plQuatTimeScale(plQuatChannel *channel, plScalarChannel *timeSource)
: fChannelIn(channel),
fTimeSource(timeSource)
{
}
// DTOR
plQuatTimeScale::~plQuatTimeScale()
{
}
hsBool plQuatTimeScale::IsStoppedAt(double time)
{
return fTimeSource->IsStoppedAt(time);
}
// VALUE
const hsQuat & plQuatTimeScale::Value(double time)
{
fResult = fChannelIn->Value(fTimeSource->Value(time));
return fResult;
}
// DETACH
plAGChannel * plQuatTimeScale::Detach(plAGChannel * channel)
{
plAGChannel *result = this;
fChannelIn = plQuatChannel::ConvertNoRef(fChannelIn->Detach(channel));
if(!fChannelIn || channel == this)
result = nil;
if (result != this)
delete this;
return result;
}
//////////////
// PLQUATBLEND
//////////////
// CTOR
plQuatBlend::plQuatBlend()
: fQuatA(nil),
fQuatB(nil),
fChannelBias(nil)
{
}
// CTOR(channelA, channelB, blend)
plQuatBlend::plQuatBlend(plQuatChannel *channelA, plQuatChannel *channelB, plScalarChannel *channelBias)
: fQuatA(channelA),
fQuatB(channelB),
fChannelBias(channelBias)
{
}
// DTOR
plQuatBlend::~plQuatBlend()
{
//if (fQuatA) delete fQuatA;
//if (fQuatB) delete fQuatB;
fQuatA = fQuatB = nil;
fChannelBias = nil;
}
hsBool plQuatBlend::IsStoppedAt(double time)
{
hsScalar blend = fChannelBias->Value(time);
if (blend == 0)
return fQuatA->IsStoppedAt(time);
if (blend == 1)
return fQuatB->IsStoppedAt(time);
return (fQuatA->IsStoppedAt(time) && fQuatB->IsStoppedAt(time));
}
// VALUE(time)
const hsQuat &plQuatBlend::Value(double time)
{
hsQuat quatA = fQuatA->Value(time);
hsQuat quatB = fQuatB->Value(time);
fResult.SetFromSlerp(quatA, quatB, fChannelBias->Value(time));
return fResult;
}
// REMOVE
// Remove the given channel wherever it may be in the graph (including this node)
plAGChannel * plQuatBlend::Detach(plAGChannel *remove)
{
plAGChannel *result = this;
hsAssert(remove != this, "Cannot remove blenders explicitly. Remove blended source instead.");
if (remove != this)
{
fChannelBias = plScalarChannel::ConvertNoRef(fChannelBias->Detach(remove));
if (!fChannelBias)
{
// No more bias channel, assume it's zero from now on, (a.k.a. We just want channelA)
result = fQuatA;
}
else
{
fQuatA = (plQuatChannel *)fQuatA->Detach(remove);
if(fQuatA)
{
// channel a still here(although children may be gone); try channel b
fQuatB = (plQuatChannel *)fQuatB->Detach(remove);
if(!fQuatB)
{
result = fQuatA; // channel b is gone: return channel a as blender's replacement
}
} else {
result = fQuatB; // channel a is gone: return channel b
}
if (result != this)
{
delete this; // lost one of our channels: kill the blender.
}
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////////////////
// Applicators
void plQuatChannelApplicator::IApply(const plAGModifier *mod, double time)
{
plQuatChannel *quatChan = plQuatChannel::ConvertNoRef(fChannel);
hsAssert(quatChan, "Invalid channel in plQuatChannelApplicator");
const hsQuat &rotate = quatChan->Value(time);
plCoordinateInterface *CI = IGetCI(mod);
hsMatrix44 l2w;
hsMatrix44 w2l;
rotate.MakeMatrix(&l2w);
l2w.GetInverse(&w2l);
CI->SetLocalToParent(l2w, w2l);
}