Files
Webcam/include/engine/motion/quaternion_channel.cpp

180 lines
4.3 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "motion/quaternion_channel.h"
using namespace GS;
//------------------------------------------------------------------------------
static float range(float v, float lo, float hi, int *i)
{
float r = hi - lo;
if (!r)
{
if (i)
*i = 0;
return lo;
}
float v2 = v - lo;
if (v2 >= 0)
v2 = lo + v2 - r * Math::Floor(v2 / r);
else v2 = hi + v2 - r * Math::Ceil(v2 / r);
if (i)
*i = - (int)((v2 - v) / r + (v2 > v ? 0.5f : -0.5f));
return Types::Clamp(v2, lo, hi);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void QuaternionChannel::Evaluate(Time t, Quaternion &p, Curve::LoopMode loop, Time loop_start, Time loop_end) const
{
if (keys.GetCount() == 0)
return;
QuaternionKey *skey = keys[0], *ekey = keys[keys.GetCount() - 1];
loop_start = (loop_start == Time::Inf) ? skey->t : Types::Clamp(loop_start, skey->t, ekey->t);
loop_end = (loop_end == Time::Inf) ? ekey->t : Types::Clamp(loop_end, skey->t, ekey->t);
int noff = 0;
if (t < loop_start)
{
switch (loop)
{
default:
case Curve::Constant:
Evaluate(loop_start, p, loop, loop_start, loop_end);
return;
case Curve::Reset:
p.Set(0, 0, 0, 1);
return;
case Curve::Repeat:
case Curve::OffsetAndRepeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL));
break;
case Curve::Oscillate:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
if (noff % 2)
t = loop_end + loop_start - t;
break;
}
}
else if (t > loop_end)
{
switch (loop)
{
default:
case Curve::Constant:
Evaluate(loop_end, p, loop, loop_start, loop_end);
return;
case Curve::Reset:
p.Set(0, 0, 0, 1);
return;
case Curve::Repeat:
case Curve::OffsetAndRepeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL));
break;
case Curve::Oscillate:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
if (noff % 2)
t = loop_end + loop_start - t;
break;
}
}
// Evaluate (t is guaranteed to be in range).
int ikey0;
#if 1
{
uint lo = 0, hi = keys.GetCount() - 1;
forever
{
uint mid = (lo + hi) / 2;
if (keys[mid]->t > t)
hi = mid;
else
{
if (lo == mid)
{
ikey0 = lo;
break;
}
else
lo = mid;
}
}
}
#else
for (ikey0 = 1; ikey0 < int(keys.GetCount()); ikey0++)
if (keys[ikey0]->t > t)
break;
--ikey0;
#endif
// Slerp.
if (ikey0 == (int(keys.GetCount()) - 1))
p = keys[ikey0]->q;
else
{
const float k = (t - keys[ikey0]->t).toSec() / (keys[ikey0 + 1]->t - keys[ikey0]->t).toSec();
p = Quaternion::Slerp(k, keys[ikey0]->q, keys[ikey0 + 1]->q).Normalize();
}
}
uint QuaternionChannel::Optimize(float threshold)
{
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
TimeRange QuaternionChannel::GetTimeRange() const
{
Time min, max;
if (keys.GetCount() > 0)
{
min = max = keys[0]->t;
for (uint n = 1; n < keys.GetCount(); ++n)
{
min = Types::Min(min, keys[n]->t);
max = Types::Max(max, keys[n]->t);
}
}
return TimeRange(min, max);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool QuaternionChannel::Insert(const QuaternionKey &key)
{
uint n = 0;
for (; n < keys.GetCount(); ++n)
if (keys[n]->t > key.t)
break;
return keys.Insert(new QuaternionKey(key), n);
}
void QuaternionChannel::Clear()
{
ArrayListDeleteAllPtr(QuaternionKey *, keys)
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
QuaternionChannel::QuaternionChannel()
{}
QuaternionChannel::~QuaternionChannel()
{ Clear(); }
//------------------------------------------------------------------------------