commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions

View File

@ -0,0 +1,342 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <float.h>
#include "geometry/bounding_box.h"
#include "metafile/nml.h"
#include "math/matrix4.h"
using namespace GS;
using namespace GS::NML;
//------------------------------------------------------------------------------
void OBB::Transform(const Matrix4 &mtx)
{
Matrix3 rmtx = Matrix3::FromMatrix4(mtx);
bb_rotation = rmtx * bb_rotation;
bb_position = bb_position * rmtx + mtx.GetRow(3);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void OBB::ComputeMinMax(MinMax &minmax)
{
Vector4 xtd(bb_scale * 0.5f);
Vector4 smt[4];
smt[0].Set(xtd.x, xtd.y, xtd.z);
smt[1].Set(-xtd.x, xtd.y, xtd.z);
smt[2].Set(xtd.x, -xtd.y, xtd.z);
smt[3].Set(xtd.x, xtd.y, -xtd.z);
int n;
for (n = 0; n < 4; n++)
smt[n] = (smt[n] * bb_rotation).Abs();
minmax.mx = smt[0];
for (n = 1; n < 4; n++)
{
if (smt[n].x > minmax.mx.x) minmax.mx.x = smt[n].x;
if (smt[n].y > minmax.mx.y) minmax.mx.y = smt[n].y;
if (smt[n].z > minmax.mx.z) minmax.mx.z = smt[n].z;
}
minmax.mn.x = -minmax.mx.x;
minmax.mn.y = -minmax.mx.y;
minmax.mn.z = -minmax.mx.z;
minmax.mn += bb_position;
minmax.mx += bb_position;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool OBB::FromMetaTag(Tag &tag)
{
Tag *t;
List <Tag *> ::Iterator i(tag.GetTags().GetRoot());
t = i.ObjectPtr();
if (!t) return false;
bb_position.FromMetaTag(*t);
++i;
t = i.ObjectPtr();
if (!t) return false;
bb_scale.FromMetaTag(*t);
++i;
t = i.ObjectPtr();
if (!t) return false;
bb_rotation.FromMetaTag(*t);
return true;
}
Tag *OBB::AsMetaTag()
{
Tag *root = new Tag("OBB");
if (root)
{
root->AddChild(bb_position.AsMetaTag("Position"));
root->AddChild(bb_scale.AsMetaTag("Scale"));
root->AddChild(bb_rotation.AsMetaTag("Matrix"));
}
return root;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool MinMax::IntersectRay(const Vector4 &o, const Vector4 &d, float &tmin, float &tmax)
{
tmin = 0;
tmax = FLT_MAX;
for (uint n = 0; n < 3; ++n)
if (Math::EqualZero(d[n]))
{
if ((o[n] < mn[n]) || (o[n] > mx[n]))
return false;
}
else
{
float ood = 1.f / d[n];
float t0 = (mn[n] - o[n]) * ood;
float t1 = (mx[n] - o[n]) * ood;
if (t0 > t1)
{ float swp = t1; t1 = t0; t0 = swp; }
tmin = tmin < t0 ? t0 : tmin;
tmax = tmax < t1 ? tmax : t1;
if (tmin > tmax)
return false;
}
return true;
}
bool MinMax::ClassifyLine(const Vector4 &p1, const Vector4 &direction, Vector4 &itr, Vector4 *n) const
{
uint oc1, oc2;
oc1 = cc_oc(mn, mx, p1);
if (oc1 == ClipNone)
{
// Point inside bounding box.
if (n)
n->Set(0, 0, 0);
itr = p1;
return true;
}
oc2 = ss_oc(direction);
// Same side.
if ((oc1 & oc2) > ClipNone)
return false;
// Check intersections.
if (oc1 & (ClipRight | ClipLeft))
{
if (oc1 & ClipRight)
{
if (n)
n->Set(1, 0, 0);
itr.x = mx.x;
}
else
{
if (n)
n->Set(-1, 0, 0);
itr.x = mn.x;
}
float x1 = direction.x;
float x2 = itr.x - p1.x;
itr.y = p1.y + x2 * direction.y / x1;
itr.z = p1.z + x2 * direction.z / x1;
if ((itr.y <= mx.y) && (itr.y >= mn.y) && (itr.z <= mx.z) && (itr.z >= mn.z))
return true;
}
if (oc1 & (ClipTop | ClipBottom))
{
if (oc1 & ClipTop)
{
if (n)
n->Set(0, 1, 0);
itr.y = mx.y;
}
else
{
if (n)
n->Set(0, -1, 0);
itr.y = mn.y;
}
float y1 = direction.y;
float y2 = itr.y - p1.y;
itr.x = p1.x + y2 * direction.x / y1;
itr.z = p1.z + y2 * direction.z / y1;
if ((itr.x <= mx.x) && (itr.x >= mn.x) && (itr.z <= mx.z) && (itr.z >= mn.z))
return true;
}
if (oc1 & (ClipFront | ClipBack))
{
if (oc1 & ClipBack)
{
if (n)
n->Set(0, 0, 1);
itr.z = mx.z;
}
else
{
if (n)
n->Set(0, 0, -1);
itr.z = mn.z;
}
float z1 = direction.z;
float z2 = itr.z - p1.z;
itr.x = p1.x + z2 * direction.x / z1;
itr.y = p1.y + z2 * direction.y / z1;
if ((itr.x <= mx.x) && (itr.x >= mn.x) && (itr.y <= mx.y) && (itr.y >= mn.y))
return true;
}
return false;
}
bool MinMax::ClassifySegment(const Vector4 &p1, const Vector4 &p2, Vector4 &itr, Vector4 *n) const
{
uint oc1, oc2;
oc1 = cc_oc(mn, mx, p1);
if (oc1 == ClipNone)
{
// Point inside bounding box.
if (n)
n->Set(0, 0, 0);
itr = p1;
return true;
}
oc2 = cc_oc(mn, mx, p2);
if (oc2 == ClipNone)
{
// point inside bounding box
itr = p2;
return true;
}
// Same side.
if ((oc1 & oc2) > ClipNone)
return false;
// Check intersections.
if (oc1 & (ClipRight | ClipLeft))
{
if (oc1 & ClipRight)
{
if (n)
n->Set(1, 0, 0);
itr.x = mx.x;
}
else
{
if (n)
n->Set(-1, 0, 0);
itr.x = mn.x;
}
float x1 = p2.x - p1.x;
float x2 = itr.x - p1.x;
itr.y = p1.y + x2 * (p2.y - p1.y) / x1;
itr.z = p1.z + x2 * (p2.z - p1.z) / x1;
if ( (itr.y <= mx.y) &&
(itr.y >= mn.y) &&
(itr.z <= mx.z) &&
(itr.z >= mn.z) )
return true;
}
if (oc1 & (ClipTop | ClipBottom))
{
if (oc1 & ClipTop)
{
if (n)
n->Set(0, 1, 0);
itr.y = mx.y;
}
else
{
if (n)
n->Set(0, -1, 0);
itr.y = mn.y;
}
float y1 = p2.y - p1.y;
float y2 = itr.y - p1.y;
itr.x = p1.x + y2 * (p2.x - p1.x) / y1;
itr.z = p1.z + y2 * (p2.z - p1.z) / y1;
if ( (itr.x <= mx.x) &&
(itr.x >= mn.x) &&
(itr.z <= mx.z) &&
(itr.z >= mn.z) )
return true;
}
if (oc1 & (ClipFront | ClipBack))
{
if (oc1 & ClipBack)
{
if (n)
n->Set(0, 0, 1);
itr.z = mx.z;
}
else
{
if (n)
n->Set(0, 0, -1);
itr.z = mn.z;
}
float z1 = p2.z - p1.z;
float z2 = itr.z - p1.z;
itr.x = p1.x + z2 * (p2.x - p1.x) / z1;
itr.y = p1.y + z2 * (p2.y - p1.y) / z1;
if ( (itr.x <= mx.x) &&
(itr.x >= mn.x) &&
(itr.y <= mx.y) &&
(itr.y >= mn.y) )
return true;
}
return false;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool MinMax::FromMetaTag(Tag &tag)
{
Tag *t;
List <Tag *> ::Iterator i(tag.GetTags().GetRoot());
t = i.ObjectPtr();
if (!t) return false;
mn.FromMetaTag(*t);
++i;
t = i.ObjectPtr();
if (!t) return false;
mx.FromMetaTag(*t);
return true;
}
Tag *MinMax::AsMetaTag()
{
Tag *root = new Tag("MinMax");
if (root)
{
root->AddChild(mn.AsMetaTag("Min"));
root->AddChild(mx.AsMetaTag("Max"));
}
return root;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,549 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include "geometry/curve.h"
#include "sort/sort.h"
using namespace GS;
//------------------------------------------------------------------------------
void Curve::Update(const CurvePoint &p, const Time &t_epsilon)
{
for (uint n = 0; n < points.GetCount(); ++n)
{
CurvePoint *point = points[n];
if ((p.t >= (point->t - t_epsilon)) && (p.t <= (point->t + t_epsilon)))
{
point->v = p.v;
return;
}
}
Insert(p);
}
void Curve::Insert(const CurvePoint &k)
{
int idx = GetPointIndex(k.t);
points.Insert(new CurvePoint(k), (idx == -1) ? points.GetCount() : idx);
}
void Curve::Append(const CurvePoint &k)
{
points.Insert(new CurvePoint(k), points.GetCount());
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Curve::Delete(CurvePoint *k)
{
points.Remove(k);
delete k;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int Curve::GetPointIndex(const Time &t, bool t_greater) const
{
if (points.GetCount() == 0)
return -1;
if (t_greater)
{
for (uint n = 0; n < points.GetCount(); ++n)
if (points[n]->t > t)
return n;
}
else
{
for (int n = points.GetCount() - 1; n >= 0; --n)
if (points[n]->t <= t)
return n;
}
return -1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
TimeRange Curve::GetTimeRange() const
{
return points.GetCount() == 0 ? TimeRange() : TimeRange(points[0]->t, points[points.GetCount() - 1]->t);
}
Range <float> Curve::GetValueRange() const
{
if (points.GetCount() == 0)
return Range <float> ();
Range <float> range(points[0]->v, points[0]->v);
for (uint n = 1; n < points.GetCount(); ++n)
{
range.start = Types::Min(range.start, points[n]->v);
range.end = Types::Max(range.end, points[n]->v);
}
return range;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Curve::Optimize(uint point_count, const CurvePoint *skf, CurvePoint *dkf, float threshold)
{
if (point_count < 3)
return 0;
uint ckf = 0, n;
for (n = 1; n < (point_count - 1); n += 2)
{
float k = (skf[n].t - skf[n - 1].t).toSec() / (skf[n + 1].t - skf[n - 1].t).toSec();
float iv = (skf[n - 1].v * k) + (skf[n + 1].v * (1.f - k));
dkf[ckf++] = skf[n - 1];
if (fabs(skf[n].v - iv) > threshold)
dkf[ckf++] = skf[n];
}
if (n == (point_count - 1))
dkf[ckf++] = skf[point_count - 2];
dkf[ckf++] = skf[point_count - 1];
return point_count - ckf;
}
uint Curve::Optimize(float threshold)
{
if (!points.GetCount())
return 0;
Array <CurvePoint> skf(points.GetCount(), Alloc::Curve), dkf(points.GetCount(), Alloc::Curve);
if (skf.IsNull() || dkf.IsNull())
__ERR__(__LOG__ << "Not enough memory.\n", 0);
// Freeze array.
for (uint n = 0; n < points.GetCount(); ++n)
skf[n] = *points[n];
// Optimize curve.
uint gain = Optimize(points.GetCount(), skf.c_ptr(), dkf.c_ptr(), threshold), out = points.GetCount() - gain;
if (gain)
{
// Send back to curve.
if (!AllocatePoint(out))
__ERR__(__LOG__ << "Failed to reallocate optimized array.\n", 0);
for (uint n = 0; n < points.GetCount(); ++n)
SetPoint(n, dkf[n]);
}
return gain;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Curve::AllocatePoint(uint n)
{
ArrayListDeleteAllPtr(CurvePoint *, points)
while (n--)
if (!points.Add(new CurvePoint))
return false;
return true;
}
void Curve::SetPoint(uint i, const CurvePoint &p) const
{ *points[i] = p; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Curve::Sort()
{
// Make sure there is work to do.
bool need_sorting = false;
for (uint n = 1; n < points.GetCount(); ++n)
if (points[n - 1]->t > points[n]->t)
{
need_sorting = true;
break;
}
if (!need_sorting)
return;
// Sort keys.
uint count = points.GetCount();
Array <GS::Sort<Time, CurvePoint *>::Entry> entries(count);
for (uint n = 0; n < count; ++n)
{
entries[n].v = points[n]->t;
entries[n].o = points[n];
}
GS::Sort<Time, CurvePoint *>::QuickSort(count, entries);
// Drop current array and rewrite ordered one.
points.Clear(false);
for (uint n = 0; n < count; ++n)
points.Add(entries[n].o);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static float range(float v, float lo, float hi, int *i)
{
float r = hi - lo;
if (r == 0.f)
{
if (i)
*i = 0;
return lo;
}
float v2 = v - lo;
if (v2 >= 0.f)
v2 = lo + v2 - r * floor(v2 / r);
else
v2 = hi + v2 - r * ceil(v2 / r);
if (i)
*i = -(int)((v2 - v) / r + (v2 > v ? 0.5f : -0.5f));
return Types::Clamp(v2, lo, hi);
}
static void hermite(float t, float *h1, float *h2, float *h3, float *h4)
{
float t2 = t * t, t3 = t * t2;
*h2 = 3.f * t2 - t3 - t3;
*h1 = 1.f - *h2;
*h4 = t3 - t2;
*h3 = *h4 - t2 + t;
}
static float bezier(float x0, float x1, float x2, float x3, float t)
{
float a, b, c, t2 = t * t, t3 = t * t2;
c = 3.f * (x1 - x0);
b = 3.f * (x2 - x1) - c;
a = x3 - x0 - c - b;
return a * t3 + b * t2 + c * t + x0;
}
static float bez2_time(float x0, float x1, float x2, float x3, float time, float *t0, float *t1)
{
float t = *t0 + (*t1 - *t0) * 0.5f, v = bezier(x0, x1, x2, x3, t);
if ((fabs(*t1 - *t0) > .0001f) && (fabs(time - v) > .0001f))
{
if (v > time)
*t1 = t;
else
*t0 = t;
return bez2_time(x0, x1, x2, x3, time, t0, t1);
}
return t;
}
static float bez2(const CurvePoint *key0, const CurvePoint *key1, float time)
{
float x, y, t, t0 = 0.f, t1 = 1.f;
if (key0->shape == CurvePoint::Shape_Bezier2)
x = key0->t.toSec() + key0->param[2];
else
x = key0->t.toSec() + (key1->t - key0->t).toSec() / 3.f;
t = bez2_time(key0->t.toSec(), x, key1->t.toSec() + key1->param[0], key1->t.toSec(), time, &t0, &t1);
if (key0->shape == CurvePoint::Shape_Bezier2)
y = key0->v + key0->param[3];
else
y = key0->v + key0->param[1] / 3.f;
return bezier(key0->v, y, key1->param[1] + key1->v, key1->v, t);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
float Curve::Outgoing(const CurvePoint *key0, const CurvePoint *key1, const CurvePoint *keyp) const
{
float a, b, d, t, out;
switch (key1->shape)
{
case CurvePoint::Shape_Linear:
d = key1->v - key0->v;
if (keyp)
{
t = (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec();
out = t * ((key0->v - keyp->v) + d);
}
else
out = d;
break;
case CurvePoint::Shape_TCB:
a = (1 - key0->tension)
* (1 + key0->continuity)
* (1 + key0->bias);
b = (1 - key0->tension)
* (1 - key0->continuity)
* (1 - key0->bias);
d = key1->v - key0->v;
if (keyp)
{
t = (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec();
out = t * (a * (key0->v - keyp->v) + b * d);
}
else
out = b * d;
break;
case CurvePoint::Shape_Bezier:
case CurvePoint::Shape_Hermite:
out = key0->param[0];
if (keyp)
out *= (key1->t - key0->t).toSec() / (key1->t - keyp->t).toSec();
break;
case CurvePoint::Shape_Bezier2:
out = key0->param[3] * (key1->t - key0->t).toSec();
if (fabs(key0->param[2]) > 1e-5f)
out /= key0->param[2];
else
out *= 1e5f;
break;
case CurvePoint::Shape_Step:
default:
out = 0;
break;
}
return out;
}
float Curve::Incoming(const CurvePoint *key0, const CurvePoint *key1, const CurvePoint *key2) const
{
float a, b, d, t, in;
switch (key1->shape)
{
case CurvePoint::Shape_Linear:
d = key1->v - key0->v;
if (key2)
{
t = (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec();
in = t * ((key2->v - key1->v) + d);
}
else
in = d;
break;
case CurvePoint::Shape_TCB:
a = (1 - key1->tension)
* (1 - key1->continuity)
* (1 + key1->bias);
b = (1 - key1->tension)
* (1 + key1->continuity)
* (1 - key1->bias);
d = key1->v - key0->v;
if (key2)
{
t = (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec();
in = t * (b * (key2->v - key1->v) + a * d);
}
else
in = a * d;
break;
case CurvePoint::Shape_Bezier:
case CurvePoint::Shape_Hermite:
in = key1->param[0];
if (key2)
in *= (key1->t - key0->t).toSec() / (key2->t - key0->t).toSec();
break;
case CurvePoint::Shape_Bezier2:
in = key1->param[1] * (key1->t - key0->t).toSec();
if (fabs(key1->param[0]) > 1e-5f)
in /= key1->param[0];
else in *= 1e5f;
break;
case CurvePoint::Shape_Step:
default:
in = 0;
break;
}
return in;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Curve::Evaluate(Time t, float *p, LoopMode loop, Time loop_start, Time loop_end) const
{
int point_count = points.GetCount();
if (point_count == 0)
{
*p = 0;
return;
}
if (point_count == 1)
{
*p = points[0]->v;
return;
}
// Loop mode.
CurvePoint *skey = points[0], *ekey = points[point_count - 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;
float offset = 0;
if (t < loop_start)
{
switch (loop)
{
case Reset:
*p = 0.f;
return;
default:
case Constant:
Evaluate(loop_start, p, loop, loop_start, loop_end);
return;
case Repeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL));
break;
case Oscillate:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
if (noff % 2)
t = loop_end + loop_start - t;
break;
case OffsetAndRepeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
offset = noff * (ekey->v - skey->v); // Broken on custom loop point.
break;
}
}
else if (t > loop_end)
{
switch (loop)
{
case Reset:
*p = 0.f;
return;
default:
case Constant:
Evaluate(loop_end, p, loop, loop_start, loop_end);
return;
case Repeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), NULL));
break;
case Oscillate:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
if (noff % 2)
t = loop_end + loop_start - t;
break;
case OffsetAndRepeat:
t.setSec(range(t.toSec(), loop_start.toSec(), loop_end.toSec(), &noff));
offset = noff * (ekey->v - skey->v);
break;
}
}
// Seek to current key.
int ikey0;
#if 1
{
uint lo = 0, hi = points.GetCount() - 1;
forever
{
uint mid = (lo + hi) / 2;
if (points[mid]->t > t)
hi = mid;
else
{
if (lo == mid)
{
ikey0 = lo;
break;
}
else
lo = mid;
}
}
}
#else
ikey0 = 0;
while (((ikey0 + 1) < point_count) && (t > points[ikey0 + 1]->t))
ikey0++;
#endif
CurvePoint *pkey0 = points[ikey0];
if (pkey0 == NULL)
return;
// Sample curve.
CurvePoint *pkeyp = ikey0 > 0 ? points[ikey0 - 1] : NULL;
int ikey1 = ikey0 + 1;
CurvePoint *pkey1 = points[ikey1], *pkey2 = ikey1 < (point_count - 1) ? points[ikey1 + 1] : NULL;
if (t == pkey0->t)
*p = pkey0->v + offset;
else if (t == pkey1->t)
*p = pkey1->v + offset;
else
{
const float k_t = (t - pkey0->t).toSec() / (pkey1->t - pkey0->t).toSec();
switch (pkey0->shape)
{
case CurvePoint::Shape_TCB:
case CurvePoint::Shape_Bezier:
case CurvePoint::Shape_Hermite:
{
float out = Outgoing(pkey0, pkey1, pkeyp), in = Incoming(pkey0, pkey1, pkey2);
float h1, h2, h3, h4;
hermite(k_t, &h1, &h2, &h3, &h4);
*p = h1 * pkey0->v + h2 * pkey1->v + h3 * out + h4 * in + offset;
}
break;
case CurvePoint::Shape_Bezier2:
*p = bez2(pkey0, pkey1, k_t) + offset;
break;
case CurvePoint::Shape_Linear:
*p = pkey0->v + k_t * (pkey1->v - pkey0->v) + offset;
break;
case CurvePoint::Shape_Step:
*p = pkey0->v + offset;
break;
default:
*p = offset;
break;
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Curve::Clear()
{
ArrayListDeleteAllPtr(CurvePoint *, points)
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Curve::~Curve()
{ Clear(); }
//------------------------------------------------------------------------------

View File

@ -0,0 +1,268 @@
/* -----------------------------------------------------------------------------
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 *)&in;
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;
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,309 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include "geometry/frustum.h"
#include "geometry/bounding_box.h"
#include "geometry/sat.h"
#include "shape/shape.h"
#include "math/matrix4.h"
using namespace GS;
//------------------------------------------------------------------------------
void Frustum::SetPerspective(float fov, float znear, float zfar, const Matrix4 *matrix, float h_ar, float v_ar)
{
fov *= 0.5f;
const float hyp = tan(fov);
const float hfov = atan(hyp / h_ar), vfov = atan(hyp / v_ar);
Vector4 n;
const float sinv = sin(vfov);
const float cosv = cos(vfov);
n.Set(0, cosv, -sinv);
plane[Top].Set(NULL, n, matrix);
n.Set(0, -cosv, -sinv);
plane[Bottom].Set(NULL, n, matrix);
const float sinh = sin(hfov);
const float cosh = cos(hfov);
n.Set(-cosh, 0, -sinh);
plane[Left].Set(NULL, n, matrix);
n.Set(cosh, 0, -sinh);
plane[Right].Set(NULL, n, matrix);
Vector4 s;
s.Set(0, 0, znear);
n.Set(0, 0, -1);
plane[Near].Set(&s, n, matrix);
s.Set(0, 0, zfar);
n.Set(0, 0, 1);
plane[Far].Set(&s, n, matrix);
// Model vertices.
Vector4 bvtx[8];
Vector4 *_vtx = matrix ? bvtx : vtx;
// Compute near plane corners.
float k = znear / -cosv;
_vtx[0].y = -sinv * k;
_vtx[0].z = znear;//-cosv * k;
k = znear / cosh;
_vtx[0].x = -sinh * k;
_vtx[0].w = 1;
_vtx[1].Set(-_vtx[0].x, _vtx[0].y, _vtx[0].z);
_vtx[2].Set(-_vtx[0].x, -_vtx[0].y, _vtx[0].z);
_vtx[3].Set(_vtx[0].x, -_vtx[0].y, _vtx[0].z);
// Compute far plane corners.
k = zfar / -cosv;
_vtx[4].y = -sinv * k;
_vtx[4].z = zfar;//-cosv * k;
k = zfar / cosh;
_vtx[4].x = -sinh * k;
_vtx[4].w = 1;
_vtx[5].Set(-_vtx[4].x, _vtx[4].y, _vtx[4].z);
_vtx[6].Set(-_vtx[4].x, -_vtx[4].y, _vtx[4].z);
_vtx[7].Set(_vtx[4].x, -_vtx[4].y, _vtx[4].z);
if (matrix)
matrix->Apply(vtx, bvtx, 8);
}
void Frustum::SetOrthographic(float width, float height, float znear, float zfar, const Matrix4 *matrix, float h_ar, float v_ar)
{
Vector4 s, n;
width *= h_ar;
height *= v_ar;
s.Set(0, height * 0.5f, 0);
n.Set(0, 1, 0);
plane[Top].Set(&s, n, matrix);
s.Set(0, -height * 0.5f, 0);
n.Set(0, -1, 0);
plane[Bottom].Set(&s, n, matrix);
s.Set(-width * 0.5f, 0, 0);
n.Set(-1, 0, 0);
plane[Left].Set(&s, n, matrix);
s.Set(width * 0.5f, 0, 0);
n.Set(1, 0, 0);
plane[Right].Set(&s, n, matrix);
s.Set(0, 0, znear);
n.Set(0, 0, -1);
plane[Near].Set(&s, n, matrix);
s.Set(0, 0, zfar);
n.Set(0, 0, 1);
plane[Far].Set(&s, n, matrix);
// Model vertices.
Vector4 bvtx[8];
Vector4 *_vtx = matrix ? bvtx : vtx;
// Compute near plane corners.
_vtx[0].Set(-width * 0.5f, height * 0.5f, znear);
_vtx[1].Set( width * 0.5f, height * 0.5f, znear);
_vtx[2].Set( width * 0.5f, -height * 0.5f, znear);
_vtx[3].Set(-width * 0.5f, -height * 0.5f, znear);
_vtx[4].Set(-width * 0.5f, height * 0.5f, zfar);
_vtx[5].Set( width * 0.5f, height * 0.5f, zfar);
_vtx[6].Set( width * 0.5f, -height * 0.5f, zfar);
_vtx[7].Set(-width * 0.5f, -height * 0.5f, zfar);
if (matrix)
matrix->Apply(vtx, bvtx, 8);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Frustum::Visibility Frustum::ClassifyShape(const Shape &s, const Matrix4 *m) const
{
Visibility v = Inside;
Matrix3 rm;
if (m)
rm = Matrix3::FromMatrix4(*m).Transposed();
for (uint n = 0; n < 6; ++n)
{
float d, r;
if (m)
{
d = plane[n].DistanceToPlane(s.GetCenter() * m[0]);
r = s.GetSupportDistance(plane[n].GetNormal() * rm);
}
else
{
d = plane[n].DistanceToPlane(s.GetCenter());
r = s.GetSupportDistance(plane[n].GetNormal());
}
if (d > r)
return Outside;
if (d > -r)
v = Clipped;
}
return v;
}
Frustum::Visibility Frustum::ClassifySphere(const Vector4 &p, float r) const
{
Visibility v = Inside;
for (uint n = 0; n < 6; ++n)
{
if (plane[n].DistanceToPlane(p) > r)
return Outside;
if (plane[n].DistanceToPlane(p) > -r)
v = Clipped;
}
return v;
}
Frustum::Visibility Frustum::ClassifySet(uint count, const Vector4 * const GSRESTRICT set, const float offset) const
{
Visibility v = Inside;
for (uint n = 0; n < 6; ++n)
{
uint out = 0;
for (uint i = 0; i < count; ++i)
if (plane[n].DistanceToPlane(set[i]) > offset)
++out;
if (out == count)
return Outside;
if (out > 0)
v = Clipped;
}
return v;
}
//------------------------------------------------------------------------------
#if (__PLATFORM_NINTENDO_WII__ == 0)
//#define FRUSTUM_TEST_USE_SAT
#endif
//--------------------------------------------
#define SAT_TEST(_N_, _U_, _A_, _V_, _B_)\
{\
SAT::Overlap _v = SAT::TestOverlap(_N_, _U_, _A_, _V_, _B_);\
if (_v == SAT::Outside)\
return Outside;\
if (_v == SAT::Clipped)\
v = Clipped;\
}
//--------------------------------------------
//------------------------------------------------------------------------------
Frustum::Visibility Frustum::ClassifyMinMax(const MinMax &mm, const Matrix4 *matrix) const
{
// TODO Please, use AABB half width and implicit interval projection... will you?
Vector4 s[8], d[8], *p;
s[0].Set(mm.mn.x, mm.mn.y, mm.mn.z);
s[1].Set(mm.mx.x, mm.mn.y, mm.mn.z);
s[2].Set(mm.mx.x, mm.mx.y, mm.mn.z);
s[3].Set(mm.mn.x, mm.mx.y, mm.mn.z);
s[4].Set(mm.mn.x, mm.mn.y, mm.mx.z);
s[5].Set(mm.mx.x, mm.mn.y, mm.mx.z);
s[6].Set(mm.mx.x, mm.mx.y, mm.mx.z);
s[7].Set(mm.mn.x, mm.mx.y, mm.mx.z);
if (matrix)
{
matrix->Apply(d, s, 8);
p = d;
}
else
p = s;
#ifndef FRUSTUM_TEST_USE_SAT
// Faster but much coarser test.
return ClassifySet(8, p);
#else
// Frustum/AABB SAT.
Visibility v = Inside;
// Test face/{face/edge} contact.
SAT_TEST(plane[Top].GetNormal(), 8, vtx, 8, p);
SAT_TEST(plane[Bottom].GetNormal(), 8, vtx, 8, p);
SAT_TEST(plane[Left].GetNormal(), 8, vtx, 8, p);
SAT_TEST(plane[Right].GetNormal(), 8, vtx, 8, p);
SAT_TEST(plane[Near].GetNormal(), 8, vtx, 8, p);
SAT_TEST(plane[Far].GetNormal(), 8, vtx, 8, p);
Vector4 _edge[3];
_edge[0] = matrix ? matrix->GetRow(0) : Vector4(1, 0, 0);
SAT_TEST(_edge[0], 8, vtx, 8, p);
_edge[1] = matrix ? matrix->GetRow(1) : Vector4(0, 1, 0);
SAT_TEST(_edge[1], 8, vtx, 8, p);
_edge[2] = matrix ? matrix->GetRow(2) : Vector4(0, 0, 1);
SAT_TEST(_edge[2], 8, vtx, 8, p);
// Test edge/edge contact.
Vector4 edge[6];
for (uint n = 0; n < 4; ++n)
edge[n] = vtx[n + 4] - vtx[n];
edge[4] = vtx[1] - vtx[0];
edge[5] = vtx[3] - vtx[0];
for (uint n = 0; n < 6; ++n)
for (uint m = 0; m < 3; ++m)
{
Vector4 axis = edge[n].Cross(_edge[m]);
if (Math::EqualZero(axis.Len2()))
continue;
SAT_TEST(axis, 8, vtx, 8, p);
}
return v;
#endif
}
Frustum::Visibility Frustum::ClassifyFrustrum(const Frustum &frustum) const
{
#ifndef FRUSTUM_TEST_USE_SAT
// Faster but much coarser test.
return ClassifySet(8, frustum.vtx);
#else
// Frustum/frustum SAT.
Visibility v = Inside;
// Test face/{face/edge} contact.
SAT_TEST(plane[Top].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(plane[Bottom].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(plane[Left].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(plane[Right].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(plane[Far].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(frustum.plane[Top].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(frustum.plane[Bottom].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(frustum.plane[Left].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(frustum.plane[Right].GetNormal(), 8, vtx, 8, frustum.vtx);
SAT_TEST(frustum.plane[Far].GetNormal(), 8, vtx, 8, frustum.vtx);
// Test edge/edge contact.
Vector4 edge[6], _edge[6];
for (uint n = 0; n < 4; ++n)
{
edge[n] = vtx[n + 4] - vtx[n];
_edge[n] = frustum.vtx[n + 4] - frustum.vtx[n];
}
edge[4] = vtx[1] - vtx[0];
edge[5] = vtx[3] - vtx[0];
_edge[4] = frustum.vtx[1] - frustum.vtx[0];
_edge[5] = frustum.vtx[3] - frustum.vtx[0];
for (uint n = 0; n < 6; ++n)
for (uint m = 0; m < 6; ++m)
{
Vector4 axis = edge[n].Cross(_edge[m]);
if (!Math::EqualZero(axis.Len2()))
SAT_TEST(axis, 8, vtx, 8, frustum.vtx);
}
return v;
#endif
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,122 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <cmath>
#include "geometry/geometric_tools.h"
namespace GS {
namespace Geometric {
//------------------------------------------------------------------------------
float TriArea2D(float x0, float y0, float x1, float y1, float x2, float y2)
{ return (x0 - x1) * (y1 - y2) - (x1 - x2) * (y0 - y1); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Barycentric(const Vector4 &a, const Vector4 &b, const Vector4 &c, const Vector4 &p, float &u, float &v, float &w)
{
Vector4 m = (b - a).Cross(c - a);
float nu, nv, ood;
float x = fabs(m.x), y = fabs(m.y), z = fabs(m.z);
if (x >= y && x >= z)
{
nu = TriArea2D(p.y, p.z, b.y, b.z, c.y, c.z);
nv = TriArea2D(p.y, p.z, c.y, c.z, a.y, a.z);
ood = 1.f / m.x;
}
else if (y >= x && y >= z)
{
nu = TriArea2D(p.x, p.z, b.x, b.z, c.x, c.z);
nv = TriArea2D(p.x, p.z, c.x, c.z, a.x, a.z);
ood = 1.f / -m.y;
}
else
{
nu = TriArea2D(p.x, p.y, b.x, b.y, c.x, c.y);
nv = TriArea2D(p.x, p.y, c.x, c.y, a.x, a.y);
ood = 1.f / m.z;
}
u = nu * ood;
v = nv * ood;
w = 1.f - u - v;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool LineIntersectPlane(const Vector4 &a, const Vector4 &v, const Vector4 &n, const Vector4 &p, float &t)
{
float k = v.Dot(n);
if (Math::EqualZero(k))
return false;
t = (p.Dot(n) - a.Dot(n)) / k;
return true;
}
bool LineIntersectSphere(const Vector4 &a, const Vector4 &v, const Vector4 &c, float r, float t[2])
{
Vector4 e = c - a;
float k = e.Dot(v);
float d = r * r - (e.Len2() - k * k);
if (d < 0)
return false;
d = Math::Sqrt(d);
if (t)
{
t[0] = k - d;
t[1] = k + d;
}
return true;
}
float LineClosestPoint(const Vector4 &a, const Vector4 &b, const Vector4 &u, Vector4 *p)
{
Vector4 _u = u - a;
Vector4 _v = b - a;
float t = _u.Dot(_v) / _v.Dot(_v);
if (p)
p[0] = _v * t + a;
return t;
}
bool LineClosestPointToLine(const Vector4 &a, const Vector4 &b, const Vector4 &la, const Vector4 &lb, float t[2])
{
Vector4 u = b - a, v = lb - la;
float ul2 = u.Len2(), vl2 = v.Len2();
float d = u.Dot(v), k = ul2 * vl2 - d * d;
if (fabs(k) < 0.00000001f)
return false;
k = 1.f / k;
float uv = d, du = (la - a).Dot(u), dv = (a - la).Dot(v);
t[0] = (vl2 * du + uv * dv) * k;
t[1] = (uv * du + ul2 * dv) * k;
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
float SegmentClosestPoint(const Vector4 &a, const Vector4 &b, const Vector4 &u, Vector4 *p)
{
Vector4 _u = u - a, _v = b - a;
float t = Types::Clamp(_u.Dot(_v) / _v.Dot(_v));
if (p)
p[0] = _v * t + a;
return t;
}
//------------------------------------------------------------------------------
} // Geometric
} // GS

View File

@ -0,0 +1,46 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "geometry/plane.h"
#include "math/matrix4.h"
using namespace GS;
//------------------------------------------------------------------------------
void Plane::Set(const Vector4 *_p, const Vector4 &_n, const Matrix4 *mtx)
{
if (mtx)
{
if (_p)
mtx->Apply(&p, _p);
else p = mtx->GetRow(3);
mtx->ApplyRotation(&n, &_n);
}
else
{
if (_p)
p = *_p;
else p.Set(0, 0, 0, 1);
n = _n;
}
d = -p.Dot(n);
}
void Plane::Set(const Vector4 _p[3], const Matrix4 *mtx)
{
Vector4 _n = (_p[1] - _p[0]).Cross(_p[2] - _p[0]);
Set(&_p[0], _n, mtx);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Plane::Plane()
{
d = 0;
p.Set();
n.Set();
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,54 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "geometry/rect.h"
#include "metafile/nml.h"
using namespace GS;
//------------------------------------------------------------------------------
template <class T> NML::Tag *Rect<T>::AsMetaTag(const char *id) const
{
NML::Tag *root = new NML::Tag(id ? id : "Rect");
if (root)
{
root->AddChild("SX", sx);
root->AddChild("SY", sy);
root->AddChild("EX", ex);
root->AddChild("EY", ey);
}
return root;
}
template <class T> bool Rect<T>::FromMetaTag(NML::Tag &tag)
{
NML::Tag *t;
List <NML::Tag *> ::Iterator i(tag.GetTags().GetRoot());
t = i.ObjectPtr();
if (!t) return false;
sx = t->GetReal();
++i;
t = i.ObjectPtr();
if (!t) return false;
sy = t->GetReal();
++i;
t = i.ObjectPtr();
if (!t) return false;
ex = t->GetReal();
++i;
t = i.ObjectPtr();
if (!t) return false;
ey = t->GetReal();
++i;
return true;
}
//------------------------------------------------------------------------------