commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
342
include/framework/geometry/bounding_box.cpp
Normal file
342
include/framework/geometry/bounding_box.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
549
include/framework/geometry/curve.cpp
Normal file
549
include/framework/geometry/curve.cpp
Normal 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(); }
|
||||
//------------------------------------------------------------------------------
|
||||
268
include/framework/geometry/curve_nml.cpp
Normal file
268
include/framework/geometry/curve_nml.cpp
Normal 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 *)∈
|
||||
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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
309
include/framework/geometry/frustum.cpp
Normal file
309
include/framework/geometry/frustum.cpp
Normal 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
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
122
include/framework/geometry/geometric_tools.cpp
Normal file
122
include/framework/geometry/geometric_tools.cpp
Normal 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
|
||||
46
include/framework/geometry/plane.cpp
Normal file
46
include/framework/geometry/plane.cpp
Normal 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();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
54
include/framework/geometry/rect.cpp
Normal file
54
include/framework/geometry/rect.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user