/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #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 must be the knot 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 , " << 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 , " << 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__ << " is corrupted, discarding.\n", false) } } else __LOG_W__ << "Unknown tag '" << pt->name << "' in .\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 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; } //------------------------------------------------------------------------------