commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
457
include/engine/motion/motion.cpp
Normal file
457
include/engine/motion/motion.cpp
Normal file
@ -0,0 +1,457 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "motion/motion.h"
|
||||
#include "core/path_kdtree.h"
|
||||
#include "math/vector.h"
|
||||
#include "geometry/geometric_tools.h"
|
||||
#include "time/ntime_range.h"
|
||||
#include "memory/memory.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Motion::Clone(const Motion &src, const TimeRange &range, bool enforce_loop)
|
||||
{
|
||||
// Clone all channels.
|
||||
channel_list.Clear();
|
||||
ListForeachPtr(MotionChannel *, sc, src.GetChannelList())
|
||||
{
|
||||
MotionChannel *c = new MotionChannel;
|
||||
if (c == NULL)
|
||||
continue;
|
||||
|
||||
c->type = sc->type;
|
||||
|
||||
// Transfer points.
|
||||
const ArrayList <CurvePoint *> &points = sc->GetPoints();
|
||||
for (uint n = 0; n < points.GetCount(); ++n)
|
||||
{
|
||||
CurvePoint *p = points[n];
|
||||
if ((p->t < range.start) || (p->t > range.end))
|
||||
continue;
|
||||
|
||||
CurvePoint np(*p);
|
||||
np.t -= range.start;
|
||||
c->Append(np);
|
||||
}
|
||||
channel_list.Add(c);
|
||||
|
||||
// Post-processing.
|
||||
const ArrayList <CurvePoint *> &c_points = c->GetPoints();
|
||||
uint count = c_points.GetCount();
|
||||
|
||||
if (count == 0)
|
||||
continue;
|
||||
|
||||
if (enforce_loop)
|
||||
{
|
||||
c_points[0]->t.setSec(0); // snap key start
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
c_points[count - 1]->t = range.valueRange();
|
||||
c_points[count - 1]->v = c_points[0]->v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone quaternion channel.
|
||||
quaternion.Clear();
|
||||
|
||||
if ((use_quaternion = src.GetUseQuaternion()) != false)
|
||||
{
|
||||
const ArrayList <QuaternionKey *> &keys = src.GetQuaternion().GetKeys();
|
||||
|
||||
for (uint n = 0; n < keys.GetCount(); ++n)
|
||||
{
|
||||
QuaternionKey *k = keys[n];
|
||||
if ((k->t < range.start) || (k->t > range.end))
|
||||
continue;
|
||||
|
||||
QuaternionKey nk(*k);
|
||||
nk.t -= range.start;
|
||||
quaternion.Insert(nk);
|
||||
}
|
||||
|
||||
// Post-processing.
|
||||
const ArrayList <QuaternionKey *> &c_keys = quaternion.GetKeys();
|
||||
uint count = c_keys.GetCount();
|
||||
|
||||
if (enforce_loop)
|
||||
{
|
||||
c_keys[0]->t.setSec(0); // snap key start
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
c_keys[count - 1]->t = range.valueRange();
|
||||
c_keys[count - 1]->q = c_keys[0]->q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Motion::HasKey(const TimeRange &t) const
|
||||
{
|
||||
ListForeachPtr(MotionChannel *, c, GetChannelList())
|
||||
for (uint n = 0; n < c->GetPointCount(); ++n)
|
||||
{
|
||||
const CurvePoint *p = c->GetPoints()[n];
|
||||
if (t.inRange(p->t))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void Motion::MoveKey(const TimeRange &t, const Time &offset) const
|
||||
{
|
||||
ListForeachPtr(MotionChannel *, c, GetChannelList())
|
||||
{
|
||||
for (uint n = 0; n < c->GetPointCount(); ++n)
|
||||
{
|
||||
CurvePoint *p = c->GetPoints()[n];
|
||||
if (t.inRange(p->t))
|
||||
p->t += offset;
|
||||
}
|
||||
c->Sort();
|
||||
}
|
||||
}
|
||||
void Motion::DeleteKey(const TimeRange &t)
|
||||
{
|
||||
ListForeachPtr(MotionChannel *, c, GetChannelList())
|
||||
{
|
||||
for (uint n = 0; n < c->GetPointCount(); ++n)
|
||||
{
|
||||
CurvePoint *p = c->GetPoints()[n];
|
||||
if (t.inRange(p->t))
|
||||
{
|
||||
c->Delete(p);
|
||||
--n;
|
||||
}
|
||||
}
|
||||
c->Sort();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Motion::GetClosestPoint(const Vector4 &position, Vector4 &closest, float *closest_t)
|
||||
{
|
||||
float best_d = -1.f;
|
||||
if (closest_t)
|
||||
*closest_t = -1;
|
||||
|
||||
MotionChannel *c[3];
|
||||
GetTransformationChannels(c, NULL, NULL);
|
||||
|
||||
// kdtree path
|
||||
if (c[0] && c[1] && c[2])
|
||||
{
|
||||
if(0 && quadtree.IsNull()) // create it, because we need it
|
||||
{
|
||||
quadtree = new PathKdtree;
|
||||
|
||||
ArrayList<CurvePoint *> &array_x = c[0]->GetPoints();
|
||||
ArrayList<CurvePoint *> &array_y = c[1]->GetPoints();
|
||||
ArrayList<CurvePoint *> &array_z = c[2]->GetPoints();
|
||||
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_x(array_x);
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_y(array_y);
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_z(array_z);
|
||||
|
||||
CurvePoint * x = iterator_x.ObjectPtr();
|
||||
CurvePoint * y = iterator_y.ObjectPtr();
|
||||
CurvePoint * z = iterator_z.ObjectPtr();
|
||||
|
||||
Vector4 a_node(x->v,y->v, z->v);
|
||||
float a_node_t = x->t.toSec();
|
||||
|
||||
// get the second node
|
||||
++iterator_x;
|
||||
++iterator_y;
|
||||
++iterator_z;
|
||||
|
||||
x = iterator_x.ObjectPtr();
|
||||
y = iterator_y.ObjectPtr();
|
||||
z = iterator_z.ObjectPtr();
|
||||
|
||||
while(x && y && z)
|
||||
{
|
||||
Vector4 b_node(x->v,y->v, z->v);
|
||||
float b_node_t = x->t.toSec();
|
||||
|
||||
nMSegment * segment = new nMSegment();
|
||||
segment->a = a_node;
|
||||
segment->b = b_node;
|
||||
segment->a_t = a_node_t;
|
||||
segment->b_t = b_node_t;
|
||||
|
||||
quadtree->AddSegment(segment);
|
||||
|
||||
a_node = b_node;
|
||||
a_node_t = b_node_t;
|
||||
|
||||
++iterator_x;
|
||||
++iterator_y;
|
||||
++iterator_z;
|
||||
|
||||
x = iterator_x.ObjectPtr();
|
||||
y = iterator_y.ObjectPtr();
|
||||
z = iterator_z.ObjectPtr();
|
||||
}
|
||||
|
||||
quadtree->BuildQuadtree();
|
||||
}
|
||||
|
||||
// check first if the point is inside the kdtree, else brute force
|
||||
if(0 && quadtree->InsideKdTree(position))
|
||||
{
|
||||
SharedArrayList <nMSegment*> list_segment;
|
||||
quadtree->NearestQuadtreeTreeNode(position, list_segment);
|
||||
|
||||
for (uint i = 0; i < list_segment.GetCount(); ++i)
|
||||
{
|
||||
Vector4 p;
|
||||
float t = GS::Geometric::SegmentClosestPoint(list_segment[i]->a, list_segment[i]->b, position, &p);
|
||||
|
||||
t = t < 0.0f? 0.0f: (t>1.0f? 1.0f:t);
|
||||
|
||||
float d = Vector4::Dist2(position, p);
|
||||
if ((best_d < 0.f) || (d < best_d))
|
||||
{
|
||||
best_d = d;
|
||||
closest = p;
|
||||
if (closest_t)
|
||||
*closest_t = t * (list_segment[i]->b_t - list_segment[i]->a_t) + list_segment[i]->a_t;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
//brute force
|
||||
{
|
||||
ArrayList<CurvePoint *> &array_x = c[0]->GetPoints();
|
||||
ArrayList<CurvePoint *> &array_y = c[1]->GetPoints();
|
||||
ArrayList<CurvePoint *> &array_z = c[2]->GetPoints();
|
||||
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_x(array_x);
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_y(array_y);
|
||||
ArrayList <CurvePoint *> ::Iterator iterator_z(array_z);
|
||||
|
||||
CurvePoint * x = iterator_x.ObjectPtr();
|
||||
CurvePoint * y = iterator_y.ObjectPtr();
|
||||
CurvePoint * z = iterator_z.ObjectPtr();
|
||||
|
||||
if (x && y && z) // [EJ] empty channels would crash on the next line
|
||||
{
|
||||
Vector4 a_node(x->v,y->v, z->v);
|
||||
float a_node_t = x->t.toSec();
|
||||
|
||||
// get the second node
|
||||
++iterator_x;
|
||||
++iterator_y;
|
||||
++iterator_z;
|
||||
|
||||
x = iterator_x.ObjectPtr();
|
||||
y = iterator_y.ObjectPtr();
|
||||
z = iterator_z.ObjectPtr();
|
||||
|
||||
while(x && y && z)
|
||||
{
|
||||
Vector4 b_node(x->v,y->v, z->v);
|
||||
float b_node_t = x->t.toSec();
|
||||
|
||||
Vector4 p;
|
||||
float t = Geometric::SegmentClosestPoint(a_node, b_node, position, &p);
|
||||
|
||||
t = t < 0.0f? 0.0f: (t>1.0f? 1.0f:t);
|
||||
|
||||
float d = Vector4::Dist2(position, p);
|
||||
if ((best_d < 0.f) || (d < best_d))
|
||||
{
|
||||
best_d = d;
|
||||
closest = p;
|
||||
if (closest_t)
|
||||
*closest_t = t * (b_node_t - a_node_t) + a_node_t;
|
||||
}
|
||||
|
||||
a_node = b_node;
|
||||
a_node_t = b_node_t;
|
||||
|
||||
++iterator_x;
|
||||
++iterator_y;
|
||||
++iterator_z;
|
||||
|
||||
x = iterator_x.ObjectPtr();
|
||||
y = iterator_y.ObjectPtr();
|
||||
z = iterator_z.ObjectPtr();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return best_d != -1.f;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Motion::EvaluateData(const Time &t, Variant &sample)
|
||||
{
|
||||
ArrayListForeachPtr(SDataPoint *, data, data_point)
|
||||
{
|
||||
if (data->t <= t)
|
||||
sample = data->data;
|
||||
else
|
||||
return; // the t in data is more than the t asked so return because the t in data is ordered
|
||||
}
|
||||
}
|
||||
void Motion::EvaluatePosition(const Time &t, Vector4 &sample, Curve::LoopMode _loop_mode)
|
||||
{
|
||||
MotionChannel *c[3];
|
||||
GetTransformationChannels(c, NULL, NULL);
|
||||
for (int n = 0; n < 3; ++n)
|
||||
if (c[n])
|
||||
c[n]->Evaluate(t, &sample[n], _loop_mode);
|
||||
}
|
||||
void Motion::EvaluateRotation(const Time &t, Vector4 &sample, Curve::LoopMode _loop_mode)
|
||||
{
|
||||
MotionChannel *c[3];
|
||||
GetTransformationChannels(NULL, c, NULL);
|
||||
for (int n = 0; n < 3; ++n)
|
||||
if (c[n])
|
||||
c[n]->Evaluate(t, &sample[n], _loop_mode);
|
||||
}
|
||||
|
||||
void Motion::EvaluateDirection(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode)
|
||||
{
|
||||
const float dt = 0.01f;
|
||||
|
||||
Vector4 p1(0,0,0), p2(0,0,0);
|
||||
|
||||
EvaluatePosition(t, p1, loop_mode);
|
||||
|
||||
Time t2 = Time::fromSec(t.toSec() + dt);
|
||||
EvaluatePosition(t2, p2, loop_mode);
|
||||
|
||||
sample = p2 - p1;
|
||||
|
||||
float len = sample.Len();
|
||||
if (len > 1e-4f)
|
||||
sample /= len;
|
||||
else
|
||||
sample = Vector4(0,0,0);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Motion::GetTransformationChannels(MotionChannel *t[3], MotionChannel *r[3], MotionChannel *s[3])
|
||||
{
|
||||
if (t) { t[0] = t[1] = t[2] = NULL; }
|
||||
if (r) { r[0] = r[1] = r[2] = NULL; }
|
||||
if (s) { s[0] = s[1] = s[2] = NULL; }
|
||||
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
switch (channel->type)
|
||||
{
|
||||
case MotionChannel::XPos: if (t) t[0] = channel; break;
|
||||
case MotionChannel::YPos: if (t) t[1] = channel; break;
|
||||
case MotionChannel::ZPos: if (t) t[2] = channel; break;
|
||||
case MotionChannel::XRot: if (r) r[0] = channel; break;
|
||||
case MotionChannel::YRot: if (r) r[1] = channel; break;
|
||||
case MotionChannel::ZRot: if (r) r[2] = channel; break;
|
||||
case MotionChannel::XScl: if (s) s[0] = channel; break;
|
||||
case MotionChannel::YScl: if (s) s[1] = channel; break;
|
||||
case MotionChannel::ZScl: if (s) s[2] = channel; break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
TimeRange Motion::GetTimeRange() const
|
||||
{
|
||||
if (channel_list.GetCount() == 0)
|
||||
return TimeRange();
|
||||
|
||||
List <MotionChannel *> ::Item *i = channel_list.GetRoot();
|
||||
|
||||
TimeRange range = i->Object()->GetTimeRange();
|
||||
for (i = i->Next(); i; i = i->Next())
|
||||
range = TimeRange::Union(range, i->Object()->GetTimeRange());
|
||||
|
||||
range = TimeRange::Union(range, quaternion.GetTimeRange());
|
||||
return range;
|
||||
}
|
||||
Time Motion::GetDuration() const
|
||||
{
|
||||
Time duration;
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
duration = Types::Max(duration, channel->GetDuration());
|
||||
return duration;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
MotionChannel *Motion::AddChannel(MotionChannel::Type type)
|
||||
{
|
||||
MotionChannel *nc = new MotionChannel;
|
||||
if (!nc)
|
||||
__ERR__(__LOG_E__ << "Could not allocate channel.\n", NULL)
|
||||
nc->type = type;
|
||||
channel_list.Add(nc);
|
||||
return nc;
|
||||
}
|
||||
void Motion::AddChannels(uint nc)
|
||||
{
|
||||
while (nc--)
|
||||
AddChannel(MotionChannel::Undf);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Motion::GetUseQuaternion() const
|
||||
{ return use_quaternion && quaternion.GetKeys().GetCount(); }
|
||||
MotionChannel *Motion::GetChannel(uint index) const
|
||||
{ return GetChannelList().ObjectAt(index); }
|
||||
MotionChannel *Motion::GetChannel(MotionChannel::Type type) const
|
||||
{
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
if (channel && channel->type == type)
|
||||
return channel;
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
size_t Motion::MemoryFootPrint() const
|
||||
{
|
||||
size_t footprint = 0;
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
footprint += channel->MemoryFootPrint();
|
||||
footprint += quaternion.MemoryFootPrint();
|
||||
footprint += sizeof(Motion);
|
||||
return footprint;
|
||||
}
|
||||
uint Motion::Optimize(float threshold)
|
||||
{
|
||||
uint wiped = 0;
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
forever
|
||||
{
|
||||
uint pass_wiped = channel->Optimize(threshold);
|
||||
if (!pass_wiped)
|
||||
break;
|
||||
wiped += pass_wiped;
|
||||
}
|
||||
|
||||
return wiped;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user