/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #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 ::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 ::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; } //------------------------------------------------------------------------------