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.
314 lines
7.0 KiB
314 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); |
|
}
|
|
|