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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@ -59,6 +59,7 @@ public:
|
||||
|
||||
void EvaluateData(const Time &t, Variant &sample);
|
||||
void EvaluatePosition(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset);
|
||||
void EvaluateDirection(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset);
|
||||
void EvaluateRotation(const Time &t, Vector4 &sample, Curve::LoopMode loop_mode = Curve::Reset);
|
||||
|
||||
/// Get transformation channels.
|
||||
|
||||
143
include/engine/motion/motion_automation_source.cpp
Normal file
143
include/engine/motion/motion_automation_source.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/motion_automation_source.h"
|
||||
#include "motion/motion.h"
|
||||
#include "automation/automation_source_group.h"
|
||||
#include "automation/automation_player.h"
|
||||
|
||||
using namespace GS::Automation;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void MotionSource::Evaluate(Player &target)
|
||||
{
|
||||
if (motion == NULL)
|
||||
return;
|
||||
|
||||
ListForeachPtr(MotionChannel *, channel, motion->GetChannelList())
|
||||
{
|
||||
if (channel->GetPointCount() == 0)
|
||||
continue;
|
||||
|
||||
// Skip rotation channels if using quaternion.
|
||||
if (motion->GetUseQuaternion())
|
||||
switch (channel->type)
|
||||
{
|
||||
case MotionChannel::XRot:
|
||||
case MotionChannel::YRot:
|
||||
case MotionChannel::ZRot:
|
||||
continue;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Evaluate channel.
|
||||
float v;
|
||||
channel->Evaluate(time, &v, loop_mode, loop_start, loop_end);
|
||||
|
||||
// Relative mode.
|
||||
switch (channel->type)
|
||||
{
|
||||
case MotionChannel::XPos:
|
||||
case MotionChannel::YPos:
|
||||
case MotionChannel::ZPos:
|
||||
{
|
||||
float _v = v, s;
|
||||
if (relative && target.property_provider->GetProperty(channel->type, s))
|
||||
v = s + v - p_pos[channel->type - MotionChannel::XPos];
|
||||
p_pos[channel->type - MotionChannel::XPos] = _v;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionChannel::XRot:
|
||||
case MotionChannel::YRot:
|
||||
case MotionChannel::ZRot:
|
||||
{
|
||||
float _v = v, s;
|
||||
if (relative && target.property_provider->GetProperty(channel->type, s))
|
||||
v = s + v - p_euler[channel->type - MotionChannel::XRot];
|
||||
p_euler[channel->type - MotionChannel::XRot] = _v;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
target.BlendAutomatedProperty(channel->type, v, GetWeight());
|
||||
}
|
||||
}
|
||||
bool MotionSource::EvaluateRotation(GS::Quaternion &q)
|
||||
{
|
||||
if (!motion->GetUseQuaternion())
|
||||
return false;
|
||||
|
||||
Quaternion s = q;
|
||||
motion->GetQuaternion().Evaluate(time, q, loop_mode, loop_start, loop_end);
|
||||
|
||||
Quaternion _q = q;
|
||||
if (relative)
|
||||
q = (q * p_quat.Inverse()) * s;
|
||||
p_quat = _q;
|
||||
return true;
|
||||
}
|
||||
bool MotionSource::IsDone() const
|
||||
{
|
||||
if (!motion)
|
||||
return true;
|
||||
|
||||
switch (loop_mode)
|
||||
{
|
||||
case Curve::Repeat:
|
||||
case Curve::OffsetAndRepeat:
|
||||
case Curve::Oscillate:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (time_scale > 0)
|
||||
{
|
||||
if (time > loop_end)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (time < loop_start)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
MotionSource::MotionSource(Motion *_motion, SourceGroup *_group)
|
||||
{
|
||||
type = TypeMotion;
|
||||
motion = _motion;
|
||||
|
||||
loop_mode = Curve::Constant;
|
||||
|
||||
if (motion)
|
||||
{
|
||||
TimeRange range = motion->GetTimeRange();
|
||||
loop_start = range.start;
|
||||
loop_end = range.end;
|
||||
}
|
||||
else
|
||||
{
|
||||
loop_start = Time::Inf;
|
||||
loop_end = Time::Inf;
|
||||
}
|
||||
|
||||
// Evaluate relative position/euler.
|
||||
relative = false;
|
||||
|
||||
motion->EvaluatePosition(loop_start, p_pos, loop_mode);
|
||||
if (motion->GetUseQuaternion())
|
||||
motion->GetQuaternion().Evaluate(loop_start, p_quat, loop_mode);
|
||||
else motion->EvaluateRotation(loop_start, p_euler, loop_mode);
|
||||
|
||||
group = _group;
|
||||
if (group)
|
||||
group->source_list.Add(this, true, false);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
17
include/engine/motion/motion_channel.cpp
Normal file
17
include/engine/motion/motion_channel.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/motion_channel.h"
|
||||
|
||||
using namespace GS::Core;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
MotionChannel::MotionChannel()
|
||||
{ type = NoType; }
|
||||
MotionChannel::~MotionChannel()
|
||||
{ Clear(); }
|
||||
//------------------------------------------------------------------------------
|
||||
131
include/engine/motion/motion_channel_nml.cpp
Normal file
131
include/engine/motion/motion_channel_nml.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/motion_channel.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::Core;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool MotionChannel::FromMetaTag(GS::NML::Tag &tag)
|
||||
{
|
||||
if (tag.name != "Channel")
|
||||
__ERR__(__LOG_E__ << "Could not parse motion channel, incorrect root tag (" << tag.name << ").\n", false)
|
||||
|
||||
// Parse root tags.
|
||||
NMLTagForeach(pt, tag)
|
||||
{
|
||||
if (pt->name == "Curve")
|
||||
Curve::FromMetaTag(*pt);
|
||||
|
||||
else if (pt->name == "Id")
|
||||
{
|
||||
String chn(pt->GetString());
|
||||
|
||||
if (chn == "PositionX") type = XPos;
|
||||
else if (chn == "PositionY") type = YPos;
|
||||
else if (chn == "PositionZ") type = ZPos;
|
||||
else if (chn == "RotationX") type = XRot;
|
||||
else if (chn == "RotationY") type = YRot;
|
||||
else if (chn == "RotationZ") type = ZRot;
|
||||
else if (chn == "ScaleX") type = XScl;
|
||||
else if (chn == "ScaleY") type = YScl;
|
||||
else if (chn == "ScaleZ") type = ZScl;
|
||||
|
||||
else if (chn == "PivotX") type = XPiv;
|
||||
else if (chn == "PivotY") type = YPiv;
|
||||
else if (chn == "PivotZ") type = ZPiv;
|
||||
|
||||
else if (chn == "DiffuseR") type = RDif;
|
||||
else if (chn == "DiffuseG") type = GDif;
|
||||
else if (chn == "DiffuseB") type = BDif;
|
||||
else if (chn == "SpecularR") type = RSpc;
|
||||
else if (chn == "SpecularG") type = GSpc;
|
||||
else if (chn == "SpecularB") type = BSpc;
|
||||
|
||||
else if (chn == "DiffuseI") type = DiffuseIntensity;
|
||||
else if (chn == "SpecularI") type = SpecularIntensity;
|
||||
|
||||
else if (chn == "ConeAngle") type = ConeAngle;
|
||||
else if (chn == "EdgeAngle") type = EdgeAngle;
|
||||
|
||||
else if (chn == "Alpha") type = Alpha;
|
||||
|
||||
else if (chn == "Zoom") type = ZoomFactor;
|
||||
|
||||
else if (chn == "Range") type = Range;
|
||||
|
||||
else if (chn == "FogStart") type = FogStart;
|
||||
else if (chn == "FogEnd") type = FogEnd;
|
||||
else if (chn == "FogR") type = RFog;
|
||||
else if (chn == "FogG") type = GFog;
|
||||
else if (chn == "FogB") type = BFog;
|
||||
|
||||
else __LOG_W__ << "Unknown channel id '" << chn << "'.\n";
|
||||
}
|
||||
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Channel>.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
GS::NML::Tag *MotionChannel::AsMetaTag() const
|
||||
{
|
||||
NML::Tag *root = new NML::Tag("Channel");
|
||||
if (!root)
|
||||
__ERR__(__LOG_E__ << "Could not create channel root tag to serialize.\n", NULL)
|
||||
|
||||
// Serialize underlying curve.
|
||||
root->AddChild(Curve::AsMetaTag());
|
||||
|
||||
// Channel type.
|
||||
switch (type)
|
||||
{
|
||||
case XPos: root->AddChild("Id", "PositionX"); break;
|
||||
case YPos: root->AddChild("Id", "PositionY"); break;
|
||||
case ZPos: root->AddChild("Id", "PositionZ"); break;
|
||||
case XRot: root->AddChild("Id", "RotationX"); break;
|
||||
case YRot: root->AddChild("Id", "RotationY"); break;
|
||||
case ZRot: root->AddChild("Id", "RotationZ"); break;
|
||||
case XScl: root->AddChild("Id", "ScaleX"); break;
|
||||
case YScl: root->AddChild("Id", "ScaleY"); break;
|
||||
case ZScl: root->AddChild("Id", "ScaleZ"); break;
|
||||
|
||||
case XPiv: root->AddChild("Id", "PivotX"); break;
|
||||
case YPiv: root->AddChild("Id", "PivotY"); break;
|
||||
case ZPiv: root->AddChild("Id", "PivotZ"); break;
|
||||
|
||||
case RDif: root->AddChild("Id", "DiffuseR"); break;
|
||||
case GDif: root->AddChild("Id", "DiffuseG"); break;
|
||||
case BDif: root->AddChild("Id", "DiffuseB"); break;
|
||||
case RSpc: root->AddChild("Id", "SpecularR"); break;
|
||||
case GSpc: root->AddChild("Id", "SpecularG"); break;
|
||||
case BSpc: root->AddChild("Id", "SpecularB"); break;
|
||||
|
||||
case DiffuseIntensity: root->AddChild("Id", "DiffuseI"); break;
|
||||
case SpecularIntensity: root->AddChild("Id", "SpecularI"); break;
|
||||
|
||||
case ConeAngle: root->AddChild("Id", "ConeAngle"); break;
|
||||
case EdgeAngle: root->AddChild("Id", "EdgeAngle"); break;
|
||||
|
||||
case Alpha: root->AddChild("Id", "Alpha"); break;
|
||||
|
||||
case ZoomFactor: root->AddChild("Id", "Zoom"); break;
|
||||
|
||||
case Range: root->AddChild("Id", "Range"); break;
|
||||
|
||||
case FogStart: root->AddChild("Id", "FogStart"); break;
|
||||
case FogEnd: root->AddChild("Id", "FogEnd"); break;
|
||||
case RFog: root->AddChild("Id", "FogR"); break;
|
||||
case GFog: root->AddChild("Id", "FogG"); break;
|
||||
case BFog: root->AddChild("Id", "FogB"); break;
|
||||
|
||||
default:
|
||||
__LOG_W__ << "Unknown motion channel type (" << type << ").\n";
|
||||
break;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
108
include/engine/motion/motion_nml.cpp
Normal file
108
include/engine/motion/motion_nml.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/motion.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::Core;
|
||||
using GS::NML::Tag;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Motion::FromMetaTag(Tag &tag)
|
||||
{
|
||||
if (tag.name != "Motion")
|
||||
__ERR__(__LOG_E__ << "Could not parse motion, incorrect root tag (" << tag.name << ").\n", false)
|
||||
|
||||
use_quaternion = false;
|
||||
|
||||
// Parse root tags.
|
||||
NMLTagForeach(pt, tag)
|
||||
{
|
||||
if (pt->name == "Id")
|
||||
name = pt->GetString();
|
||||
else if (pt->name == "UseQuaternion")
|
||||
use_quaternion = pt->GetBool();
|
||||
else if (pt->name == "QChannel")
|
||||
quaternion.FromMetaTag(*pt);
|
||||
|
||||
else if (pt->name == "Channel")
|
||||
{
|
||||
MotionChannel *chn = AddChannel(MotionChannel::Undf);
|
||||
chn->FromMetaTag(*pt);
|
||||
}
|
||||
else if (pt->name == "DataKnot")
|
||||
{
|
||||
Tag *count_tag = pt->GetTag("Count");
|
||||
|
||||
ArrayListDeleteAllPtr(SDataPoint *, data_point)
|
||||
|
||||
if (count_tag && count_tag->GetInteger() > 0)
|
||||
{
|
||||
uint n = (uint)count_tag->GetInteger();
|
||||
while (n--)
|
||||
if (!data_point.Add(new SDataPoint))
|
||||
return false;
|
||||
|
||||
n = 0;
|
||||
NMLTagForeach(st, *pt)
|
||||
{
|
||||
if (st->name == "Knot")
|
||||
{
|
||||
if (n == data_point.GetCount())
|
||||
{
|
||||
__LOG_E__ << "Too many knot in <DataKnot>, " << data_point.GetCount() << " expected.\n";
|
||||
break;
|
||||
}
|
||||
|
||||
if (const char *p = st->GetString())
|
||||
{
|
||||
data_point[n]->t = Time::fromSec(String::atof(p));
|
||||
|
||||
p = String::strfindchar(p, ':');
|
||||
data_point[n]->data = Variant(p + 1);
|
||||
|
||||
n++;
|
||||
}
|
||||
else
|
||||
__LOG_W__ << "Invalid knot tag while parsing curve.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Motion>.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Tag *Motion::AsMetaTag()
|
||||
{
|
||||
Tag *root = new Tag("Motion");
|
||||
if (!root)
|
||||
__ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL)
|
||||
|
||||
root->AddChild("Id", name.c_str());
|
||||
|
||||
// Dump quaternion channel.
|
||||
root->AddChild("UseQuaternion", use_quaternion);
|
||||
root->AddChild(quaternion.AsMetaTag());
|
||||
|
||||
// Dump all channels.
|
||||
ListForeachPtr(MotionChannel *, channel, channel_list)
|
||||
root->AddChild(channel->AsMetaTag());
|
||||
|
||||
// Dump the data array
|
||||
if (data_point.GetCount())
|
||||
if (Tag *data_knot_tag = root->AddChild("DataKnot"))
|
||||
{
|
||||
data_knot_tag->AddChild("Count", (int)data_point.GetCount());
|
||||
|
||||
ArrayListForeachPtr(SDataPoint *, data, data_point)
|
||||
data_knot_tag->AddChild("Knot",String::Format("%f:%s", data->t.toSec(), data->data.s_value.c_str()).c_str());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
179
include/engine/motion/quaternion_channel.cpp
Normal file
179
include/engine/motion/quaternion_channel.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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(); }
|
||||
//------------------------------------------------------------------------------
|
||||
121
include/engine/motion/quaternion_channel_nml.cpp
Normal file
121
include/engine/motion/quaternion_channel_nml.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/quaternion_channel.h"
|
||||
#include "metafile/nml.h"
|
||||
#include "alloc/ialloc.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using NML::Tag;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool QuaternionChannel::FromMetaTag(Tag &tag)
|
||||
{
|
||||
if (tag.name != "QChannel")
|
||||
__ERR__(__LOG_E__ << "Could not parse motion quaternion channel, incorrect root tag (" << tag.name << ").\n", false)
|
||||
|
||||
Clear();
|
||||
|
||||
// Parse root tags.
|
||||
NMLTagForeach(pt, tag)
|
||||
{
|
||||
if (pt->name == "BinaryKeys")
|
||||
{
|
||||
Tag *count_tag = pt->GetTag("Count"), *data_tag = pt->GetTag("Data");
|
||||
|
||||
if (count_tag && data_tag)
|
||||
{
|
||||
float *data = (float *)data_tag->GetValue().GetBinaryBuffer(), *p_data = data;
|
||||
|
||||
if (data)
|
||||
{
|
||||
int count = count_tag->GetInteger();
|
||||
for (int n = 0; n < count; ++n)
|
||||
{
|
||||
QuaternionKey *key = new QuaternionKey;
|
||||
|
||||
key->t = Time::fromSec(*p_data++);
|
||||
key->q.x = *p_data++;
|
||||
key->q.y = *p_data++;
|
||||
key->q.z = *p_data++;
|
||||
key->q.w = *p_data++;
|
||||
|
||||
keys.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pt->name == "Keys")
|
||||
{
|
||||
NMLTagForeach(st, *pt)
|
||||
if (st->name == "Key")
|
||||
{
|
||||
const char *p = st->GetString();
|
||||
if (!p)
|
||||
__LOG_W__ << "Invalid key tag while parsing quaternion channel.\n";
|
||||
|
||||
else
|
||||
{
|
||||
//-------------------------------------------------------------------------------------------
|
||||
#define SEEK_CHAR(v) \
|
||||
p = String::strfindchar(p, (v)); \
|
||||
if (!p[0]) \
|
||||
__ERR__(__LOG_W__ << "Mangled keyframe tag while parsing quaternion channel.\n", false) \
|
||||
p++; \
|
||||
//-------------------------------------------------------------------------------------------
|
||||
|
||||
QuaternionKey *key = new QuaternionKey;
|
||||
|
||||
key->t = Time::fromSec(String::atof(p, NULL, false));
|
||||
SEEK_CHAR(':');
|
||||
|
||||
key->q.x = String::atof(p, NULL, false);
|
||||
SEEK_CHAR(',');
|
||||
key->q.y = String::atof(p, NULL, false);
|
||||
SEEK_CHAR(',');
|
||||
key->q.z = String::atof(p, NULL, false);
|
||||
SEEK_CHAR(',');
|
||||
key->q.w = String::atof(p, NULL, false);
|
||||
|
||||
keys.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <QChannel>.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Tag *QuaternionChannel::AsMetaTag()
|
||||
{
|
||||
Tag *root = new Tag("QChannel");
|
||||
if (!root)
|
||||
__ERR__(__LOG_E__ << "Could not create quaternion channel root tag to serialize.\n", NULL)
|
||||
|
||||
if (keys.GetCount())
|
||||
if (Tag *kf_tag = root->AddChild("BinaryKeys"))
|
||||
{
|
||||
kf_tag->AddChild("Count", (int)keys.GetCount()); // Legacy support.
|
||||
|
||||
float *kf_array = new float[5 * keys.GetCount()], *p_kf = kf_array;
|
||||
|
||||
for (uint n = 0; n < keys.GetCount(); n++)
|
||||
{
|
||||
*p_kf++ = keys[n]->t.toSec();
|
||||
*p_kf++ = keys[n]->q.x;
|
||||
*p_kf++ = keys[n]->q.y;
|
||||
*p_kf++ = keys[n]->q.z;
|
||||
*p_kf++ = keys[n]->q.w;
|
||||
}
|
||||
|
||||
kf_tag->AddChild("Data", (uchar *)kf_array, 5 * 4 * keys.GetCount());
|
||||
_safe_delete_array(kf_array);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
138
include/engine/motion/scene_motion.cpp
Normal file
138
include/engine/motion/scene_motion.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/scene_motion.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
using GS::NML::Tag;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Motion *SceneMotion::GetItemMotion(uint uid, bool create_if_missing)
|
||||
{
|
||||
ListForeachPtr(ItemMotion *, m, item_motions)
|
||||
if (m->uid == uid)
|
||||
return m->motion;
|
||||
|
||||
if (!create_if_missing)
|
||||
return NULL;
|
||||
|
||||
ItemMotion *item_motion = new ItemMotion;
|
||||
if (!item_motion)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate item motion.\n", NULL)
|
||||
|
||||
item_motion->uid = uid;
|
||||
item_motion->motion = new Motion;
|
||||
|
||||
item_motions.Add(item_motion);
|
||||
return item_motion->motion;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SceneMotion::Clone(const SceneMotion &src, const TimeRange &range, bool enforce_loop)
|
||||
{
|
||||
// Clone item motions.
|
||||
item_motions.Clear();
|
||||
|
||||
ListForeachPtr(ItemMotion *, m, src.item_motions)
|
||||
{
|
||||
ItemMotion *c = new ItemMotion;
|
||||
if (c == NULL)
|
||||
continue;
|
||||
|
||||
c->uid = m->uid;
|
||||
c->motion = new Motion;
|
||||
c->motion->Clone(*m->motion, range, enforce_loop);
|
||||
|
||||
item_motions.Add(c);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
TimeRange SceneMotion::GetTimeRange() const
|
||||
{
|
||||
List <ItemMotion *> ::Item *i = item_motions.GetRoot();
|
||||
if (i == NULL)
|
||||
return TimeRange();
|
||||
|
||||
TimeRange range = i->Object()->motion->GetTimeRange();
|
||||
for (i = i->Next(); i; i = i->Next())
|
||||
range = TimeRange::Union(range, i->Object()->motion->GetTimeRange());
|
||||
|
||||
return range;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool SceneMotion::FromMetaTag(Tag &tag, const Map <uint, uint> *uid_map)
|
||||
{
|
||||
if (tag.name != "SceneMotion")
|
||||
__ERR__(__LOG_E__ << "Could not parse scene motion, incorrect root tag (" << tag.name << ").\n", false)
|
||||
|
||||
item_motions.Clear();
|
||||
|
||||
// Parse root tags.
|
||||
NMLTagForeach(pt, tag)
|
||||
{
|
||||
if (pt->name == "Name")
|
||||
name = pt->GetString();
|
||||
|
||||
else if (pt->name == "ItemMotions")
|
||||
{
|
||||
NMLTagForeach(it, *pt)
|
||||
{
|
||||
if (it->name == "ItemMotion")
|
||||
{
|
||||
Tag *uid_tag = it->GetTypedTag("UId", Variant::VariantInteger),
|
||||
*motion_tag = it->GetTag("Motion");
|
||||
|
||||
if (uid_tag && motion_tag)
|
||||
{
|
||||
uint uid = uid_tag->GetUnsigned();
|
||||
if (uid_map && !uid_map->HasKey(uid))
|
||||
continue; // item got lost, don't load
|
||||
|
||||
ItemMotion *item_motion = new ItemMotion;
|
||||
|
||||
item_motion->uid = uid_map ? (*uid_map)[uid] : uid;
|
||||
item_motion->motion = new Motion;
|
||||
item_motion->motion->FromMetaTag(*motion_tag);
|
||||
|
||||
item_motions.Add(item_motion);
|
||||
}
|
||||
else
|
||||
__LOG_W__ << "Mangled item motion tag.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
__LOG_W__ << "Unknown tag '" << pt->name << "' in <SceneMotion>.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Tag *SceneMotion::AsMetaTag()
|
||||
{
|
||||
Tag *root = new Tag("SceneMotion");
|
||||
if (!root)
|
||||
__ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL)
|
||||
|
||||
root->AddChild("Name", name);
|
||||
|
||||
if (Tag *pim = root->AddChild("ItemMotions"))
|
||||
ListForeachPtr(ItemMotion *, m, item_motions)
|
||||
if (Tag *pm = pim->AddChild("ItemMotion"))
|
||||
{
|
||||
pm->AddChild("UId", m->uid);
|
||||
pm->AddChild(m->motion->AsMetaTag());
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
48
include/engine/motion/scene_motion_container.cpp
Normal file
48
include/engine/motion/scene_motion_container.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "motion/scene_motion_container.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
using GS::NML::Tag;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool SceneMotionContainer::FromMetaTag(Tag &tag, const Map <uint, uint> *uid_map)
|
||||
{
|
||||
if (tag.name != "SceneMotionContainer")
|
||||
__ERR__(__LOG_E__ << "Could not parse scene motion container, incorrect root tag (" << tag.name << ").\n", false)
|
||||
|
||||
motions.Clear();
|
||||
|
||||
// Parse root tags.
|
||||
NMLTagForeach(pt, tag)
|
||||
{
|
||||
if (pt->name == "SceneMotion")
|
||||
{
|
||||
SceneMotion *set = new SceneMotion;
|
||||
set->FromMetaTag(*pt, uid_map);
|
||||
motions.Add(set);
|
||||
}
|
||||
else
|
||||
__LOG_W__ << "Unknown tag '" << pt->name << "' in <SceneMotionContainer>.\n";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Tag *SceneMotionContainer::AsMetaTag() const
|
||||
{
|
||||
Tag *root = new Tag("SceneMotionContainer");
|
||||
if (!root)
|
||||
__ERR__(__LOG_E__ << "Could not create root tag to serialize.\n", NULL)
|
||||
|
||||
ListForeachPtr(SceneMotion *, s, motions)
|
||||
root->AddChild(s->AsMetaTag());
|
||||
|
||||
return root;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user