/*---------------------------------------------------------------------------* Project: Horizon File: math_Geometry.h Copyright (C)2009-2010 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 34617 $ *--------------------------------------------------------------------------- */ #ifndef NN_MATH_GEOMETRY_H_ #define NN_MATH_GEOMETRY_H_ #include #include #include namespace nn { namespace math { // Define geometric objects such as lines and surfaces first // Reserve name struct LINE2; struct RAY2; struct SEGMENT2; struct CIRCLE2; struct TRIANGLE2; struct LINE3; struct RAY3; struct SEGMENT3; struct SPHERE; struct TRIANGLE3; struct PLANE; struct CYLINDER; struct CONE; struct AABB; struct CAPSULE; enum IntersectionResult { INTERSECTION_NONE = 0, INTERSECTION_1 = 1, INTERSECTION_2 = 2, INTERSECTION_LINE3_ON_PLANE = 2, INTERSECTION_RAY3_ON_PLANE = INTERSECTION_LINE3_ON_PLANE, INTERSECTION_SEGMENT3_ON_PLANE = INTERSECTION_LINE3_ON_PLANE, INTERSECTION_OUTSIDE = 0, INTERSECTION_INSIDE = 1, INTERSECTION_INTERSECT = 2 }; /* ======================================================================= Class definitions ======================================================================== */ /* ------------------------------------------------------------------------ LINE3: L: P + td Parametric format line (3D). Line heading in direction d from its start point P. It is assumed that d has been normalized during use. ------------------------------------------------------------------------ */ struct LINE3 { public: typedef LINE3 self_type; public: LINE3() {} LINE3(const f32* p, bool isNormalized = false) : P(p), d(p + 3) { if (!isNormalized) Normalize(); } LINE3(const VEC3& Pt, const VEC3& dir, bool isNormalized = false) : P(Pt), d(dir) { if (!isNormalized) Normalize(); } operator f32*() { return &P.x; } operator const f32*() const { return &P.x; } bool operator==(const self_type& rhs) const { return P == rhs.P && d == rhs.d; } bool operator!=(const self_type& rhs) const { return P != rhs.P || d != rhs.d; } // Converts a line segment into a line having the same start point. void Set(const SEGMENT3* S); void Normalize() { (void)VEC3Normalize(&d, &d); } public: VEC3 P; VEC3 d; // Be sure to normalize if substituting directly }; /* ------------------------------------------------------------------------ RAY3 R: P + td (where, t >= 0) Line heading in direction d only from its start point. Line heading in direction d from its start point P. It is assumed that d has been normalized during use. ------------------------------------------------------------------------ */ struct RAY3 { public: typedef RAY3 self_type; public: RAY3() {} RAY3(const f32* p, bool isNormalized = false) : P(p), d(p + 3) { if (!isNormalized) Normalize(); } RAY3(const VEC3& Pt, const VEC3& dir, bool isNormalized = false) : P(Pt), d(dir) { if (!isNormalized) Normalize(); } operator f32*() { return &P.x; } operator const f32*() const { return &P.x; } bool operator==(const self_type& rhs) const { return P == rhs.P && d == rhs.d; } bool operator!=(const self_type& rhs) const { return P != rhs.P || d != rhs.d; } void Normalize() { (void)VEC3Normalize(&d, &d); } public: VEC3 P; VEC3 d; // Be sure to normalize if substituting directly }; /* ------------------------------------------------------------------------ SEGMENT3 S: (1 - t)P0 + tP1 (where, 0 <= t <= 1) This line segment connects P0 and P1. ------------------------------------------------------------------------ */ struct SEGMENT3 { public: typedef SEGMENT3 self_type; public: SEGMENT3() {} explicit SEGMENT3(const f32* p) : P0(p), P1(p + 3) {} SEGMENT3(const VEC3& pt0, const VEC3& pt1) : P0(pt0), P1(pt1) {} operator f32*() { return &P0.x; } operator const f32*() const { return &P0.x; } bool operator==(const self_type& rhs) const { return P0 == rhs.P0 && P1 == rhs.P1; } bool operator!=(const self_type& rhs) const { return P0 != rhs.P0 || P1 == rhs.P1; } public: VEC3 P0; VEC3 P1; }; inline void LINE3::Set(const SEGMENT3* S) { P = S->P0; VEC3Sub(&d, &S->P1, &S->P0); Normalize(); } /* ------------------------------------------------------------------------ SPHERE S: |P - C| <= r This sphere takes C as the center and has a radius of r. ------------------------------------------------------------------------ */ struct SPHERE { public: typedef SPHERE self_type; public: SPHERE() {} explicit SPHERE(const f32* p) : C(p), r(*(p + 3)) {} SPHERE(const VEC3& center, f32 radius) : C(center), r(radius) {} operator f32*() { return &C.x; } operator const f32*() const { return &C.x; } bool operator==(const self_type& rhs) const { return C == rhs.C && r == rhs.r; } bool operator!=(const self_type& rhs) const { return C != rhs.C || r != rhs.r; } // Set a sphere that includes a collection of points. void Set(const VEC3* arrayPoint, unsigned int numPoints); public: VEC3 C; f32 r; }; /* ------------------------------------------------------------------------ PLANE (N.x)x + (N.y)y + (N.z)z + d = 0 The shadow function representation of the plane is used as a parameter. Normal vector, N, must be normalized. ------------------------------------------------------------------------ */ struct PLANE { public: typedef PLANE self_type; public: PLANE() {} PLANE(const f32* p, bool isNormalized = false) : N(p), d(*(p + 3)) { if (!isNormalized) Normalize(); } PLANE(f32 A, f32 B, f32 C, f32 D, bool isNormalized = false) : N(A, B, C), d(D) { if (!isNormalized) Normalize(); } PLANE(const VEC3& P0, const VEC3& P1, const VEC3& P2) { Set(&P0, &P1, &P2); } operator f32*() { return &N.x; } operator const f32*() const { return &N.x; } bool operator==(const self_type& rhs) const { return N == rhs.N && d == rhs.d; } bool operator!=(const self_type& rhs) const { return N != rhs.N || d != rhs.d; } // P is positive if it points in the normal direction of the plane; otherwise, it is negative. f32 Test(const VEC3& P) const { return d + VEC3Dot(&N, &P); } void Normalize() { f32 r = FrSqrt(VEC3SquareLen(&N)); (void)VEC3Scale(&N, &N, r); d *= r; } void Set(const VEC3* P0, const VEC3* P1, const VEC3* P2); public: VEC3 N; // Be sure to normalize if substituting directly f32 d; }; /* ------------------------------------------------------------------------ CAPSULE The capsule is defined as the distance between two line segments. ------------------------------------------------------------------------ */ struct CAPSULE { public: typedef CAPSULE self_type; public: CAPSULE() {} explicit CAPSULE(const f32* p) : S(p), r(*(p + 6)) {} CAPSULE(const SEGMENT3& S_, f32 r_) : S(S_), r(r_) {} CAPSULE(const VEC3& P0, const VEC3& P1, f32 r_) : S(P0, P1), r(r_) {} operator f32*() { return &S.P0.x; } operator const f32*() const { return &S.P0.x; } bool operator==(const self_type& rhs) const { return S == rhs.S && r == rhs.r; } bool operator!=(const self_type& rhs) const { return S != rhs.S || r != rhs.r; } public: SEGMENT3 S; f32 r; }; /* ------------------------------------------------------------------------ AABB This box is aligned with the x, y, and z axes. This box is defined using the two points Pmin and Pmax. Each of the coordinates of Pmin must be smaller than the coordinates of Pmax. ------------------------------------------------------------------------ */ struct AABB { public: typedef AABB self_type; public: AABB() {} AABB(const f32* p, bool isNormalized = false) : Pmin(p), Pmax(p + 3) { if (!isNormalized) Normalize(); } AABB(const VEC3& min, const VEC3& max, bool isNormalized = false) : Pmin(min), Pmax(max) { if (!isNormalized) Normalize(); } operator f32*() { return &Pmin.x; } operator const f32*() const { return &Pmin.x; } bool operator==(const self_type& rhs) const { return Pmin == rhs.Pmin && Pmax == rhs.Pmax; } bool operator!=(const self_type& rhs) const { return Pmin != rhs.Pmin || Pmax != rhs.Pmax; } void Set(const VEC3* arrayPoint, unsigned int numPoints); void Set(const AABB* box, const MTX34* M); void Normalize(); public: VEC3 Pmin; VEC3 Pmax; }; /* ------------------------------------------------------------------------ CYLINDER This object is interpreted as a cylinder having a radius of r and a height of z from the start point. Determination of intersection with lines and/or planes must be performed after coordinate conversion. ------------------------------------------------------------------------ */ struct CYLINDER { public: typedef CYLINDER self_type; public: CYLINDER() {} explicit CYLINDER(const f32* p) : r(*p), h(*(p + 1)) {} CYLINDER(f32 radius, f32 height) : r(radius), h(height) {} public: f32 r; f32 h; }; /* ------------------------------------------------------------------------ CONE This object is interpreted as a cone having a radius of r and a height of h from the start point only on the Z axis. Determination of intersection with lines and/or planes must be performed after coordinate conversion. ------------------------------------------------------------------------ */ struct CONE { public: typedef CONE self_type; public: CONE() {} explicit CONE(const f32* p) : r(*p), h(*(p + 1)) {} CONE(f32 radius, f32 height) : r(radius), h(height) {} public: f32 r; f32 h; }; /* ------------------------------------------------------------------------ FRUSTUM Define a frustum primarily used for culling ------------------------------------------------------------------------ */ class FRUSTUM { public: typedef FRUSTUM self_type; public: //--------------------------------------------------------------------------- // //--------------------------------------------------------------------------- FRUSTUM() {} //--------------------------------------------------------------------------- // // // // // // // //--------------------------------------------------------------------------- FRUSTUM(f32 fovyRad, f32 aspect, f32 n, f32 f, const MTX34& camera) { Set(fovyRad, aspect, n, f, camera); } //--------------------------------------------------------------------------- // // // // // // // // // //--------------------------------------------------------------------------- FRUSTUM(f32 top, f32 bottom, f32 left, f32 right, f32 n, f32 f, const MTX34& camera) { Set(top, bottom, left, right, n, f, camera); } private: MTX34 cam; /* Data members for view coordinates */ PLANE leftPlane; PLANE rightPlane; PLANE topPlane; PLANE bottomPlane; f32 znear; f32 zfar; /* Data members for world coordinates */ AABB box; // Use in a rough determination using AABB that contains the frustum PLANE planes[6]; // In order of left, right, near, far, up, and down (from Optimized View Frustum Culling Algorithm) public: //--------------------------------------------------------------------------- // // // // // // // // // //--------------------------------------------------------------------------- void Set(f32 top, f32 bottom, f32 left, f32 right, f32 n, f32 f, const MTX34& camera); //--------------------------------------------------------------------------- // // // // // // // //--------------------------------------------------------------------------- void Set(f32 fovyRad, f32 aspect, f32 n, f32 f, const MTX34& camera) { f32 tanRad = TanRad(0.5f * fovyRad); f32 ny = tanRad * n; f32 nx = ny * aspect; Set(ny, -ny, -nx, nx, n, f, camera); } public: // SPHERE is in world coordinates bool IntersectSphere(const SPHERE* S) const; // AABB is in world coordinates bool IntersectAABB(const AABB* B) const; // AABB is in world coordinates IntersectionResult IntersectAABB_Ex(const AABB* B) const; }; // // Distance between 3D geometric objects // // Points f32 DistSqPoint3ToLine3(const VEC3* P, const LINE3* L, f32* t); f32 DistSqPoint3ToRay3(const VEC3* P, const RAY3* R, f32* t); f32 DistSqPoint3ToSegment3(const VEC3* P, const SEGMENT3* S, f32* t); f32 DistSqPoint3ToPlane(const VEC3* P, const PLANE* J, VEC3* Q); f32 DistSqSphereToPlane(const SPHERE* S, const PLANE* J); f32 DistSqPoint3ToPolyline3(const VEC3* P, const VEC3* vertices, unsigned int nVertices); f32 DistSqPoint3ToAABB(const VEC3* P, const AABB* B, VEC3* q); // Lines, rays, and line segments f32 DistSqLine3ToLine3(const LINE3* L0, const LINE3* L1, f32* s, f32* t); f32 DistSqSegment3ToSegment3(const SEGMENT3* S0, const SEGMENT3* S1, f32* s, f32* t); f32 DistSqLine3ToRay3(const LINE3* L, const RAY3* R, f32* s, f32* t); f32 DistSqLine3ToSegment3(const LINE3* L0, const SEGMENT3* S, f32* s, f32* t); f32 DistSqRay3ToRay3(const RAY3* R0, const RAY3* R1, f32* s, f32* t); f32 DistSqRay3ToSegment3(const RAY3* R0, const SEGMENT3* S, f32* s, f32* t); // // Intersection of 3D geometric objects // IntersectionResult IntersectionLine3Plane(const LINE3* L, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionRay3Plane(const RAY3* R, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionSegment3Plane(const SEGMENT3* S, const PLANE* J, f32* t, VEC3* I); IntersectionResult IntersectionLine3Sphere(const LINE3* L, const SPHERE* sphere, f32* t0, f32* t1); IntersectionResult IntersectionRay3Sphere(const RAY3* R, const SPHERE* sphere, f32* t0, f32* t1); bool IntersectionRay3Sphere(const RAY3* R, const SPHERE* sphere); IntersectionResult IntersectionSegment3Sphere(const SEGMENT3* S, const SPHERE* sphere, f32* t0, f32* t1); bool IntersectionRay3AABB(const RAY3* R, const AABB* box, f32* t); bool IntersectionAABB(const AABB* a, const AABB* b); bool IntersectionSphereAABB(const SPHERE* sphere, const AABB* aabb); bool IntersectionSphere(const SPHERE* s0, const SPHERE* s1); bool IntersectionPlaneAABB(const PLANE* J, const AABB* B); bool IntersectionCapsule(const CAPSULE* C0, const CAPSULE* C1); bool IntersectionRay3Capsule(const RAY3* R, const CAPSULE* C); bool IntersectionLine3Capsule(const LINE3* L, const CAPSULE* C); bool IntersectionPlaneCapsule(const PLANE* J, const CAPSULE* C); inline bool IntersectionSphereFrustum(const SPHERE* S, const FRUSTUM* F) { return F->IntersectSphere(S); } inline bool IntersectionAABBFrustum(const AABB* B, const FRUSTUM* F) { return F->IntersectAABB(B); } inline IntersectionResult IntersectionAABBFrustumEx(const AABB* B, const FRUSTUM* F) { return F->IntersectAABB_Ex(B); } // // Merge 3D geometry // SPHERE* MergeSphere(SPHERE* s2, const SPHERE* s0, const SPHERE* s1); AABB* MergeAABB(AABB* a2, const AABB* a0, const AABB* a1); }} // nn::math #endif