269 lines
7.2 KiB
C++
269 lines
7.2 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "geometry/curve.h"
|
|
#include "math/nmath.h"
|
|
#include "sort/sort.h"
|
|
#include "alloc/ialloc.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS;
|
|
using namespace GS::NML;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
Reflection::Enum::Dict Curve::loop_mode_dict[] =
|
|
{
|
|
{ Curve::Reset, "Reset" },
|
|
{ Curve::Constant, "Constant" },
|
|
{ Curve::Repeat, "Repeat" },
|
|
{ Curve::Oscillate, "Oscillate" },
|
|
{ Curve::OffsetAndRepeat, "OffsetAndRepeat" },
|
|
{ 0, 0 }
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// ARM odd address read/write helper functions.
|
|
void ARM_unaligned_read(float &out, const char *addr)
|
|
{
|
|
char *p_out = (char *)&out;
|
|
for (int n = 0; n < sizeof(float); ++n)
|
|
p_out[n] = addr[n];
|
|
}
|
|
void ARM_unaligned_write(char *addr, const float &in)
|
|
{
|
|
const char *p_in = (const char *)∈
|
|
for (int n = 0; n < sizeof(float); ++n)
|
|
addr[n] = p_in[n];
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Curve::FromMetaTag(Tag &tag)
|
|
{
|
|
if (tag.name != "Curve")
|
|
__ERR__(__LOG_E__ << "Could not parse curve, incorrect root tag (" << tag.name << ").\n", false)
|
|
|
|
Clear();
|
|
|
|
// Parse root tags.
|
|
NMLTagForeach(pt, tag)
|
|
{
|
|
if (pt->name == "BinaryKnot")
|
|
{
|
|
Tag *count_tag = pt->GetTag("Count"), *data_tag = pt->GetTag("Data");
|
|
|
|
if (count_tag && data_tag)
|
|
{
|
|
char *data = (char *)data_tag->GetValue().GetBinaryBuffer(), *p_data = data;
|
|
|
|
if (data && AllocatePoint(count_tag->GetInteger()))
|
|
for (uint n = 0; n < points.GetCount(); ++n)
|
|
{
|
|
CurvePoint *p = points[n];
|
|
|
|
p->shape = CurvePoint::Shape(*p_data++);
|
|
|
|
float t;
|
|
ARM_unaligned_read(t, p_data + 0);
|
|
p->t.setSec(t);
|
|
ARM_unaligned_read(p->v, p_data + 4);
|
|
|
|
if (p->shape == CurvePoint::Shape_Linear)
|
|
p_data += 2 * 4;
|
|
|
|
else
|
|
{
|
|
ARM_unaligned_read(p->tension, p_data + 8);
|
|
ARM_unaligned_read(p->continuity, p_data + 12);
|
|
ARM_unaligned_read(p->bias, p_data + 16);
|
|
|
|
for (int n = 0; n < 4; ++n)
|
|
ARM_unaligned_read(p->param[n], p_data + 20 + n * 4);
|
|
|
|
p_data += 9 * 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pt->name == "Knot")
|
|
{
|
|
Tag *st = pt->GetTags()[0];
|
|
if (!st || (st->name != "Count"))
|
|
__ERR__(__LOG_E__ << "First sub-tag in <Curve> must be the knot <Count> tag.\n", false)
|
|
|
|
if (!AllocatePoint((uint)st->GetInteger()))
|
|
return false;
|
|
|
|
static String _count("Count"), _knot("Knot"), _knotex("KnotEx");
|
|
|
|
uint n = 0;
|
|
NMLTagForeach(st, *pt)
|
|
{
|
|
if (st->name == _count)
|
|
{}
|
|
|
|
// Legacy knot definition.
|
|
if (st->name == _knot)
|
|
{
|
|
if (n == points.GetCount())
|
|
{
|
|
__LOG_E__ << "Too many knot in <Curve>, " << points.GetCount() << " expected.\n";
|
|
break;
|
|
}
|
|
|
|
if (const char *p = st->GetString())
|
|
{
|
|
points[n]->t = Time::fromSec(String::atof(p));
|
|
points[n]->shape = CurvePoint::Shape_Linear;
|
|
|
|
p = String::strfindchar(p, ':');
|
|
points[n]->v = p[0] ? String::atof(p + 1) : 0;
|
|
|
|
n++;
|
|
}
|
|
else
|
|
__LOG_W__ << "Invalid knot tag while parsing curve.\n";
|
|
}
|
|
|
|
/*
|
|
Extended knot definition.
|
|
*/
|
|
else if (st->name == _knotex)
|
|
{
|
|
if (n == points.GetCount())
|
|
{
|
|
__LOG_E__ << "Too many knot in <Knot>, " << points.GetCount() << " specified.\n";
|
|
break;
|
|
}
|
|
|
|
if (const char *p = st->GetString())
|
|
{
|
|
CurvePoint *_knot = points[n];
|
|
_knot->t = Time::fromSec(String::atof(p));
|
|
|
|
// Read shape.
|
|
p = String::strfindchar(p, ':');
|
|
int shape = p[0] ? String::atoi(p + 1) : 0;
|
|
p++;
|
|
|
|
switch (shape)
|
|
{
|
|
default:
|
|
case 0: _knot->shape = CurvePoint::Shape_None; break;
|
|
case 1: _knot->shape = CurvePoint::Shape_Linear; break;
|
|
case 2: _knot->shape = CurvePoint::Shape_Bezier; break;
|
|
case 3: _knot->shape = CurvePoint::Shape_Bezier2; break;
|
|
case 4: _knot->shape = CurvePoint::Shape_Hermite; break;
|
|
case 5: _knot->shape = CurvePoint::Shape_TCB; break;
|
|
case 6: _knot->shape = CurvePoint::Shape_Step; break;
|
|
}
|
|
|
|
// Read knot parameters.
|
|
//--------------------------------------------
|
|
#define GetInputKnotParamEx(_PARM_)\
|
|
{\
|
|
p = String::strfindchar(p, ':');\
|
|
(_PARM_) = p[0] ? String::atof(p + 1) : -1;\
|
|
p++;\
|
|
}
|
|
//--------------------------------------------
|
|
|
|
GetInputKnotParamEx(_knot->v);
|
|
GetInputKnotParamEx(_knot->tension);
|
|
GetInputKnotParamEx(_knot->continuity);
|
|
GetInputKnotParamEx(_knot->bias);
|
|
|
|
GetInputKnotParamEx(_knot->param[0]);
|
|
GetInputKnotParamEx(_knot->param[1]);
|
|
GetInputKnotParamEx(_knot->param[2]);
|
|
GetInputKnotParamEx(_knot->param[3]);
|
|
n++;
|
|
}
|
|
else
|
|
__LOG_W__ << "Invalid extended knot tag while parsing curve.\n";
|
|
}
|
|
else
|
|
__LOG_W__ << "Unsupported knot tag '" << st->name << "'.\n";
|
|
}
|
|
|
|
// Incomplete/erroneous definition.
|
|
if (n != points.GetCount())
|
|
{
|
|
Clear();
|
|
__ERR__(__LOG_E__ << "<Curve> is corrupted, discarding.\n", false)
|
|
}
|
|
}
|
|
else __LOG_W__ << "Unknown tag '" << pt->name << "' in <Curve>.\n";
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
Tag *Curve::AsMetaTag() const
|
|
{
|
|
Tag *root = new Tag("Curve");
|
|
if (!root)
|
|
__ERR__(__LOG_E__ << "Could not create curve root tag to serialize.\n", NULL)
|
|
|
|
// Binary knots.
|
|
if (points.GetCount())
|
|
if (Tag *binary_knot_tag = root->AddChild("BinaryKnot"))
|
|
{
|
|
binary_knot_tag->AddChild("Count", points.GetCount());
|
|
|
|
// Get size.
|
|
int size = 0;
|
|
for (uint n = 0; n < points.GetCount(); ++n)
|
|
{
|
|
CurvePoint *_knot = points[n];
|
|
|
|
// Legacy definition.
|
|
if (_knot->shape == CurvePoint::Shape_Linear)
|
|
size += 2 * 4; // Knot size.
|
|
else size += 9 * 4; // Extended knot size.
|
|
}
|
|
|
|
// Output binary.
|
|
Array <char> knot_array(points.GetCount() + size);
|
|
char *p_knot = knot_array;
|
|
|
|
for (uint n = 0; n < points.GetCount(); ++n)
|
|
{
|
|
CurvePoint *_knot = points[n];
|
|
|
|
*p_knot++ = uchar(_knot->shape);
|
|
|
|
float t = _knot->t.toSec();
|
|
ARM_unaligned_write(p_knot + 0, t);
|
|
ARM_unaligned_write(p_knot + 4, _knot->v);
|
|
|
|
if (_knot->shape == CurvePoint::Shape_Linear)
|
|
p_knot += 2 * 4;
|
|
|
|
else
|
|
{
|
|
ARM_unaligned_write(p_knot + 8, _knot->tension);
|
|
ARM_unaligned_write(p_knot + 12, _knot->continuity);
|
|
ARM_unaligned_write(p_knot + 16, _knot->bias);
|
|
|
|
for (int n = 0; n < 4; ++n)
|
|
ARM_unaligned_write(p_knot + 20 + n * 4, _knot->param[n]);
|
|
|
|
p_knot += 9 * 4;
|
|
}
|
|
}
|
|
|
|
binary_knot_tag->AddChild("Data", knot_array, points.GetCount() + size);
|
|
}
|
|
|
|
return root;
|
|
}
|
|
//------------------------------------------------------------------------------
|