diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/stan_hull | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/general/stan_hull')
| -rw-r--r-- | APEX_1.4/shared/general/stan_hull/include/StanHull.h | 186 | ||||
| -rw-r--r-- | APEX_1.4/shared/general/stan_hull/include/StanHullConfig.h | 21 | ||||
| -rw-r--r-- | APEX_1.4/shared/general/stan_hull/src/StanHull.cpp | 3653 |
3 files changed, 3860 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/stan_hull/include/StanHull.h b/APEX_1.4/shared/general/stan_hull/include/StanHull.h new file mode 100644 index 00000000..2ecea618 --- /dev/null +++ b/APEX_1.4/shared/general/stan_hull/include/StanHull.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef STAN_HULL_H + +#define STAN_HULL_H + +/*---------------------------------------------------------------------- + Copyright (c) 2004 Open Dynamics Framework Group + www.physicstools.org + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided + that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + Neither the name of the Open Dynamics Framework Group nor the names of its contributors may + be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-----------------------------------------------------------------------*/ + +#include "StanHullConfig.h" + +namespace nvidia +{ + namespace stanhull + { + +class HullResult +{ +public: + HullResult(void) + { + mPolygons = true; + mNumOutputVertices = 0; + mOutputVertices = NULL; + mNumFaces = 0; + mNumIndices = 0; + mIndices = NULL; + mFaces = NULL; + } + bool mPolygons; // true if indices represents polygons, false indices are triangles + uint32_t mNumOutputVertices; // number of vertices in the output hull + float *mOutputVertices; // array of vertices, 3 floats each x,y,z + uint32_t mNumFaces; // the number of faces produced + uint32_t mNumIndices; // the total number of indices + uint32_t *mIndices; // pointer to indices. + uint8_t *mFaces; // Number of points in each polygon face +}; + +enum HullFlag +{ + QF_TRIANGLES = (1<<0), // report results as triangles, not polygons. + QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices. + QF_SKIN_WIDTH = (1<<2), // extrude hull based on this skin width + QF_DEFAULT = 0 +}; + + +class HullDesc +{ +public: + HullDesc(void) + { + mFlags = QF_DEFAULT; + mVcount = 0; + mVertices = 0; + mVertexStride = 0; + mNormalEpsilon = 0.001f; + mMaxVertices = 4096; // maximum number of points to be considered for a convex hull. + mSkinWidth = 0.01f; // default is one centimeter + }; + + HullDesc(uint32_t flags, + uint32_t vcount, + const float *vertices, + uint32_t stride) + { + mFlags = flags; + mVcount = vcount; + mVertices = vertices; + mVertexStride = stride; + mNormalEpsilon = 0.001f; + mMaxVertices = 4096; + mSkinWidth = 0.01f; // default is one centimeter + } + + bool HasHullFlag(uint32_t flags) const + { + if ( mFlags & flags ) return true; + return false; + } + + void SetHullFlag(uint32_t flags) + { + mFlags|=flags; + } + + void ClearHullFlag(uint32_t flags) + { + mFlags&=~flags; + } + + uint32_t mFlags; // flags to use when generating the convex hull. + uint32_t mVcount; // number of vertices in the input point cloud + const float *mVertices; // the array of vertices. + uint32_t mVertexStride; // the stride of each vertex, in bytes. + float mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on. + float mSkinWidth; + uint32_t mMaxVertices; // maximum number of vertices to be considered for the hull! +}; + +enum HullError +{ + QE_OK, // success! + QE_FAIL, // failed. + QE_NOT_READY, +}; + +// This class is used when converting a convex hull into a triangle mesh. +class ConvexHullVertex +{ +public: + float mPos[3]; + float mNormal[3]; + float mTexel[2]; +}; + +// A virtual interface to receive the triangles from the convex hull. +class ConvexHullTriangleInterface +{ +public: + virtual void ConvexHullTriangle(const ConvexHullVertex &v1,const ConvexHullVertex &v2,const ConvexHullVertex &v3) = 0; +}; + + +class HullLibrary +{ +public: + + HullError CreateConvexHull(const HullDesc &desc, // describes the input request + HullResult &result); // contains the resulst + + HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it. + + HullError CreateTriangleMesh(HullResult &answer,ConvexHullTriangleInterface *iface); +private: + float ComputeNormal(float *n,const float *A,const float *B,const float *C); + void AddConvexTriangle(ConvexHullTriangleInterface *callback,const float *p1,const float *p2,const float *p3); + + void BringOutYourDead(const float *verts,uint32_t vcount, float *overts,uint32_t &ocount,uint32_t *indices,uint32_t indexcount); + + bool CleanupVertices(uint32_t svcount, + const float *svertices, + uint32_t stride, + uint32_t &vcount, // output number of vertices + float *vertices, // location to store the results. + float normalepsilon, + float *scale); +}; + +}; // end of namespace +}; + +#endif diff --git a/APEX_1.4/shared/general/stan_hull/include/StanHullConfig.h b/APEX_1.4/shared/general/stan_hull/include/StanHullConfig.h new file mode 100644 index 00000000..ada76e65 --- /dev/null +++ b/APEX_1.4/shared/general/stan_hull/include/StanHullConfig.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef STAN_HULL_CONFIG_H + +#define STAN_HULL_CONFIG_H + +#include "PxSimpleTypes.h" +#include "PxAssert.h" +#include "PsUserAllocated.h" + + +#endif diff --git a/APEX_1.4/shared/general/stan_hull/src/StanHull.cpp b/APEX_1.4/shared/general/stan_hull/src/StanHull.cpp new file mode 100644 index 00000000..749e8feb --- /dev/null +++ b/APEX_1.4/shared/general/stan_hull/src/StanHull.cpp @@ -0,0 +1,3653 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +/*---------------------------------------------------------------------- + Copyright (c) 2004 Open Dynamics Framework Group + www.physicstools.org + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided + that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + Neither the name of the Open Dynamics Framework Group nor the names of its contributors may + be used to endorse or promote products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-----------------------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <float.h> + + +#include <stdarg.h> +#include <setjmp.h> + +#include "StanHull.h" +#include "ApexUsingNamespace.h" + +using namespace nvidia; +using namespace nvidia; + +namespace nvidia +{ + namespace stanhull + { + +//***************************************************** +//*** DARRAY.H +//***************************************************** + +template <class Type> class ArrayRet; +template <class Type> class StanArray +{ + public: + StanArray(int32_t s=0); + StanArray(StanArray<Type> &array); + StanArray(ArrayRet<Type> &array); + ~StanArray(); + void allocate(int32_t s); + void SetSize(int32_t s); + void Pack(); + Type& Add(Type); + void AddUnique(Type); + int32_t Contains(Type); + void Insert(Type,int32_t); + int32_t IndexOf(Type); + void Remove(Type); + void DelIndex(int32_t i); + Type * element; + int32_t count; + int32_t array_size; + const Type &operator[](int32_t i) const + { + PX_ASSERT(i>=0 && i<count); + return element[i]; + } + Type &operator[](int32_t i) + { + PX_ASSERT(i>=0 && i<count); + return element[i]; + } + + Type &Pop() + { + PX_ASSERT(count); + count--; + return element[count]; + } + StanArray<Type> &operator=(StanArray<Type> &array); + StanArray<Type> &operator=(ArrayRet<Type> &array); + // operator ArrayRet<Type> &() { return *(ArrayRet<Type> *)this;} // this worked but i suspect could be dangerous +}; + +template <class Type> class ArrayRet:public StanArray<Type> +{ +}; + +template <class Type> StanArray<Type>::StanArray(int32_t s) +{ + count=0; + array_size = 0; + element = NULL; + if(s) + { + allocate(s); + } +} + + +template <class Type> StanArray<Type>::StanArray(StanArray<Type> &array) +{ + count=0; + array_size = 0; + element = NULL; + for(int32_t i=0;i<array.count;i++) + { + Add(array[i]); + } +} + + +template <class Type> StanArray<Type>::StanArray(ArrayRet<Type> &array) +{ + *this = array; +} +template <class Type> StanArray<Type> &StanArray<Type>::operator=(ArrayRet<Type> &array) +{ + count=array.count; + array_size = array.array_size; + element = array.element; + array.element=NULL; + array.count=0; + array.array_size=0; + return *this; +} + + +template <class Type> StanArray<Type> &StanArray<Type>::operator=(StanArray<Type> &array) +{ + count=0; + for(int32_t i=0;i<array.count;i++) + { + Add(array[i]); + } + return *this; +} + +template <class Type> StanArray<Type>::~StanArray() +{ + if (element != NULL) + { + PX_FREE(element); + } + count=0;array_size=0;element=NULL; +} + +template <class Type> void StanArray<Type>::allocate(int32_t s) +{ + PX_ASSERT(s>0); + PX_ASSERT(s>=count); + Type *old = element; + array_size =s; + element = (Type *) PX_ALLOC( sizeof(Type)*array_size, PX_DEBUG_EXP("StanArray") ); + PX_ASSERT(element); + for(int32_t i=0;i<count;i++) + { + element[i]=old[i]; + } + if(old) + { + PX_FREE(old); + } +} + +template <class Type> void StanArray<Type>::SetSize(int32_t s) +{ + if(s==0) + { + if(element) + { + PX_FREE(element); + element = NULL; + } + array_size = s; + } + else + { + allocate(s); + } + count=s; +} + +template <class Type> void StanArray<Type>::Pack() +{ + allocate(count); +} + +template <class Type> Type& StanArray<Type>::Add(Type t) +{ + PX_ASSERT(count<=array_size); + if(count==array_size) + { + allocate((array_size)?array_size *2:16); + } + element[count++] = t; + return element[count-1]; +} + +template <class Type> int32_t StanArray<Type>::Contains(Type t) +{ + int32_t i; + int32_t found=0; + for(i=0;i<count;i++) + { + if(element[i] == t) found++; + } + return found; +} + +template <class Type> void StanArray<Type>::AddUnique(Type t) +{ + if(!Contains(t)) + { + Add(t); + } +} + + +template <class Type> void StanArray<Type>::DelIndex(int32_t i) +{ + PX_ASSERT(i<count); + count--; + while(i<count) + { + element[i] = element[i+1]; + i++; + } +} + +template <class Type> void StanArray<Type>::Remove(Type t) +{ + int32_t i; + for(i=0;i<count;i++) + { + if(element[i] == t) + { + break; + } + } + PX_ASSERT(i<count); // assert object t is in the array. + DelIndex(i); + for(i=0;i<count;i++) + { + PX_ASSERT(element[i] != t); + } +} + +template <class Type> void StanArray<Type>::Insert(Type t,int32_t k) +{ + int32_t i=count; + Add(t); // to allocate space + while(i>k) + { + element[i]=element[i-1]; + i--; + } + PX_ASSERT(i==k); + element[k]=t; +} + + +template <class Type> int32_t StanArray<Type>::IndexOf(Type t) +{ + int32_t i; + for(i=0;i<count;i++) + { + if(element[i] == t) + { + return i; + } + } + PX_ALWAYS_ASSERT(); + return -1; +} + +//**************************************************** +//** VECMATH.H +//**************************************************** +#define PI (3.1415926535897932384626433832795f) + +#define DEG2RAD (PI / 180.0f) +#define RAD2DEG (180.0f / PI) +#define SQRT_OF_2 (1.4142135f) +#define OFFSET(Class,Member) (((char*) (&(((Class*)NULL)-> Member )))- ((char*)NULL)) + +int32_t argmin(float a[],int32_t n); +float sqr(float a); +float clampf(float a) ; +float Round(float a,float precision); +float Interpolate(const float &f0,const float &f1,float alpha) ; + +template <class T> +void Swap(T &a,T &b) +{ + T tmp = a; + a=b; + b=tmp; +} + + + +template <class T> +T Max(const T &a,const T &b) +{ + return (a>b)?a:b; +} + +template <class T> +T Min(const T &a,const T &b) +{ + return (a<b)?a:b; +} + +//---------------------------------- + +class int3 : public UserAllocated +{ +public: + int32_t x,y,z; + int3(){}; + int3(int32_t _x,int32_t _y, int32_t _z) + { + x=_x; + y=_y; + z=_z; + } + const int32_t& operator[](int32_t i) const + { + return (&x)[i]; + } + int32_t& operator[](int32_t i) + { + return (&x)[i]; + } +}; + + +//-------- 2D -------- + +class float2 : public UserAllocated +{ +public: + float x,y; + float2(){x=0;y=0;}; + float2(float _x,float _y) + { + x=_x; + y=_y; + } + float& operator[](int32_t i) + { + PX_ASSERT(i>=0&&i<2); + return ((float*)this)[i]; + } + const float& operator[](int32_t i) const + { + PX_ASSERT(i>=0&&i<2); + return ((float*)this)[i]; + } +}; + +inline float2 operator-( const float2& a, const float2& b ) +{ + return float2(a.x-b.x,a.y-b.y); +} + +inline float2 operator+( const float2& a, const float2& b ) +{ + return float2(a.x+b.x,a.y+b.y); +} + +//--------- 3D --------- + +class float3 : public UserAllocated // 3D +{ + public: + float x,y,z; + float3() + { + x=0; + y=0; + z=0; + }; + float3(float _x,float _y,float _z) + { + x=_x; + y=_y; + z=_z; + }; + //operator float *() { return &x;}; + float& operator[](int32_t i) + { + PX_ASSERT(i>=0&&i<3); + return ((float*)this)[i]; + } + const float& operator[](int32_t i) const + { + PX_ASSERT(i>=0&&i<3); + return ((float*)this)[i]; + } +}; + + +float3& operator+=( float3 &a, const float3& b ); +float3& operator-=( float3 &a ,const float3& b ); +float3& operator*=( float3 &v ,const float s ); +float3& operator/=( float3 &v, const float s ); + +float magnitude( const float3& v ); +float3 normalize( const float3& v ); +float3 safenormalize(const float3 &v); +float3 vabs(const float3 &v); +float3 operator+( const float3& a, const float3& b ); +float3 operator-( const float3& a, const float3& b ); +float3 operator-( const float3& v ); +float3 operator*( const float3& v, const float s ); +float3 operator*( const float s, const float3& v ); +float3 operator/( const float3& v, const float s ); +inline int32_t operator==( const float3 &a, const float3 &b ) +{ + return (a.x==b.x && a.y==b.y && a.z==b.z); +} +inline int32_t operator!=( const float3 &a, const float3 &b ) +{ + return (a.x!=b.x || a.y!=b.y || a.z!=b.z); +} +// due to ambiguity and inconsistent standards ther are no overloaded operators for mult such as va*vb. +float dot( const float3& a, const float3& b ); +float3 cmul( const float3 &a, const float3 &b); +float3 cross( const float3& a, const float3& b ); +float3 Interpolate(const float3 &v0,const float3 &v1,float alpha); +float3 Round(const float3& a,float precision); +float3 VectorMax(const float3 &a, const float3 &b); +float3 VectorMin(const float3 &a, const float3 &b); + + + +class float3x3 : public UserAllocated +{ + public: + float3 x,y,z; // the 3 rows of the Matrix + float3x3(){} + float3x3(float xx,float xy,float xz,float yx,float yy,float yz,float zx,float zy,float zz):x(xx,xy,xz),y(yx,yy,yz),z(zx,zy,zz){} + float3x3(float3 _x,float3 _y,float3 _z):x(_x),y(_y),z(_z){} + float3& operator[](int32_t i) + { + PX_ASSERT(i>=0&&i<3); + return (&x)[i]; + } + const float3& operator[](int32_t i) const + { + PX_ASSERT(i>=0&&i<3); + return (&x)[i]; + } + float& operator()(int32_t r, int32_t c) + { + PX_ASSERT(r>=0&&r<3&&c>=0&&c<3); + return ((&x)[r])[c]; + } + const float& operator()(int32_t r, int32_t c) const + { + PX_ASSERT(r>=0&&r<3&&c>=0&&c<3); + return ((&x)[r])[c]; + } +}; +float3x3 Transpose( const float3x3& m ); +float3 operator*( const float3& v , const float3x3& m ); +float3 operator*( const float3x3& m , const float3& v ); +float3x3 operator*( const float3x3& m , const float& s ); +float3x3 operator*( const float3x3& ma, const float3x3& mb ); +float3x3 operator/( const float3x3& a, const float& s ) ; +float3x3 operator+( const float3x3& a, const float3x3& b ); +float3x3 operator-( const float3x3& a, const float3x3& b ); +float3x3 &operator+=( float3x3& a, const float3x3& b ); +float3x3 &operator-=( float3x3& a, const float3x3& b ); +float3x3 &operator*=( float3x3& a, const float& s ); +float Determinant(const float3x3& m ); +float3x3 Inverse(const float3x3& a); // its just 3x3 so we simply do that cofactor method + + +//-------- 4D Math -------- + +class float4 : public UserAllocated +{ +public: + float x,y,z,w; + float4(){x=0;y=0;z=0;w=0;}; + float4(float _x,float _y,float _z,float _w){x=_x;y=_y;z=_z;w=_w;} + float4(const float3 &v,float _w){x=v.x;y=v.y;z=v.z;w=_w;} + //operator float *() { return &x;}; + float& operator[](int32_t i) {PX_ASSERT(i>=0&&i<4);return ((float*)this)[i];} + const float& operator[](int32_t i) const {PX_ASSERT(i>=0&&i<4);return ((float*)this)[i];} + const float3& xyz() const { return *((float3*)this);} + float3& xyz() { return *((float3*)this);} +}; + + +struct D3DXMATRIX; + +class float4x4 : public UserAllocated +{ + public: + float4 x,y,z,w; // the 4 rows + float4x4(){} + float4x4(const float4 &_x, const float4 &_y, const float4 &_z, const float4 &_w):x(_x),y(_y),z(_z),w(_w){} + float4x4(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33 ) + :x(m00,m01,m02,m03),y(m10,m11,m12,m13),z(m20,m21,m22,m23),w(m30,m31,m32,m33){} + float& operator()(int32_t r, int32_t c) {PX_ASSERT(r>=0&&r<4&&c>=0&&c<4);return ((&x)[r])[c];} + const float& operator()(int32_t r, int32_t c) const {PX_ASSERT(r>=0&&r<4&&c>=0&&c<4);return ((&x)[r])[c];} + operator float* () {return &x.x;} + operator const float* () const {return &x.x;} + operator struct D3DXMATRIX* () { return (struct D3DXMATRIX*) this;} + operator const struct D3DXMATRIX* () const { return (struct D3DXMATRIX*) this;} +}; + + +int32_t operator==( const float4 &a, const float4 &b ); +float4 Homogenize(const float3 &v3,const float &w=1.0f); // Turns a 3D float3 4D vector4 by appending w +float4 cmul( const float4 &a, const float4 &b); +float4 operator*( const float4 &v, float s); +float4 operator*( float s, const float4 &v); +float4 operator+( const float4 &a, const float4 &b); +float4 operator-( const float4 &a, const float4 &b); +float4x4 operator*( const float4x4& a, const float4x4& b ); +float4 operator*( const float4& v, const float4x4& m ); +float4x4 Inverse(const float4x4 &m); +float4x4 MatrixRigidInverse(const float4x4 &m); +float4x4 MatrixTranspose(const float4x4 &m); +float4x4 MatrixPerspectiveFov(float fovy, float Aspect, float zn, float zf ); +float4x4 MatrixTranslation(const float3 &t); +float4x4 MatrixRotationZ(const float angle_radians); +float4x4 MatrixLookAt(const float3& eye, const float3& at, const float3& up); +int32_t operator==( const float4x4 &a, const float4x4 &b ); + + +//-------- Quaternion ------------ + +class Quaternion :public float4 +{ + public: + Quaternion() { x = y = z = 0.0f; w = 1.0f; } + Quaternion( float3 v, float t ) { v = normalize(v); w = cosf(t/2.0f); v = v*sinf(t/2.0f); x = v.x; y = v.y; z = v.z; } + Quaternion(float _x, float _y, float _z, float _w){x=_x;y=_y;z=_z;w=_w;} + float angle() const { return acosf(w)*2.0f; } + float3 axis() const { float3 a(x,y,z); if(fabsf(angle())<0.0000001f) return float3(1,0,0); return a*(1/sinf(angle()/2.0f)); } + float3 xdir() const { return float3( 1-2*(y*y+z*z), 2*(x*y+w*z), 2*(x*z-w*y) ); } + float3 ydir() const { return float3( 2*(x*y-w*z),1-2*(x*x+z*z), 2*(y*z+w*x) ); } + float3 zdir() const { return float3( 2*(x*z+w*y), 2*(y*z-w*x),1-2*(x*x+y*y) ); } + float3x3 getmatrix() const { return float3x3( xdir(), ydir(), zdir() ); } + operator float3x3() { return getmatrix(); } + void Normalize(); +}; + +Quaternion& operator*=(Quaternion& a, float s ); +Quaternion operator*( const Quaternion& a, float s ); +Quaternion operator*( const Quaternion& a, const Quaternion& b); +Quaternion operator+( const Quaternion& a, const Quaternion& b ); +Quaternion normalize( Quaternion a ); +float dot( const Quaternion &a, const Quaternion &b ); +float3 operator*( const Quaternion& q, const float3& v ); +float3 operator*( const float3& v, const Quaternion& q ); +Quaternion slerp( Quaternion a, const Quaternion& b, float interp ); +Quaternion Interpolate(const Quaternion &q0,const Quaternion &q1,float alpha); +Quaternion RotationArc(float3 v0, float3 v1 ); // returns quat q where q*v0=v1 +Quaternion Inverse(const Quaternion &q); +float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v); + + +//------ Euler Angle ----- + +Quaternion YawPitchRoll( float yaw, float pitch, float roll ); +float Yaw( const Quaternion& q ); +float Pitch( const Quaternion& q ); +float Roll( Quaternion q ); +float Yaw( const float3& v ); +float Pitch( const float3& v ); + + +//------- Plane ---------- + +class Plane +{ + public: + float3 normal; + float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 + Plane(const float3 &n,float d):normal(n),dist(d){} + Plane():normal(),dist(0){} + void Transform(const float3 &position, const Quaternion &orientation); +}; + +inline Plane PlaneFlip(const Plane &plane){return Plane(-plane.normal,-plane.dist);} +inline int32_t operator==( const Plane &a, const Plane &b ) { return (a.normal==b.normal && a.dist==b.dist); } +inline int32_t coplanar( const Plane &a, const Plane &b ) { return (a==b || a==PlaneFlip(b)); } + + +//--------- Utility Functions ------ + +float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1); +float3 PlaneProject(const Plane &plane, const float3 &point); +float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a); // projects a onto infinite line p0p1 +float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a); +float3 ThreePlaneIntersection(const Plane &p0,const Plane &p1, const Plane &p2); +int32_t PolyHit(const float3 *vert,const int32_t n,const float3 &v0, const float3 &v1, float3 *impact=NULL, float3 *normal=NULL); +int32_t BoxInside(const float3 &p,const float3 &bmin, const float3 &bmax) ; +int32_t BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax, float3 *impact); +float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint=NULL, float3 *vpoint=NULL); +float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2); +float3 NormalOf(const float3 *vert, const int32_t n); +Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir0, const float3 &dir1); + + + + +//***************************************************** +// ** VECMATH.CPP +//***************************************************** + + +float sqr(float a) {return a*a;} +float clampf(float a) {return Min(1.0f,Max(0.0f,a));} + + +float Round(float a,float precision) +{ + return floorf(0.5f+a/precision)*precision; +} + + +float Interpolate(const float &f0,const float &f1,float alpha) +{ + return f0*(1-alpha) + f1*alpha; +} + + +int32_t argmin(float a[],int32_t n) +{ + int32_t r=0; + for(int32_t i=1;i<n;i++) + { + if(a[i]<a[r]) + { + r = i; + } + } + return r; +} + + + +//------------ float3 (3D) -------------- + + + +float3 operator+( const float3& a, const float3& b ) +{ + return float3(a.x+b.x, a.y+b.y, a.z+b.z); +} + + +float3 operator-( const float3& a, const float3& b ) +{ + return float3( a.x-b.x, a.y-b.y, a.z-b.z ); +} + + +float3 operator-( const float3& v ) +{ + return float3( -v.x, -v.y, -v.z ); +} + + +float3 operator*( const float3& v, float s ) +{ + return float3( v.x*s, v.y*s, v.z*s ); +} + + +float3 operator*( float s, const float3& v ) +{ + return float3( v.x*s, v.y*s, v.z*s ); +} + + +float3 operator/( const float3& v, float s ) +{ + return v*(1.0f/s); +} + +float dot( const float3& a, const float3& b ) +{ + return a.x*b.x + a.y*b.y + a.z*b.z; +} + +float3 cmul( const float3 &v1, const float3 &v2) +{ + return float3(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z); +} + + +float3 cross( const float3& a, const float3& b ) +{ + return float3( a.y*b.z - a.z*b.y, + a.z*b.x - a.x*b.z, + a.x*b.y - a.y*b.x ); +} + + + + +float3& operator+=( float3& a , const float3& b ) +{ + a.x += b.x; + a.y += b.y; + a.z += b.z; + return a; +} + + +float3& operator-=( float3& a , const float3& b ) +{ + a.x -= b.x; + a.y -= b.y; + a.z -= b.z; + return a; +} + + +float3& operator*=(float3& v , float s ) +{ + v.x *= s; + v.y *= s; + v.z *= s; + return v; +} + + +float3& operator/=(float3& v , float s ) +{ + float sinv = 1.0f / s; + v.x *= sinv; + v.y *= sinv; + v.z *= sinv; + return v; +} + +float3 vabs(const float3 &v) +{ + return float3(fabsf(v.x),fabsf(v.y),fabsf(v.z)); +} + + +float magnitude( const float3& v ) +{ + return sqrtf(sqr(v.x) + sqr( v.y)+ sqr(v.z)); +} + +float3 normalize( const float3 &v ) +{ + // this routine, normalize, is ok, provided magnitude works!! + float d=magnitude(v); + if (d==0) + { + printf("Cant normalize ZERO vector\n"); + PX_ALWAYS_ASSERT();// yes this could go here + d=0.1f; + } + d = 1/d; + return float3(v.x*d,v.y*d,v.z*d); +} + +float3 safenormalize(const float3 &v) +{ + if(magnitude(v)<=0.0f) + { + return float3(1,0,0); + } + return normalize(v); +} + +float3 Round(const float3 &a,float precision) +{ + return float3(Round(a.x,precision),Round(a.y,precision),Round(a.z,precision)); +} + + +float3 Interpolate(const float3 &v0,const float3 &v1,float alpha) +{ + return v0*(1-alpha) + v1*alpha; +} + +float3 VectorMin(const float3 &a,const float3 &b) +{ + return float3(Min(a.x,b.x),Min(a.y,b.y),Min(a.z,b.z)); +} +float3 VectorMax(const float3 &a,const float3 &b) +{ + return float3(Max(a.x,b.x),Max(a.y,b.y),Max(a.z,b.z)); +} + +// the statement v1*v2 is ambiguous since there are 3 types +// of vector multiplication +// - componantwise (for example combining colors) +// - dot product +// - cross product +// Therefore we never declare/implement this function. +// So we will never see: float3 operator*(float3 a,float3 b) + + + + +//------------ float3x3 --------------- +float Determinant(const float3x3 &m) +{ + return m.x.x*m.y.y*m.z.z + m.y.x*m.z.y*m.x.z + m.z.x*m.x.y*m.y.z + -m.x.x*m.z.y*m.y.z - m.y.x*m.x.y*m.z.z - m.z.x*m.y.y*m.x.z ; +} + +float3x3 Inverse(const float3x3 &a) +{ + float3x3 b; + float d=Determinant(a); + PX_ASSERT(d!=0); + for(int32_t i=0;i<3;i++) + { + for(int32_t j=0;j<3;j++) + { + int32_t i1=(i+1)%3; + int32_t i2=(i+2)%3; + int32_t j1=(j+1)%3; + int32_t j2=(j+2)%3; + // reverse indexs i&j to take transpose + b[j][i] = (a[i1][j1]*a[i2][j2]-a[i1][j2]*a[i2][j1])/d; + } + } + // Matrix check=a*b; // Matrix 'check' should be the identity (or close to it) + return b; +} + + +float3x3 Transpose( const float3x3& m ) +{ + return float3x3( float3(m.x.x,m.y.x,m.z.x), + float3(m.x.y,m.y.y,m.z.y), + float3(m.x.z,m.y.z,m.z.z)); +} + + +float3 operator*(const float3& v , const float3x3 &m ) { + return float3((m.x.x*v.x + m.y.x*v.y + m.z.x*v.z), + (m.x.y*v.x + m.y.y*v.y + m.z.y*v.z), + (m.x.z*v.x + m.y.z*v.y + m.z.z*v.z)); +} +float3 operator*(const float3x3 &m,const float3& v ) { + return float3(dot(m.x,v),dot(m.y,v),dot(m.z,v)); +} + + +float3x3 operator*( const float3x3& a, const float3x3& b ) +{ + return float3x3(a.x*b,a.y*b,a.z*b); +} + +float3x3 operator*( const float3x3& a, const float& s ) +{ + return float3x3(a.x*s, a.y*s ,a.z*s); +} +float3x3 operator/( const float3x3& a, const float& s ) +{ + float t=1/s; + return float3x3(a.x*t, a.y*t ,a.z*t); +} +float3x3 operator+( const float3x3& a, const float3x3& b ) +{ + return float3x3(a.x+b.x, a.y+b.y, a.z+b.z); +} +float3x3 operator-( const float3x3& a, const float3x3& b ) +{ + return float3x3(a.x-b.x, a.y-b.y, a.z-b.z); +} +float3x3 &operator+=( float3x3& a, const float3x3& b ) +{ + a.x+=b.x; + a.y+=b.y; + a.z+=b.z; + return a; +} +float3x3 &operator-=( float3x3& a, const float3x3& b ) +{ + a.x-=b.x; + a.y-=b.y; + a.z-=b.z; + return a; +} +float3x3 &operator*=( float3x3& a, const float& s ) +{ + a.x*=s; + a.y*=s; + a.z*=s; + return a; +} + + + +float3 ThreePlaneIntersection(const Plane &p0,const Plane &p1, const Plane &p2){ + float3x3 mp =Transpose(float3x3(p0.normal,p1.normal,p2.normal)); + float3x3 mi = Inverse(mp); + float3 b(p0.dist,p1.dist,p2.dist); + return -b * mi; +} + + +//--------------- 4D ---------------- + +float4 operator*( const float4& v, const float4x4& m ) +{ + return v.x*m.x + v.y*m.y + v.z*m.z + v.w*m.w; // yes this actually works +} + +int32_t operator==( const float4 &a, const float4 &b ) +{ + return (a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w); +} + + +// Dont implement m*v for now, since that might confuse us +// All our transforms are based on multiplying the "row" vector on the left +//float4 operator*(const float4x4& m , const float4& v ) +//{ +// return float4(dot(v,m.x),dot(v,m.y),dot(v,m.z),dot(v,m.w)); +//} + + + +float4 cmul( const float4 &a, const float4 &b) +{ + return float4(a.x*b.x,a.y*b.y,a.z*b.z,a.w*b.w); +} + + +float4 operator*( const float4 &v, float s) +{ + return float4(v.x*s,v.y*s,v.z*s,v.w*s); +} + + +float4 operator*( float s, const float4 &v) +{ + return float4(v.x*s,v.y*s,v.z*s,v.w*s); +} + + +float4 operator+( const float4 &a, const float4 &b) +{ + return float4(a.x+b.x,a.y+b.y,a.z+b.z,a.w+b.w); +} + + + +float4 operator-( const float4 &a, const float4 &b) +{ + return float4(a.x-b.x,a.y-b.y,a.z-b.z,a.w-b.w); +} + + +float4 Homogenize(const float3 &v3,const float &w) +{ + return float4(v3.x,v3.y,v3.z,w); +} + + + +float4x4 operator*( const float4x4& a, const float4x4& b ) +{ + return float4x4(a.x*b,a.y*b,a.z*b,a.w*b); +} + +float4x4 MatrixTranspose(const float4x4 &m) +{ + return float4x4( + m.x.x, m.y.x, m.z.x, m.w.x, + m.x.y, m.y.y, m.z.y, m.w.y, + m.x.z, m.y.z, m.z.z, m.w.z, + m.x.w, m.y.w, m.z.w, m.w.w ); +} + +float4x4 MatrixRigidInverse(const float4x4 &m) +{ + float4x4 trans_inverse = MatrixTranslation(-m.w.xyz()); + float4x4 rot = m; + rot.w = float4(0,0,0,1); + return trans_inverse * MatrixTranspose(rot); +} + + +float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf ) +{ + float h = 1.0f/tanf(fovy/2.0f); // view space height + float w = h / aspect ; // view space width + return float4x4( + w, 0, 0 , 0, + 0, h, 0 , 0, + 0, 0, zf/(zn-zf) , -1, + 0, 0, zn*zf/(zn-zf) , 0 ); +} + + + +float4x4 MatrixLookAt(const float3& eye, const float3& at, const float3& up) +{ + float4x4 m; + m.w.w = 1.0f; + m.w.xyz() = eye; + m.z.xyz() = normalize(eye-at); + m.x.xyz() = normalize(cross(up,m.z.xyz())); + m.y.xyz() = cross(m.z.xyz(),m.x.xyz()); + return MatrixRigidInverse(m); +} + + +float4x4 MatrixTranslation(const float3 &t) +{ + return float4x4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + t.x,t.y,t.z,1 ); +} + + +float4x4 MatrixRotationZ(const float angle_radians) +{ + float s = sinf(angle_radians); + float c = cosf(angle_radians); + return float4x4( + c, s, 0, 0, + -s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 ); +} + + + +int32_t operator==( const float4x4 &a, const float4x4 &b ) +{ + return (a.x==b.x && a.y==b.y && a.z==b.z && a.w==b.w); +} + + +float4x4 Inverse(const float4x4 &m) +{ + float4x4 d; + float *dst = &d.x.x; + float tmp[12]; /* temp array for pairs */ + float src[16]; /* array of transpose source matrix */ + float det; /* determinant */ + /* transpose matrix */ + for ( int32_t i = 0; i < 4; i++) { + src[i] = m(i,0) ; + src[i + 4] = m(i,1); + src[i + 8] = m(i,2); + src[i + 12] = m(i,3); + } + /* calculate pairs for first 8 elements (cofactors) */ + tmp[0] = src[10] * src[15]; + tmp[1] = src[11] * src[14]; + tmp[2] = src[9] * src[15]; + tmp[3] = src[11] * src[13]; + tmp[4] = src[9] * src[14]; + tmp[5] = src[10] * src[13]; + tmp[6] = src[8] * src[15]; + tmp[7] = src[11] * src[12]; + tmp[8] = src[8] * src[14]; + tmp[9] = src[10] * src[12]; + tmp[10] = src[8] * src[13]; + tmp[11] = src[9] * src[12]; + /* calculate first 8 elements (cofactors) */ + dst[0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; + dst[0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; + dst[1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; + dst[1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; + dst[2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; + dst[2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; + dst[3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; + dst[3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; + dst[4] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; + dst[4] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; + dst[5] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; + dst[5] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; + dst[6] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; + dst[6] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; + dst[7] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; + dst[7] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; + /* calculate pairs for second 8 elements (cofactors) */ + tmp[0] = src[2]*src[7]; + tmp[1] = src[3]*src[6]; + tmp[2] = src[1]*src[7]; + tmp[3] = src[3]*src[5]; + tmp[4] = src[1]*src[6]; + tmp[5] = src[2]*src[5]; + tmp[6] = src[0]*src[7]; + tmp[7] = src[3]*src[4]; + tmp[8] = src[0]*src[6]; + tmp[9] = src[2]*src[4]; + tmp[10] = src[0]*src[5]; + tmp[11] = src[1]*src[4]; + /* calculate second 8 elements (cofactors) */ + dst[8] = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15]; + dst[8] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15]; + dst[9] = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15]; + dst[9] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15]; + dst[10] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15]; + dst[10]-= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15]; + dst[11] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14]; + dst[11]-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14]; + dst[12] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9]; + dst[12]-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10]; + dst[13] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10]; + dst[13]-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8]; + dst[14] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8]; + dst[14]-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9]; + dst[15] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9]; + dst[15]-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8]; + /* calculate determinant */ + det=src[0]*dst[0]+src[1]*dst[1]+src[2]*dst[2]+src[3]*dst[3]; + /* calculate matrix inverse */ + det = 1/det; + for ( int32_t j = 0; j < 16; j++) + dst[j] *= det; + return d; +} + + +//--------- Quaternion -------------- + +Quaternion operator*( const Quaternion& a, const Quaternion& b ) +{ + Quaternion c; + c.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z; + c.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y; + c.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x; + c.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w; + return c; +} + + +Quaternion operator*( const Quaternion& a, float b ) +{ + return Quaternion(a.x*b, a.y*b, a.z*b ,a.w*b); +} + +Quaternion Inverse(const Quaternion &q) +{ + return Quaternion(-q.x,-q.y,-q.z,q.w); +} + +Quaternion& operator*=( Quaternion& q, const float s ) +{ + q.x *= s; + q.y *= s; + q.z *= s; + q.w *= s; + return q; +} +void Quaternion::Normalize() +{ + float m = sqrtf(sqr(w)+sqr(x)+sqr(y)+sqr(z)); + if(m<0.000000001f) { + w=1.0f; + x=y=z=0.0f; + return; + } + (*this) *= (1.0f/m); +} + +float3 operator*( const Quaternion& q, const float3& v ) +{ + // The following is equivalent to: + //return (q.getmatrix() * v); + float qx2 = q.x*q.x; + float qy2 = q.y*q.y; + float qz2 = q.z*q.z; + + float qxqy = q.x*q.y; + float qxqz = q.x*q.z; + float qxqw = q.x*q.w; + float qyqz = q.y*q.z; + float qyqw = q.y*q.w; + float qzqw = q.z*q.w; + return float3( + (1-2*(qy2+qz2))*v.x + (2*(qxqy-qzqw))*v.y + (2*(qxqz+qyqw))*v.z , + (2*(qxqy+qzqw))*v.x + (1-2*(qx2+qz2))*v.y + (2*(qyqz-qxqw))*v.z , + (2*(qxqz-qyqw))*v.x + (2*(qyqz+qxqw))*v.y + (1-2*(qx2+qy2))*v.z ); +} + +Quaternion operator+( const Quaternion& a, const Quaternion& b ) +{ + return Quaternion(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); +} + +float dot( const Quaternion &a,const Quaternion &b ) +{ + return (a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z); +} + +Quaternion normalize( Quaternion a ) +{ + float m = sqrtf(sqr(a.w)+sqr(a.x)+sqr(a.y)+sqr(a.z)); + if(m<0.000000001) + { + a.w=1; + a.x=a.y=a.z=0; + return a; + } + return a * (1/m); +} + +Quaternion slerp( Quaternion a, const Quaternion& b, float interp ) +{ + if(dot(a,b) <0.0) + { + a.w=-a.w; + a.x=-a.x; + a.y=-a.y; + a.z=-a.z; + } + float d = dot(a,b); + if(d>=1.0) { + return a; + } + float theta = acosf(d); + if(theta==0.0f) { return(a);} + return a*(sinf(theta-interp*theta)/sinf(theta)) + b*(sinf(interp*theta)/sinf(theta)); +} + + +Quaternion Interpolate(const Quaternion &q0,const Quaternion &q1,float alpha) { + return slerp(q0,q1,alpha); +} + + +Quaternion YawPitchRoll( float yaw, float pitch, float roll ) +{ + roll *= DEG2RAD; + yaw *= DEG2RAD; + pitch *= DEG2RAD; + return Quaternion(float3(0.0f,0.0f,1.0f),yaw)*Quaternion(float3(1.0f,0.0f,0.0f),pitch)*Quaternion(float3(0.0f,1.0f,0.0f),roll); +} + +float Yaw( const Quaternion& q ) +{ + static float3 v; + v=q.ydir(); + return (v.y==0.0&&v.x==0.0) ? 0.0f: atan2f(-v.x,v.y)*RAD2DEG; +} + +float Pitch( const Quaternion& q ) +{ + static float3 v; + v=q.ydir(); + return atan2f(v.z,sqrtf(sqr(v.x)+sqr(v.y)))*RAD2DEG; +} + +float Roll( Quaternion q ) +{ + q = Quaternion(float3(0.0f,0.0f,1.0f),-Yaw(q)*DEG2RAD) *q; + q = Quaternion(float3(1.0f,0.0f,0.0f),-Pitch(q)*DEG2RAD) *q; + return atan2f(-q.xdir().z,q.xdir().x)*RAD2DEG; +} + +float Yaw( const float3& v ) +{ + return (v.y==0.0&&v.x==0.0) ? 0.0f: atan2f(-v.x,v.y)*RAD2DEG; +} + +float Pitch( const float3& v ) +{ + return atan2f(v.z,sqrtf(sqr(v.x)+sqr(v.y)))*RAD2DEG; +} + + +//------------- Plane -------------- + + +void Plane::Transform(const float3 &position, const Quaternion &orientation) { + // Transforms the plane to the space defined by the + // given position/orientation. + static float3 newnormal; + static float3 origin; + + newnormal = Inverse(orientation)*normal; + origin = Inverse(orientation)*(-normal*dist - position); + + normal = newnormal; + dist = -dot(newnormal, origin); +} + + + + +//--------- utility functions ------------- + +// RotationArc() +// Given two vectors v0 and v1 this function +// returns quaternion q where q*v0==v1. +// Routine taken from game programming gems. +Quaternion RotationArc(float3 v0,float3 v1){ + static Quaternion q; + v0 = normalize(v0); // Comment these two lines out if you know its not needed. + v1 = normalize(v1); // If vector is already unit length then why do it again? + float3 c = cross(v0,v1); + float d = dot(v0,v1); + if(d<=-1.0f) { return Quaternion(1,0,0,0);} // 180 about x axis + float s = sqrtf((1+d)*2); + q.x = c.x / s; + q.y = c.y / s; + q.z = c.z / s; + q.w = s /2.0f; + return q; +} + + +float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v) +{ + // builds a 4x4 transformation matrix based on orientation q and translation v + float qx2 = q.x*q.x; + float qy2 = q.y*q.y; + float qz2 = q.z*q.z; + + float qxqy = q.x*q.y; + float qxqz = q.x*q.z; + float qxqw = q.x*q.w; + float qyqz = q.y*q.z; + float qyqw = q.y*q.w; + float qzqw = q.z*q.w; + + return float4x4( + 1-2*(qy2+qz2), + 2*(qxqy+qzqw), + 2*(qxqz-qyqw), + 0 , + 2*(qxqy-qzqw), + 1-2*(qx2+qz2), + 2*(qyqz+qxqw), + 0 , + 2*(qxqz+qyqw), + 2*(qyqz-qxqw), + 1-2*(qx2+qy2), + 0 , + v.x , + v.y , + v.z , + 1.0f ); +} + + +float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1) +{ + // returns the point where the line p0-p1 intersects the plane n&d + static float3 dif; + dif = p1-p0; + float dn= dot(plane.normal,dif); + float t = -(plane.dist+dot(plane.normal,p0) )/dn; + return p0 + (dif*t); +} + +float3 PlaneProject(const Plane &plane, const float3 &point) +{ + return point - plane.normal * (dot(point,plane.normal)+plane.dist); +} + +float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a) +{ + float3 w; + w = p1-p0; + float t= dot(w,(a-p0)) / (sqr(w.x)+sqr(w.y)+sqr(w.z)); + return p0+ w*t; +} + + +float LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a) +{ + float3 w; + w = p1-p0; + float t= dot(w,(a-p0)) / (sqr(w.x)+sqr(w.y)+sqr(w.z)); + return t; +} + + + +float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2) +{ + // return the normal of the triangle + // inscribed by v0, v1, and v2 + float3 cp=cross(v1-v0,v2-v1); + float m=magnitude(cp); + if(m==0) return float3(1,0,0); + return cp*(1.0f/m); +} + + + +int32_t BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax) +{ + return (p.x >= bmin.x && p.x <=bmax.x && + p.y >= bmin.y && p.y <=bmax.y && + p.z >= bmin.z && p.z <=bmax.z ); +} + + +int32_t BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax,float3 *impact) +{ + if(BoxInside(v0,bmin,bmax)) + { + *impact=v0; + return 1; + } + if(v0.x<=bmin.x && v1.x>=bmin.x) + { + float a = (bmin.x-v0.x)/(v1.x-v0.x); + //v.x = bmin.x; + float vy = (1-a) *v0.y + a*v1.y; + float vz = (1-a) *v0.z + a*v1.z; + if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) + { + impact->x = bmin.x; + impact->y = vy; + impact->z = vz; + return 1; + } + } + else if(v0.x >= bmax.x && v1.x <= bmax.x) + { + float a = (bmax.x-v0.x)/(v1.x-v0.x); + //v.x = bmax.x; + float vy = (1-a) *v0.y + a*v1.y; + float vz = (1-a) *v0.z + a*v1.z; + if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) + { + impact->x = bmax.x; + impact->y = vy; + impact->z = vz; + return 1; + } + } + if(v0.y<=bmin.y && v1.y>=bmin.y) + { + float a = (bmin.y-v0.y)/(v1.y-v0.y); + float vx = (1-a) *v0.x + a*v1.x; + //v.y = bmin.y; + float vz = (1-a) *v0.z + a*v1.z; + if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) + { + impact->x = vx; + impact->y = bmin.y; + impact->z = vz; + return 1; + } + } + else if(v0.y >= bmax.y && v1.y <= bmax.y) + { + float a = (bmax.y-v0.y)/(v1.y-v0.y); + float vx = (1-a) *v0.x + a*v1.x; + // vy = bmax.y; + float vz = (1-a) *v0.z + a*v1.z; + if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) + { + impact->x = vx; + impact->y = bmax.y; + impact->z = vz; + return 1; + } + } + if(v0.z<=bmin.z && v1.z>=bmin.z) + { + float a = (bmin.z-v0.z)/(v1.z-v0.z); + float vx = (1-a) *v0.x + a*v1.x; + float vy = (1-a) *v0.y + a*v1.y; + // v.z = bmin.z; + if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) + { + impact->x = vx; + impact->y = vy; + impact->z = bmin.z; + return 1; + } + } + else if(v0.z >= bmax.z && v1.z <= bmax.z) + { + float a = (bmax.z-v0.z)/(v1.z-v0.z); + float vx = (1-a) *v0.x + a*v1.x; + float vy = (1-a) *v0.y + a*v1.y; + // v.z = bmax.z; + if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) + { + impact->x = vx; + impact->y = vy; + impact->z = bmax.z; + return 1; + } + } + return 0; +} + + +float DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint, float3 *vpoint) +{ + static float3 cp; + cp = normalize(cross(udir,vdir)); + + float distu = -dot(cp,ustart); + float distv = -dot(cp,vstart); + float dist = (float)fabs(distu-distv); + if(upoint) + { + Plane plane; + plane.normal = normalize(cross(vdir,cp)); + plane.dist = -dot(plane.normal,vstart); + *upoint = PlaneLineIntersection(plane,ustart,ustart+udir); + } + if(vpoint) + { + Plane plane; + plane.normal = normalize(cross(udir,cp)); + plane.dist = -dot(plane.normal,ustart); + *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir); + } + return dist; +} + + +Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir1, const float3 &dir2) +{ + // routine taken from game programming gems. + // Implement track ball functionality to spin stuf on the screen + // cop center of projection + // cor center of rotation + // dir1 old mouse direction + // dir2 new mouse direction + // pretend there is a sphere around cor. Then find the points + // where dir1 and dir2 intersect that sphere. Find the + // rotation that takes the first point to the second. + float m; + // compute plane + float3 nrml = cor - cop; + float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop + nrml = normalize(nrml); + float dist = -dot(nrml,cor); + float3 u= PlaneLineIntersection(Plane(nrml,dist),cop,cop+dir1); + u=u-cor; + u=u*fudgefactor; + m= magnitude(u); + if(m>1) + { + u/=m; + } + else + { + u=u - (nrml * sqrtf(1-m*m)); + } + float3 v= PlaneLineIntersection(Plane(nrml,dist),cop,cop+dir2); + v=v-cor; + v=v*fudgefactor; + m= magnitude(v); + if(m>1) + { + v/=m; + } + else + { + v=v - (nrml * sqrtf(1-m*m)); + } + return RotationArc(u,v); +} + + +int32_t countpolyhit=0; +int32_t PolyHit(const float3 *vert, const int32_t n, const float3 &v0, const float3 &v1, float3 *impact, float3 *normal) +{ + countpolyhit++; + int32_t i; + float3 nrml(0,0,0); + for(i=0;i<n;i++) + { + int32_t i1=(i+1)%n; + int32_t i2=(i+2)%n; + nrml = nrml + cross(vert[i1]-vert[i],vert[i2]-vert[i1]); + } + + float m = magnitude(nrml); + if(m==0.0) + { + return 0; + } + nrml = nrml * (1.0f/m); + float dist = -dot(nrml,vert[0]); + float d0,d1; + if((d0=dot(v0,nrml)+dist) <0 || (d1=dot(v1,nrml)+dist) >0) + { + return 0; + } + + static float3 the_point; + // By using the cached plane distances d0 and d1 + // we can optimize the following: + // the_point = planelineintersection(nrml,dist,v0,v1); + float a = d0/(d0-d1); + the_point = v0*(1-a) + v1*a; + + + int32_t inside=1; + for(int32_t j=0;inside && j<n;j++) + { + // let inside = 0 if outside + float3 pp1,pp2,side; + pp1 = vert[j] ; + pp2 = vert[(j+1)%n]; + side = cross((pp2-pp1),(the_point-pp1)); + inside = (dot(nrml,side) >= 0.0); + } + if(inside) + { + if(normal){*normal=nrml;} + if(impact){*impact=the_point;} + } + return inside; +} + +//**************************************************** +// HULL.H source code goes here +//**************************************************** +class PHullResult +{ +public: + + PHullResult(void) + { + mVcount = 0; + mIndexCount = 0; + mFaceCount = 0; + mVertices = NULL; + mIndices = NULL; + mFaces = NULL; + } + + uint32_t mVcount; + uint32_t mIndexCount; + uint32_t mFaceCount; + float *mVertices; + uint32_t *mIndices; + uint8_t *mFaces; // contains the number of points in each face, if this is generating polygons as output. +}; + +bool ComputeHull(uint32_t vcount,const float *vertices,PHullResult &result,uint32_t maxverts,float inflate,bool useTriangles); +void ReleaseHull(PHullResult &result); + +//***************************************************** +// HULL.cpp source code goes here +//***************************************************** + + +#define REAL3 float3 +#define REAL float + +#define COPLANAR (0) +#define UNDER (1) +#define OVER (2) +#define SPLIT (OVER|UNDER) +#define PAPERWIDTH (0.001f) +#define VOLUME_EPSILON (1e-20f) + +float planetestepsilon = PAPERWIDTH; + +class ConvexH : public UserAllocated +{ + public: + class HalfEdge + { + public: + short ea; // the other half of the edge (index into edges list) + uint8_t v; // the vertex at the start of this edge (index into vertices list) + uint8_t p; // the facet on which this edge lies (index into facets list) + HalfEdge(){} + HalfEdge(short _ea,uint8_t _v, uint8_t _p):ea(_ea),v(_v),p(_p){} + }; + StanArray<REAL3> vertices; + StanArray<HalfEdge> edges; + StanArray<Plane> facets; + ConvexH(int32_t vertices_size,int32_t edges_size,int32_t facets_size); +}; + +typedef ConvexH::HalfEdge HalfEdge; + +ConvexH::ConvexH(int32_t vertices_size,int32_t edges_size,int32_t facets_size) + :vertices(vertices_size) + ,edges(edges_size) + ,facets(facets_size) +{ + vertices.count=vertices_size; + edges.count = edges_size; + facets.count = facets_size; +} + +ConvexH *ConvexHDup(ConvexH *src) +{ + ConvexH *dst = PX_NEW(ConvexH)(src->vertices.count,src->edges.count,src->facets.count); + + memcpy(dst->vertices.element,src->vertices.element,sizeof(float3)*src->vertices.count); + memcpy(dst->edges.element,src->edges.element,sizeof(HalfEdge)*src->edges.count); + memcpy(dst->facets.element,src->facets.element,sizeof(Plane)*src->facets.count); + return dst; +} + + +int32_t PlaneTest(const Plane &p, const REAL3 &v) { + REAL a = dot(v,p.normal)+p.dist; + int32_t flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR); + return flag; +} + +int32_t SplitTest(ConvexH &convex,const Plane &plane) { + int32_t flag=0; + for(int32_t i=0;i<convex.vertices.count;i++) { + flag |= PlaneTest(plane,convex.vertices[i]); + } + return flag; +} + +class VertFlag +{ +public: + uint8_t planetest; + uint8_t junk; + uint8_t undermap; + uint8_t overmap; +}; +class EdgeFlag +{ +public: + uint8_t planetest; + uint8_t fixes; + short undermap; + short overmap; +}; +class PlaneFlag +{ +public: + uint8_t undermap; + uint8_t overmap; +}; +class Coplanar{ +public: + unsigned short ea; + uint8_t v0; + uint8_t v1; +}; + +int32_t AssertIntact(ConvexH &convex) +{ + int32_t i; + int32_t estart=0; + for(i=0;i<convex.edges.count;i++) + { + if(convex.edges[estart].p!= convex.edges[i].p) + { + estart=i; + } + int32_t inext = i+1; + if(inext>= convex.edges.count || convex.edges[inext].p != convex.edges[i].p) + { + inext = estart; + } + PX_ASSERT(convex.edges[inext].p == convex.edges[i].p); + int32_t nb = convex.edges[i].ea; + PX_ASSERT(nb!=255); + if(nb==255 || nb==-1) return 0; + PX_ASSERT(nb!=-1); + PX_ASSERT(i== convex.edges[nb].ea); + } + for(i=0;i<convex.edges.count;i++) + { + PX_ASSERT(COPLANAR==PlaneTest(convex.facets[convex.edges[i].p],convex.vertices[convex.edges[i].v])); + if(COPLANAR!=PlaneTest(convex.facets[convex.edges[i].p],convex.vertices[convex.edges[i].v])) return 0; + if(convex.edges[estart].p!= convex.edges[i].p) + { + estart=i; + } + int32_t i1 = i+1; + if(i1>= convex.edges.count || convex.edges[i1].p != convex.edges[i].p) + { + i1 = estart; + } + int32_t i2 = i1+1; + if(i2>= convex.edges.count || convex.edges[i2].p != convex.edges[i].p) + { + i2 = estart; + } + if(i==i2) continue; // i sliced tangent to an edge and created 2 meaningless edges + REAL3 localnormal = TriNormal(convex.vertices[convex.edges[i ].v], + convex.vertices[convex.edges[i1].v], + convex.vertices[convex.edges[i2].v]); + //PX_ASSERT(dot(localnormal,convex.facets[convex.edges[i].p].normal)>0);//Commented out on Stan Melax' advice + if(dot(localnormal,convex.facets[convex.edges[i].p].normal)<=0) + { + return 0; + } + } + return 1; +} + +ConvexH *ConvexHCrop(ConvexH &convex,const Plane &slice) +{ + int32_t i; + int32_t vertcountunder=0; + int32_t vertcountover =0; + static StanArray<int32_t> vertscoplanar; // existing vertex members of convex that are coplanar + vertscoplanar.count=0; + static StanArray<int32_t> edgesplit; // existing edges that members of convex that cross the splitplane + edgesplit.count=0; + + PX_ASSERT(convex.edges.count<480); + + EdgeFlag edgeflag[512]; + VertFlag vertflag[256]; + PlaneFlag planeflag[128]; + HalfEdge tmpunderedges[512]; + Plane tmpunderplanes[128]; + Coplanar coplanaredges[512]; + int32_t coplanaredges_num=0; + + StanArray<REAL3> createdverts; + // do the side-of-plane tests + for(i=0;i<convex.vertices.count;i++) + { + vertflag[i].planetest = (uint8_t)PlaneTest(slice,convex.vertices[i]); + if(vertflag[i].planetest == COPLANAR) + { + // ? vertscoplanar.Add(i); + vertflag[i].undermap = (uint8_t)vertcountunder++; + vertflag[i].overmap = (uint8_t)vertcountover++; + } + else if(vertflag[i].planetest == UNDER) + { + vertflag[i].undermap = (uint8_t)vertcountunder++; + } + else + { + PX_ASSERT(vertflag[i].planetest == OVER); + vertflag[i].overmap = (uint8_t)vertcountover++; + vertflag[i].undermap = (uint8_t)-1; // for debugging purposes + } + } + + int32_t under_edge_count =0; + int32_t underplanescount=0; + int32_t e0=0; + + for(int32_t currentplane=0; currentplane<convex.facets.count; currentplane++) + { + int32_t estart =e0; + int32_t enextface=0; + int32_t planeside = 0; + int32_t e1 = e0+1; + int32_t vout=-1; + int32_t vin =-1; + int32_t coplanaredge = -1; + do + { + if(e1 >= convex.edges.count || convex.edges[e1].p!=currentplane) + { + enextface = e1; + e1=estart; + } + HalfEdge &edge0 = convex.edges[e0]; + HalfEdge &edge1 = convex.edges[e1]; + HalfEdge &edgea = convex.edges[edge0.ea]; + + + planeside |= vertflag[edge0.v].planetest; + //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { + // PX_ASSERT(ecop==-1); + // ecop=e; + //} + + if(vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == OVER) + { + // both endpoints over plane + edgeflag[e0].undermap = -1; + } + else if((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == UNDER) + { + // at least one endpoint under, the other coplanar or under + + edgeflag[e0].undermap = (short)under_edge_count; + tmpunderedges[under_edge_count].v = (uint8_t)vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + if(edge0.ea < e0) + { + // connect the neighbors + PX_ASSERT(edgeflag[edge0.ea].undermap !=-1); + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + } + under_edge_count++; + } + else if((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == COPLANAR) + { + // both endpoints coplanar + // must check a 3rd point to see if UNDER + int32_t e2 = e1+1; + if(e2>=convex.edges.count || convex.edges[e2].p!=currentplane) + { + e2 = estart; + } + PX_ASSERT(convex.edges[e2].p==currentplane); + HalfEdge &edge2 = convex.edges[e2]; + if(vertflag[edge2.v].planetest==UNDER) + { + + edgeflag[e0].undermap = (short)under_edge_count; + tmpunderedges[under_edge_count].v = (uint8_t)vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + // make sure this edge is added to the "coplanar" list + coplanaredge = under_edge_count; + vout = vertflag[edge0.v].undermap; + vin = vertflag[edge1.v].undermap; + under_edge_count++; + } + else + { + edgeflag[e0].undermap = -1; + } + } + else if(vertflag[edge0.v].planetest == UNDER && vertflag[edge1.v].planetest == OVER) + { + // first is under 2nd is over + + edgeflag[e0].undermap = (short) under_edge_count; + tmpunderedges[under_edge_count].v = (uint8_t)vertflag[edge0.v].undermap; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + if(edge0.ea < e0) + { + PX_ASSERT(edgeflag[edge0.ea].undermap !=-1); + // connect the neighbors + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + vout = tmpunderedges[edgeflag[edge0.ea].undermap].v; + } + else + { + Plane &p0 = convex.facets[edge0.p]; + Plane &pa = convex.facets[edgea.p]; + createdverts.Add(ThreePlaneIntersection(p0,pa,slice)); + //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); + //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); + vout = vertcountunder++; + } + under_edge_count++; + /// hmmm something to think about: i might be able to output this edge regarless of + // wheter or not we know v-in yet. ok i;ll try this now: + tmpunderedges[under_edge_count].v = (uint8_t)vout; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + coplanaredge = under_edge_count; + under_edge_count++; + + if(vin!=-1) + { + // we previously processed an edge where we came under + // now we know about vout as well + + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + + } + else if(vertflag[edge0.v].planetest == COPLANAR && vertflag[edge1.v].planetest == OVER) + { + // first is coplanar 2nd is over + + edgeflag[e0].undermap = -1; + vout = vertflag[edge0.v].undermap; + // I hate this but i have to make sure part of this face is UNDER before ouputting this vert + int32_t k=estart; + PX_ASSERT(edge0.p == currentplane); + while(!(planeside&UNDER) && k<convex.edges.count && convex.edges[k].p==edge0.p) + { + planeside |= vertflag[convex.edges[k].v].planetest; + k++; + } + if(planeside&UNDER) + { + tmpunderedges[under_edge_count].v = (uint8_t)vout; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + tmpunderedges[under_edge_count].ea = -1; + coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on + under_edge_count++; + + } + } + else if(vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == UNDER) + { + // first is over next is under + // new vertex!!! + if (vin!=-1) return NULL; + if(e0<edge0.ea) + { + Plane &p0 = convex.facets[edge0.p]; + Plane &pa = convex.facets[edgea.p]; + createdverts.Add(ThreePlaneIntersection(p0,pa,slice)); + //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); + //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); + vin = vertcountunder++; + } + else + { + // find the new vertex that was created by edge[edge0.ea] + int32_t nea = edgeflag[edge0.ea].undermap; + PX_ASSERT(tmpunderedges[nea].p==tmpunderedges[nea+1].p); + vin = tmpunderedges[nea+1].v; + PX_ASSERT(vin < vertcountunder); + } + if(vout!=-1) + { + // we previously processed an edge where we went over + // now we know vin too + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + // output edge + tmpunderedges[under_edge_count].v = (uint8_t)vin; + tmpunderedges[under_edge_count].p = (uint8_t)underplanescount; + edgeflag[e0].undermap = (short)under_edge_count; + if(e0>edge0.ea) + { + PX_ASSERT(edgeflag[edge0.ea].undermap !=-1); + // connect the neighbors + tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; + tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; + } + PX_ASSERT(edgeflag[e0].undermap == under_edge_count); + under_edge_count++; + } + else if(vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == COPLANAR) + { + // first is over next is coplanar + + edgeflag[e0].undermap = -1; + vin = vertflag[edge1.v].undermap; + if (vin==-1) return NULL; + if(vout!=-1) + { + // we previously processed an edge where we came under + // now we know both endpoints + // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! + } + + } + else + { + PX_ALWAYS_ASSERT(); + } + + + e0=e1; + e1++; // do the modulo at the beginning of the loop + + } while(e0!=estart) ; + e0 = enextface; + if(planeside&UNDER) + { + planeflag[currentplane].undermap = (uint8_t)underplanescount; + tmpunderplanes[underplanescount] = convex.facets[currentplane]; + underplanescount++; + } + else + { + planeflag[currentplane].undermap = 0; + } + if(vout>=0 && (planeside&UNDER)) + { + PX_ASSERT(vin>=0); + PX_ASSERT(coplanaredge>=0); + PX_ASSERT(coplanaredge!=511); + coplanaredges[coplanaredges_num].ea = (unsigned short)coplanaredge; + coplanaredges[coplanaredges_num].v0 = (uint8_t)vin; + coplanaredges[coplanaredges_num].v1 = (uint8_t)vout; + coplanaredges_num++; + } + } + + // add the new plane to the mix: + if(coplanaredges_num>0) + { + tmpunderplanes[underplanescount++]=slice; + } + for(i=0;i<coplanaredges_num-1;i++) + { + if(coplanaredges[i].v1 != coplanaredges[i+1].v0) + { + int32_t j = 0; + for(j=i+2;j<coplanaredges_num;j++) + { + if(coplanaredges[i].v1 == coplanaredges[j].v0) + { + Coplanar tmp = coplanaredges[i+1]; + coplanaredges[i+1] = coplanaredges[j]; + coplanaredges[j] = tmp; + break; + } + } + if(j>=coplanaredges_num) + { + // PX_ASSERT(j<coplanaredges_num); + return NULL; + } + } + } + ConvexH *punder = PX_NEW(ConvexH)(vertcountunder,under_edge_count+coplanaredges_num,underplanescount); + + ConvexH &under = *punder; + int32_t k=0; + for(i=0;i<convex.vertices.count;i++) + { + if(vertflag[i].planetest != OVER) + { + under.vertices[k++] = convex.vertices[i]; + } + } + i=0; + while(k<vertcountunder) + { + under.vertices[k++] = createdverts[i++]; + } + PX_ASSERT(i==createdverts.count); + + for(i=0;i<coplanaredges_num;i++) + { + under.edges[under_edge_count+i].p = (uint8_t)(underplanescount-1); + under.edges[under_edge_count+i].ea = (short)coplanaredges[i].ea; + tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count+i); + under.edges[under_edge_count+i].v = coplanaredges[i].v0; + } + + memcpy(under.edges.element,tmpunderedges,sizeof(HalfEdge)*under_edge_count); + memcpy(under.facets.element,tmpunderplanes,sizeof(Plane)*underplanescount); + + PX_UNUSED(planeflag[0]); // Make compiler happy + + return punder; +} + + +float minadjangle = 3.0f; // in degrees - result wont have two adjacent facets within this angle of each other. +static int32_t candidateplane(Plane *planes,int32_t planes_count,ConvexH *convex,float epsilon) +{ + int32_t p =-1; + REAL md=0; + int32_t i,j; + float maxdot_minang = cosf(DEG2RAD*minadjangle); + for(i=0;i<planes_count;i++) + { + float d=0; + float dmax=0; + float dmin=0; + for(j=0;j<convex->vertices.count;j++) + { + dmax = Max(dmax,dot(convex->vertices[j],planes[i].normal)+planes[i].dist); + dmin = Min(dmin,dot(convex->vertices[j],planes[i].normal)+planes[i].dist); + } + float dr = dmax-dmin; + if(dr<planetestepsilon) dr=1.0f; // shouldn't happen. + d = dmax /dr; + if(d<=md) continue; + for(j=0;j<convex->facets.count;j++) + { + if(planes[i]==convex->facets[j]) + { + d=0;continue; + } + if(dot(planes[i].normal,convex->facets[j].normal)>maxdot_minang) + { + for(int32_t k=0;k<convex->edges.count;k++) + { + if(convex->edges[k].p!=j) continue; + if(dot(convex->vertices[convex->edges[k].v],planes[i].normal)+planes[i].dist<0) + { + d=0; // so this plane wont get selected. + break; + } + } + } + } + if(d>md) + { + p=i; + md=d; + } + } + return (md>epsilon)?p:-1; +} + + + +template<class T> +inline int32_t maxdir(const T *p,int32_t count,const T &dir) +{ + PX_ASSERT(count); + int32_t m=0; + for(int32_t i=1;i<count;i++) + { + if(dot(p[i],dir)>dot(p[m],dir)) m=i; + } + return m; +} + + +template<class T> +int32_t maxdirfiltered(const T *p,int32_t count,const T &dir,StanArray<int32_t> &allow) +{ + PX_ASSERT(count); + int32_t m=-1; + for(int32_t i=0;i<count;i++) if(allow[i]) + { + if(m==-1 || dot(p[i],dir)>dot(p[m],dir)) m=i; + } + PX_ASSERT(m!=-1); + return m; +} + +float3 orth(const float3 &v) +{ + float3 a=cross(v,float3(0,0,1)); + float3 b=cross(v,float3(0,1,0)); + return normalize((magnitude(a)>magnitude(b))?a:b); +} + + +template<class T> +int32_t maxdirsterid(const T *p,int32_t count,const T &dir,StanArray<int32_t> &allow) +{ + int32_t m=-1; + while(m==-1) + { + m = maxdirfiltered(p,count,dir,allow); + if(allow[m]==3) return m; + T u = orth(dir); + T v = cross(u,dir); + int32_t ma=-1; + for(float x = 0.0f ; x<= 360.0f ; x+= 45.0f) + { + float s = sinf(DEG2RAD*(x)); + float c = cosf(DEG2RAD*(x)); + int32_t mb = maxdirfiltered(p,count,dir+(u*s+v*c)*0.025f,allow); + if(ma==m && mb==m) + { + allow[m]=3; + return m; + } + if(ma!=-1 && ma!=mb) // Yuck - this is really ugly + { + int32_t mc = ma; + for(float xx = x-40.0f ; xx <= x ; xx+= 5.0f) + { + float s = sinf(DEG2RAD*(xx)); + float c = cosf(DEG2RAD*(xx)); + int32_t md = maxdirfiltered(p,count,dir+(u*s+v*c)*0.025f,allow); + if(mc==m && md==m) + { + allow[m]=3; + return m; + } + mc=md; + } + } + ma=mb; + } + allow[m]=0; + m=-1; + } + PX_ALWAYS_ASSERT(); + return m; +} + + + + +int32_t operator ==(const int3 &a,const int3 &b) +{ + for(int32_t i=0;i<3;i++) + { + if(a[i]!=b[i]) return 0; + } + return 1; +} + +int3 roll3(int3 a) +{ + int32_t tmp=a[0]; + a[0]=a[1]; + a[1]=a[2]; + a[2]=tmp; + return a; +} +int32_t isa(const int3 &a,const int3 &b) +{ + return ( a==b || roll3(a)==b || a==roll3(b) ); +} +int32_t b2b(const int3 &a,const int3 &b) +{ + return isa(a,int3(b[2],b[1],b[0])); +} +int32_t above(float3* vertices,const int3& t, const float3 &p, float epsilon) +{ + float3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]); + return (dot(n,p-vertices[t[0]]) > epsilon); // EPSILON??? +} +int32_t hasedge(const int3 &t, int32_t a,int32_t b) +{ + for(int32_t i=0;i<3;i++) + { + int32_t i1= (i+1)%3; + if(t[i]==a && t[i1]==b) return 1; + } + return 0; +} +int32_t hasvert(const int3 &t, int32_t v) +{ + return (t[0]==v || t[1]==v || t[2]==v) ; +} +int32_t shareedge(const int3 &a,const int3 &b) +{ + int32_t i; + for(i=0;i<3;i++) + { + int32_t i1= (i+1)%3; + if(hasedge(a,b[i1],b[i])) return 1; + } + return 0; +} + +class Tri; + +static StanArray<Tri*> tris; // djs: For heaven's sake!!!! + +class Tri : public int3 +{ +public: + int3 n; + int32_t id; + int32_t vmax; + float rise; + Tri(int32_t a,int32_t b,int32_t c):int3(a,b,c),n(-1,-1,-1) + { + id = tris.count; + tris.Add(this); + vmax=-1; + rise = 0.0f; + } + ~Tri() + { + PX_ASSERT(tris[id]==this); + tris[id]=NULL; + } + int32_t &neib(int32_t a,int32_t b); +}; + + +int32_t &Tri::neib(int32_t a,int32_t b) +{ + static int32_t er=-1; + int32_t i; + for(i=0;i<3;i++) + { + int32_t i1=(i+1)%3; + int32_t i2=(i+2)%3; + if((*this)[i]==a && (*this)[i1]==b) return n[i2]; + if((*this)[i]==b && (*this)[i1]==a) return n[i2]; + } + PX_ALWAYS_ASSERT(); + return er; +} +void b2bfix(Tri* s,Tri*t) +{ + int32_t i; + for(i=0;i<3;i++) + { + int32_t i1=(i+1)%3; + int32_t i2=(i+2)%3; + int32_t a = (*s)[i1]; + int32_t b = (*s)[i2]; + PX_ASSERT(tris[s->neib(a,b)]->neib(b,a) == s->id); + PX_ASSERT(tris[t->neib(a,b)]->neib(b,a) == t->id); + tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a); + tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b); + } +} + +void removeb2b(Tri* s,Tri*t) +{ + b2bfix(s,t); + delete s; + delete t; +} + +void extrude(Tri *t0,int32_t v) +{ + int3 t= *t0; + int32_t n = tris.count; + Tri* ta = PX_NEW(Tri)(v,t[1],t[2]); + ta->n = int3(t0->n[0],n+1,n+2); + tris[t0->n[0]]->neib(t[1],t[2]) = n+0; + Tri* tb = PX_NEW(Tri)(v,t[2],t[0]); + tb->n = int3(t0->n[1],n+2,n+0); + tris[t0->n[1]]->neib(t[2],t[0]) = n+1; + Tri* tc = PX_NEW(Tri)(v,t[0],t[1]); + tc->n = int3(t0->n[2],n+0,n+1); + tris[t0->n[2]]->neib(t[0],t[1]) = n+2; + if(hasvert(*tris[ta->n[0]],v)) removeb2b(ta,tris[ta->n[0]]); + if(hasvert(*tris[tb->n[0]],v)) removeb2b(tb,tris[tb->n[0]]); + if(hasvert(*tris[tc->n[0]],v)) removeb2b(tc,tris[tc->n[0]]); + delete t0; + +} + +Tri *extrudable(float epsilon) +{ + int32_t i; + Tri *t=NULL; + for(i=0;i<tris.count;i++) + { + if(!t || (tris[i] && t->rise<tris[i]->rise)) + { + t = tris[i]; + } + } + return (t->rise >epsilon)?t:NULL ; +} + +class int4 +{ +public: + int32_t x,y,z,w; + int4(){}; + int4(int32_t _x,int32_t _y, int32_t _z,int32_t _w){x=_x;y=_y;z=_z;w=_w;} + const int32_t& operator[](int32_t i) const {return (&x)[i];} + int32_t& operator[](int32_t i) {return (&x)[i];} +}; + + + +bool hasVolume(float3 *verts, int32_t p0, int32_t p1, int32_t p2, int32_t p3) +{ + float3 result3 = cross(verts[p1]-verts[p0], verts[p2]-verts[p0]); + if (magnitude(result3) < VOLUME_EPSILON && magnitude(result3) > -VOLUME_EPSILON) // Almost collinear or otherwise very close to each other + return false; + float result = dot(normalize(result3), verts[p3]-verts[p0]); + return (result > VOLUME_EPSILON || result < -VOLUME_EPSILON); // Returns true iff volume is significantly non-zero +} + +int4 FindSimplex(float3 *verts,int32_t verts_count,StanArray<int32_t> &allow) +{ + float3 basis[3]; + basis[0] = float3( 0.01f, 0.02f, 1.0f ); + int32_t p0 = maxdirsterid(verts,verts_count, basis[0],allow); + int32_t p1 = maxdirsterid(verts,verts_count,-basis[0],allow); + basis[0] = verts[p0]-verts[p1]; + if(p0==p1 || basis[0]==float3(0,0,0)) + return int4(-1,-1,-1,-1); + basis[1] = cross(float3( 1, 0.02f, 0),basis[0]); + basis[2] = cross(float3(-0.02f, 1, 0),basis[0]); + basis[1] = normalize( (magnitude(basis[1])>magnitude(basis[2])) ? basis[1]:basis[2]); + int32_t p2 = maxdirsterid(verts,verts_count,basis[1],allow); + if(p2 == p0 || p2 == p1) + { + p2 = maxdirsterid(verts,verts_count,-basis[1],allow); + } + if(p2 == p0 || p2 == p1) + return int4(-1,-1,-1,-1); + basis[1] = verts[p2] - verts[p0]; + basis[2] = normalize(cross(basis[1],basis[0])); + int32_t p3 = maxdirsterid(verts,verts_count,basis[2],allow); + if(p3==p0||p3==p1||p3==p2||!hasVolume(verts, p0, p1, p2, p3)) p3 = maxdirsterid(verts,verts_count,-basis[2],allow); + if(p3==p0||p3==p1||p3==p2) + return int4(-1,-1,-1,-1); + PX_ASSERT(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3)); + if(dot(verts[p3]-verts[p0],cross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);} + return int4(p0,p1,p2,p3); +} + +#pragma warning(push) +#pragma warning(disable:4706) +int32_t calchullgen(float3 *verts,int32_t verts_count, int32_t vlimit) +{ + if(verts_count <4) return 0; + if(vlimit==0) vlimit=1000000000; + int32_t j; + float3 bmin(*verts),bmax(*verts); + StanArray<int32_t> isextreme(verts_count); + StanArray<int32_t> allow(verts_count); + for(j=0;j<verts_count;j++) + { + allow.Add(1); + isextreme.Add(0); + bmin = VectorMin(bmin,verts[j]); + bmax = VectorMax(bmax,verts[j]); + } + float epsilon = magnitude(bmax-bmin) * 0.001f; + + + int4 p = FindSimplex(verts,verts_count,allow); + if(p.x==-1) return 0; // simplex failed + + + + float3 center = (verts[p[0]]+verts[p[1]]+verts[p[2]]+verts[p[3]]) /4.0f; // a valid interior point + Tri *t0 = PX_NEW(Tri)(p[2],p[3],p[1]); t0->n=int3(2,3,1); + Tri *t1 = PX_NEW(Tri)(p[3],p[2],p[0]); t1->n=int3(3,2,0); + Tri *t2 = PX_NEW(Tri)(p[0],p[1],p[3]); t2->n=int3(0,1,3); + Tri *t3 = PX_NEW(Tri)(p[1],p[0],p[2]); t3->n=int3(1,0,2); + isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1; + + for(j=0;j<tris.count;j++) + { + Tri *t=tris[j]; + PX_ASSERT(t); + PX_ASSERT(t->vmax<0); + float3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); + t->vmax = maxdirsterid(verts,verts_count,n,allow); + t->rise = dot(n,verts[t->vmax]-verts[(*t)[0]]); + } + Tri *te; + vlimit-=4; + while(vlimit >0 && (te=extrudable(epsilon))) + { + int32_t v=te->vmax; + PX_ASSERT(!isextreme[v]); // wtf we've already done this vertex + isextreme[v]=1; + //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already + j=tris.count; + while(j--) { + if(!tris[j]) continue; + int3 t=*tris[j]; + if(above(verts,t,verts[v],0.01f*epsilon)) + { + extrude(tris[j],v); + } + } + // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle + j=tris.count; + while(j--) + { + if(!tris[j]) continue; + if(!hasvert(*tris[j],v)) break; + int3 nt=*tris[j]; + if(above(verts,nt,center,0.01f*epsilon) || magnitude(cross(verts[nt[1]]-verts[nt[0]],verts[nt[2]]-verts[nt[1]]))< epsilon*epsilon*0.1f ) + { + Tri *nb = tris[tris[j]->n[0]]; + PX_ASSERT(nb);PX_ASSERT(!hasvert(*nb,v));PX_ASSERT(nb->id<j); + extrude(nb,v); + j=tris.count; + } + } + j=tris.count; + while(j--) + { + Tri *t=tris[j]; + if(!t) continue; + if(t->vmax>=0) break; + float3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); + t->vmax = maxdirsterid(verts,verts_count,n,allow); + if(isextreme[t->vmax]) + { + t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate. + } + else + { + t->rise = dot(n,verts[t->vmax]-verts[(*t)[0]]); + } + } + vlimit --; + } + return 1; +} +#pragma warning(pop) + +int32_t calchull(float3 *verts,int32_t verts_count, int32_t *&tris_out, int32_t &tris_count,int32_t vlimit) +{ + int32_t rc=calchullgen(verts,verts_count, vlimit) ; + if(!rc) return 0; + StanArray<int32_t> ts; + for(int32_t i=0;i<tris.count;i++)if(tris[i]) + { + for(int32_t j=0;j<3;j++)ts.Add((*tris[i])[j]); + delete tris[i]; + } + tris_count = ts.count/3; + tris_out = ts.element; + ts.element=NULL; ts.count=ts.array_size=0; + // please reset here, otherwise, we get a nice virtual function call (R6025) error with PxCooking library + tris.SetSize( 0 ); + return 1; +} + +static float area2(const float3 &v0,const float3 &v1,const float3 &v2) +{ + float3 cp = cross(v0-v1,v2-v0); + return dot(cp,cp); +} +int32_t calchullpbev(float3 *verts,int32_t verts_count,int32_t vlimit, StanArray<Plane> &planes,float bevangle) +{ + int32_t i,j; + StanArray<Plane> bplanes; + planes.count=0; + int32_t rc = calchullgen(verts,verts_count,vlimit); + if(!rc) return 0; + extern float minadjangle; // default is 3.0f; // in degrees - result wont have two adjacent facets within this angle of each other. + float maxdot_minang = cosf(DEG2RAD*minadjangle); + for(i=0;i<tris.count;i++)if(tris[i]) + { + Plane p; + Tri *t = tris[i]; + p.normal = TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); + p.dist = -dot(p.normal, verts[(*t)[0]]); + for(j=0;j<3;j++) + { + if(t->n[j]<t->id) continue; + Tri *s = tris[t->n[j]]; + REAL3 snormal = TriNormal(verts[(*s)[0]],verts[(*s)[1]],verts[(*s)[2]]); + if(dot(snormal,p.normal)>=cos(bevangle*DEG2RAD)) continue; + REAL3 e = verts[(*t)[(j+2)%3]] - verts[(*t)[(j+1)%3]]; + REAL3 n = (e!=REAL3(0,0,0))? cross(snormal,e)+cross(e,p.normal) : snormal+p.normal; + PX_ASSERT(n!=REAL3(0,0,0)); + if(n==REAL3(0,0,0)) return 0; + n=normalize(n); + bplanes.Add(Plane(n,-dot(n,verts[maxdir(verts,verts_count,n)]))); + } + } + for(i=0;i<tris.count;i++)if(tris[i])for(j=i+1;j<tris.count;j++)if(tris[i] && tris[j]) + { + Tri *ti = tris[i]; + Tri *tj = tris[j]; + REAL3 ni = TriNormal(verts[(*ti)[0]],verts[(*ti)[1]],verts[(*ti)[2]]); + REAL3 nj = TriNormal(verts[(*tj)[0]],verts[(*tj)[1]],verts[(*tj)[2]]); + if(dot(ni,nj)>maxdot_minang) + { + // somebody has to die, keep the biggest triangle + if( area2(verts[(*ti)[0]],verts[(*ti)[1]],verts[(*ti)[2]]) < area2(verts[(*tj)[0]],verts[(*tj)[1]],verts[(*tj)[2]])) + { + delete tris[i]; + } + else + { + delete tris[j]; + } + } + } + for(i=0;i<tris.count;i++)if(tris[i]) + { + Plane p; + Tri *t = tris[i]; + p.normal = TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); + p.dist = -dot(p.normal, verts[(*t)[0]]); + planes.Add(p); + } + for(i=0;i<bplanes.count;i++) + { + for(j=0;j<planes.count;j++) + { + if(dot(bplanes[i].normal,planes[j].normal)>maxdot_minang) break; + } + if(j==planes.count) + { + planes.Add(bplanes[i]); + } + } + for(i=0;i<tris.count;i++)if(tris[i]) + { + delete tris[i]; + } + tris.count = 0; //bad place to do the tris.SetSize(0) fix, this line is executed many times, and will result in a whole lot of allocations if the array is totally cleared here + return 1; +} + +ConvexH *test_cube() +{ + ConvexH *convex = PX_NEW(ConvexH)(8,24,6); + convex->vertices[0] = REAL3(0,0,0); + convex->vertices[1] = REAL3(0,0,1); + convex->vertices[2] = REAL3(0,1,0); + convex->vertices[3] = REAL3(0,1,1); + convex->vertices[4] = REAL3(1,0,0); + convex->vertices[5] = REAL3(1,0,1); + convex->vertices[6] = REAL3(1,1,0); + convex->vertices[7] = REAL3(1,1,1); + + convex->facets[0] = Plane(REAL3(-1,0,0),0); + convex->facets[1] = Plane(REAL3(1,0,0),-1); + convex->facets[2] = Plane(REAL3(0,-1,0),0); + convex->facets[3] = Plane(REAL3(0,1,0),-1); + convex->facets[4] = Plane(REAL3(0,0,-1),0); + convex->facets[5] = Plane(REAL3(0,0,1),-1); + + convex->edges[0 ] = HalfEdge(11,0,0); + convex->edges[1 ] = HalfEdge(23,1,0); + convex->edges[2 ] = HalfEdge(15,3,0); + convex->edges[3 ] = HalfEdge(16,2,0); + + convex->edges[4 ] = HalfEdge(13,6,1); + convex->edges[5 ] = HalfEdge(21,7,1); + convex->edges[6 ] = HalfEdge( 9,5,1); + convex->edges[7 ] = HalfEdge(18,4,1); + + convex->edges[8 ] = HalfEdge(19,0,2); + convex->edges[9 ] = HalfEdge( 6,4,2); + convex->edges[10] = HalfEdge(20,5,2); + convex->edges[11] = HalfEdge( 0,1,2); + + convex->edges[12] = HalfEdge(22,3,3); + convex->edges[13] = HalfEdge( 4,7,3); + convex->edges[14] = HalfEdge(17,6,3); + convex->edges[15] = HalfEdge( 2,2,3); + + convex->edges[16] = HalfEdge( 3,0,4); + convex->edges[17] = HalfEdge(14,2,4); + convex->edges[18] = HalfEdge( 7,6,4); + convex->edges[19] = HalfEdge( 8,4,4); + + convex->edges[20] = HalfEdge(10,1,5); + convex->edges[21] = HalfEdge( 5,5,5); + convex->edges[22] = HalfEdge(12,7,5); + convex->edges[23] = HalfEdge( 1,3,5); + + + return convex; +} + +ConvexH *ConvexHMakeCube(const REAL3 &bmin, const REAL3 &bmax) +{ + ConvexH *convex = test_cube(); + convex->vertices[0] = REAL3(bmin.x,bmin.y,bmin.z); + convex->vertices[1] = REAL3(bmin.x,bmin.y,bmax.z); + convex->vertices[2] = REAL3(bmin.x,bmax.y,bmin.z); + convex->vertices[3] = REAL3(bmin.x,bmax.y,bmax.z); + convex->vertices[4] = REAL3(bmax.x,bmin.y,bmin.z); + convex->vertices[5] = REAL3(bmax.x,bmin.y,bmax.z); + convex->vertices[6] = REAL3(bmax.x,bmax.y,bmin.z); + convex->vertices[7] = REAL3(bmax.x,bmax.y,bmax.z); + + convex->facets[0] = Plane(REAL3(-1,0,0), bmin.x); + convex->facets[1] = Plane(REAL3(1,0,0), -bmax.x); + convex->facets[2] = Plane(REAL3(0,-1,0), bmin.y); + convex->facets[3] = Plane(REAL3(0,1,0), -bmax.y); + convex->facets[4] = Plane(REAL3(0,0,-1), bmin.z); + convex->facets[5] = Plane(REAL3(0,0,1), -bmax.z); + return convex; +} + + +static int32_t overhull(Plane *planes,int32_t planes_count,float3 *verts, int32_t verts_count,int32_t maxplanes, + float3 *&verts_out, int32_t &verts_count_out, int32_t *&faces_out, int32_t &faces_count_out ,float inflate) +{ + int32_t i,j; + if(verts_count <4) return 0; + maxplanes = Min(maxplanes,planes_count); + float3 bmin(verts[0]),bmax(verts[0]); + for(i=0;i<verts_count;i++) + { + bmin = VectorMin(bmin,verts[i]); + bmax = VectorMax(bmax,verts[i]); + } + float diameter = magnitude(bmax-bmin); +// inflate *=diameter; // RELATIVE INFLATION + bmin -= float3(inflate*2.5f,inflate*2.5f,inflate*2.5f); + bmax += float3(inflate*2.5f,inflate*2.5f,inflate*2.5f); + // 2 is from the formula: + // D = d*|n1+n2|/(1-n1 dot n2), where d is "inflate" and + // n1 and n2 are the normals of two planes at bevelAngle to each other + // for 120 degrees, D is 2d + + //bmin -= float3(inflate,inflate,inflate); + //bmax += float3(inflate,inflate,inflate); + for(i=0;i<planes_count;i++) + { + planes[i].dist -= inflate; + } + float3 emin = bmin; // VectorMin(bmin,float3(0,0,0)); + float3 emax = bmax; // VectorMax(bmax,float3(0,0,0)); + float epsilon = 0.01f; // size of object is taken into account within candidate plane function. Used to multiply here by magnitude(emax-emin) + planetestepsilon = magnitude(emax-emin) * PAPERWIDTH; + // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think. + // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter)); + float maxdot_minang = cosf(DEG2RAD*minadjangle); + for(j=0;j<6;j++) + { + float3 n(0,0,0); + n[j/2] = (j%2)? 1.0f : -1.0f; + for(i=0;i<planes_count;i++) + { + if(dot(n,planes[i].normal)> maxdot_minang) + { + (*((j%2)?&bmax:&bmin)) += n * (diameter*0.5f); + break; + } + } + } + ConvexH *c = ConvexHMakeCube(REAL3(bmin),REAL3(bmax)); + int32_t k; + while(maxplanes-- && (k=candidateplane(planes,planes_count,c,epsilon))>=0) + { + ConvexH *tmp = c; + c = ConvexHCrop(*tmp,planes[k]); + if(c==NULL) {c=tmp; break;} // might want to debug this case better!!! + if(!AssertIntact(*c)) { delete c; c=tmp; break;} // might want to debug this case better too!!! + delete tmp; + } + + PX_ASSERT(AssertIntact(*c)); + //return c; + faces_out = (int32_t*)PX_ALLOC(sizeof(int32_t)*(1+c->facets.count+c->edges.count), PX_DEBUG_EXP("StanHull::overhull")); // new int32_t[1+c->facets.count+c->edges.count]; + faces_count_out=0; + i=0; + faces_out[faces_count_out++]=-1; + k=0; + while(i<c->edges.count) + { + j=1; + while(j+i<c->edges.count && c->edges[i].p==c->edges[i+j].p) { j++; } + faces_out[faces_count_out++]=j; + while(j--) + { + faces_out[faces_count_out++] = c->edges[i].v; + i++; + } + k++; + } + faces_out[0]=k; // number of faces. + PX_ASSERT(k==c->facets.count); + PX_ASSERT(faces_count_out == 1+c->facets.count+c->edges.count); + verts_out = c->vertices.element; // new float3[c->vertices.count]; + verts_count_out = c->vertices.count; + for(i=0;i<c->vertices.count;i++) + { + verts_out[i] = float3(c->vertices[i]); + } + c->vertices.count=c->vertices.array_size=0; c->vertices.element=NULL; + delete c; + return 1; +} + +static int32_t overhullv(float3 *verts, int32_t verts_count,int32_t maxplanes, + float3 *&verts_out, int32_t &verts_count_out, int32_t *&faces_out, int32_t &faces_count_out ,float inflate,float bevangle,int32_t vlimit) +{ + if(!verts_count) return 0; + extern int32_t calchullpbev(float3 *verts,int32_t verts_count,int32_t vlimit, StanArray<Plane> &planes,float bevangle) ; + StanArray<Plane> planes; + int32_t rc=calchullpbev(verts,verts_count,vlimit,planes,bevangle) ; + if(!rc) return 0; + return overhull(planes.element,planes.count,verts,verts_count,maxplanes,verts_out,verts_count_out,faces_out,faces_count_out,inflate); +} + + +//***************************************************** +//***************************************************** + + +bool ComputeHull(uint32_t vcount, + const float *vertices, + PHullResult &result, + uint32_t vlimit, + float inflate, + bool useTriangles) +{ + + int32_t index_count; + int32_t *faces = 0; + float3 *verts_out = 0; + int32_t verts_count_out = 0; + + if(inflate==0.0f && useTriangles) + { + int32_t *tris_out; + int32_t tris_count; + int32_t ret = calchull( (float3 *) vertices, (int32_t) vcount, tris_out, tris_count, (int32_t) vlimit ); + if(!ret) return false; + result.mIndexCount = (uint32_t) (tris_count*3); + result.mFaceCount = (uint32_t) tris_count; + result.mVertices = (float*) vertices; + result.mVcount = (uint32_t) vcount; + result.mIndices = (uint32_t *) tris_out; + return true; + } + + int32_t ret = overhullv((float3*)vertices, (int32_t) vcount,35,verts_out,verts_count_out,faces,index_count,inflate,120.0f, (int32_t) vlimit); + + if(!ret) + { + tris.SetSize(0); //have to set the size to 0 in order to protect from a "pure virtual function call" problem + return false; + } + + if ( useTriangles ) + { + StanArray<int3> triangles; + int32_t n=faces[0]; + int32_t k=1; + for(int32_t i=0;i<n;i++) + { + int32_t pn = faces[k++]; + for(int32_t j=2;j<pn;j++) triangles.Add(int3(faces[k],faces[k+j-1],faces[k+j])); + k+=pn; + } + PX_ASSERT(triangles.count == index_count-1-(n*3)); + + result.mIndexCount = (uint32_t) (triangles.count*3); + result.mFaceCount = (uint32_t) triangles.count; + result.mVertices = (float*) verts_out; + result.mVcount = (uint32_t) verts_count_out; + result.mIndices = (uint32_t *) triangles.element; + triangles.element=NULL; triangles.count = triangles.array_size=0; + nvidia::stanhull::tris.SetSize(0); //have to set the size to 0 in order to protect from a "pure virtual function call" problem + } + else + { + StanArray<uint32_t> indices; + StanArray<uint8_t> faceCounts; + + int32_t n=faces[0]; + int32_t k=1; + for(int32_t i=0;i<n;i++) + { + int32_t pn = faces[k++]; + PX_ASSERT( pn >= 3 && pn < 256 ); + faceCounts.Add( (uint8_t)pn ); + for(int32_t j=0;j<pn;j++) + { + indices.Add((uint32_t)faces[k]); + k++; + } + } + result.mIndexCount = (uint32_t)indices.count; + result.mFaceCount = (uint32_t)faceCounts.count; + result.mVertices = (float*) verts_out; + result.mVcount = (uint32_t) verts_count_out; + result.mIndices = (uint32_t *) indices.element; + result.mFaces = (uint8_t *)faceCounts.element; + + // Null these out since we are keeping the memory associated with these containers + indices.element = NULL; + indices.count = indices.array_size = 0; + faceCounts.element = NULL; + faceCounts.count = faceCounts.array_size = 0; + + nvidia::stanhull::tris.SetSize(0); //have to set the size to 0 in order to protect from a "pure virtual function call" problem + + } + + PX_FREE(faces); + + return true; +} + + +void ReleaseHull(PHullResult &result) +{ + PX_FREE(result.mIndices); // PT: I added that. Is it ok ? + PX_FREE(result.mVertices); // PT: I added that. Is it ok ? + if (result.mFaces != 0) + PX_FREE(result.mFaces); + + result.mVcount = 0; + result.mIndexCount = 0; + result.mIndices = 0; + result.mVertices = 0; + result.mIndices = 0; + result.mFaceCount = 0; + result.mFaces = 0; +} + + + +//****** HULLLIB source code + + +HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request + HullResult &result) // contains the resulst +{ + HullError ret = QE_FAIL; + + + PHullResult hr; + + uint32_t vcount = desc.mVcount; + if ( vcount < 8 ) + { + vcount = 8; + } + + float *vsource = (float *) PX_ALLOC( sizeof(float)*vcount*3, PX_DEBUG_EXP("HullLibrary::CreateConvexHull") ); + + + float scale[3]; + + uint32_t ovcount; + + bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, vsource, desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates! + + if ( ok ) + { + { + for (uint32_t i=0; i<ovcount; i++) + { + float *v = &vsource[i*3]; + v[0]*=scale[0]; + v[1]*=scale[1]; + v[2]*=scale[2]; + } + } + + float skinwidth = 0; + if ( desc.HasHullFlag(QF_SKIN_WIDTH) ) + { + skinwidth = desc.mSkinWidth; + } + + ok = ComputeHull(ovcount,vsource,hr,desc.mMaxVertices,skinwidth,desc.HasHullFlag(QF_TRIANGLES)); + + if ( ok ) + { + + // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table. + float *vscratch = (float *) PX_ALLOC( sizeof(float)*hr.mVcount*3, PX_DEBUG_EXP("HullLibrary::CreateConvexHull")); + BringOutYourDead(hr.mVertices,hr.mVcount, vscratch, ovcount, hr.mIndices, hr.mIndexCount ); + + ret = QE_OK; + + if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle! + { + result.mPolygons = false; + result.mNumOutputVertices = ovcount; + result.mOutputVertices = (float *)PX_ALLOC( sizeof(float)*ovcount*3, PX_DEBUG_EXP("HullLibrary::CreateConvexHull")); + result.mNumFaces = hr.mFaceCount; + result.mNumIndices = hr.mIndexCount; + + result.mIndices = (uint32_t *) PX_ALLOC( sizeof(uint32_t)*hr.mIndexCount, PX_DEBUG_EXP("HullLibrary::CreateConvexHull")); + + memcpy(result.mOutputVertices, vscratch, sizeof(float)*3*ovcount ); + + if ( desc.HasHullFlag(QF_REVERSE_ORDER) ) + { + const uint32_t *source = hr.mIndices; + uint32_t *dest = result.mIndices; + for (uint32_t i=0; i<hr.mFaceCount; i++) + { + dest[0] = source[2]; + dest[1] = source[1]; + dest[2] = source[0]; + dest+=3; + source+=3; + } + } + else + { + memcpy(result.mIndices, hr.mIndices, sizeof(uint32_t)*hr.mIndexCount); + } + } + else + { + result.mPolygons = true; + result.mNumOutputVertices = ovcount; + result.mOutputVertices = (float *)PX_ALLOC( sizeof(float)*ovcount*3, PX_DEBUG_EXP("HullLibrary::CreateConvexHull")); + result.mNumFaces = hr.mFaceCount; + result.mNumIndices = hr.mIndexCount; + result.mIndices = (uint32_t *) PX_ALLOC( sizeof(uint32_t)*result.mNumIndices, PX_DEBUG_EXP("HullLibrary::CreateConvexHull")); + result.mFaces = (uint8_t *)PX_ALLOC(sizeof(uint8_t)*hr.mFaceCount,PX_DEBUG_EXP("HullLibrary::Faces")); + + memcpy(result.mOutputVertices, vscratch, sizeof(float)*3*ovcount ); // copy the vertices + memcpy(result.mFaces, hr.mFaces, sizeof(uint8_t)*hr.mFaceCount); // copy the face counters + + if ( desc.HasHullFlag(QF_REVERSE_ORDER) ) + { + const uint32_t *source = hr.mIndices; + uint32_t *dest = result.mIndices; + for (uint32_t i=0; i<hr.mFaceCount; i++) + { + uint32_t pcount = result.mFaces[i]; + for (uint32_t j=0; j<pcount; j++) + { + dest[j] = source[(pcount-1)-j]; + } + dest+=pcount; + source+=pcount; + } + } + else + { + memcpy(result.mIndices, hr.mIndices, sizeof(uint32_t)*hr.mIndexCount); // copy the indices + } + } + + // ReleaseHull frees memory for hr.mVertices, which can be the + // same pointer as vsource, so be sure to set it to NULL if necessary + + if ( hr.mVertices == vsource) vsource = NULL; + + ReleaseHull(hr); + + if ( vscratch ) + { + PX_FREE(vscratch); + } + } + } + + // this pointer is usually freed in ReleaseHull() + if ( vsource ) + { + PX_FREE(vsource); + } + + + return ret; +} + + + +HullError HullLibrary::ReleaseResult(HullResult &result) // release memory allocated for this result, we are done with it. +{ + if ( result.mOutputVertices ) + { + PX_FREE(result.mOutputVertices); + result.mOutputVertices = 0; + } + if ( result.mIndices ) + { + PX_FREE(result.mIndices); + result.mIndices = 0; + } + if( result.mFaces ) + { + PX_FREE(result.mFaces); + result.mFaces = NULL; + } + return QE_OK; +} + + +static void AddPoint(uint32_t &vcount,float *p,float x,float y,float z) +{ + float *dest = &p[vcount*3]; + dest[0] = x; + dest[1] = y; + dest[2] = z; + vcount++; +} + + +float GetDist(float px,float py,float pz,const float *p2) +{ + + float dx = px - p2[0]; + float dy = py - p2[1]; + float dz = pz - p2[2]; + + return dx*dx+dy*dy+dz*dz; +} + + + +bool HullLibrary::CleanupVertices(uint32_t svcount, + const float *svertices, + uint32_t stride, + uint32_t &vcount, // output number of vertices + float *vertices, // location to store the results. + float normalepsilon, + float *scale) +{ + if ( svcount == 0 ) return false; + + + #define EPSILON 0.000001f // close enough to consider two floating point numbers to be 'the same'. + + vcount = 0; + + float recip[3]; + + if ( scale ) + { + scale[0] = 1; + scale[1] = 1; + scale[2] = 1; + } + else + { + // Make compiler happy + recip[0] = recip[1] = recip[2] = 0; + } + + float bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; + float bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; + + const char *vtx = (const char *) svertices; + + { + for (uint32_t i=0; i<svcount; i++) + { + const float *p = (const float *) vtx; + + vtx+=stride; + + for (int32_t j=0; j<3; j++) + { + if ( p[j] < bmin[j] ) bmin[j] = p[j]; + if ( p[j] > bmax[j] ) bmax[j] = p[j]; + } + } + } + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + float center[3]; + + center[0] = dx*0.5f + bmin[0]; + center[1] = dy*0.5f + bmin[1]; + center[2] = dz*0.5f + bmin[2]; + + if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 ) + { + + float len = FLT_MAX; + + if ( dx > EPSILON && dx < len ) len = dx; + if ( dy > EPSILON && dy < len ) len = dy; + if ( dz > EPSILON && dz < len ) len = dz; + + if ( len == FLT_MAX ) + { + dx = dy = dz = 0.01f; // one centimeter + } + else + { + if ( dx < EPSILON ) dx = len * 0.05f; // 1/5th the shortest non-zero edge. + if ( dy < EPSILON ) dy = len * 0.05f; + if ( dz < EPSILON ) dz = len * 0.05f; + } + + float x1 = center[0] - dx; + float x2 = center[0] + dx; + + float y1 = center[1] - dy; + float y2 = center[1] + dy; + + float z1 = center[2] - dz; + float z2 = center[2] + dz; + + AddPoint(vcount,vertices,x1,y1,z1); + AddPoint(vcount,vertices,x2,y1,z1); + AddPoint(vcount,vertices,x2,y2,z1); + AddPoint(vcount,vertices,x1,y2,z1); + AddPoint(vcount,vertices,x1,y1,z2); + AddPoint(vcount,vertices,x2,y1,z2); + AddPoint(vcount,vertices,x2,y2,z2); + AddPoint(vcount,vertices,x1,y2,z2); + + return true; // return cube + + + } + else + { + if ( scale ) + { + scale[0] = dx; + scale[1] = dy; + scale[2] = dz; + + recip[0] = 1 / dx; + recip[1] = 1 / dy; + recip[2] = 1 / dz; + + center[0]*=recip[0]; + center[1]*=recip[1]; + center[2]*=recip[2]; + + } + + } + + + + vtx = (const char *) svertices; + + for (uint32_t i=0; i<svcount; i++) + { + + const float *p = (const float *)vtx; + vtx+=stride; + + float px = p[0]; + float py = p[1]; + float pz = p[2]; + + if ( scale ) + { + px = px*recip[0]; // normalize + py = py*recip[1]; // normalize + pz = pz*recip[2]; // normalize + } + + { + uint32_t j; + + for (j=0; j<vcount; j++) + { + float *v = &vertices[j*3]; + + float x = v[0]; + float y = v[1]; + float z = v[2]; + + float dx = fabsf(x - px ); + float dy = fabsf(y - py ); + float dz = fabsf(z - pz ); + + if ( dx < normalepsilon && dy < normalepsilon && dz < normalepsilon ) + { + // ok, it is close enough to the old one + // now let us see if it is further from the center of the point cloud than the one we already recorded. + // in which case we keep this one instead. + + float dist1 = GetDist(px,py,pz,center); + float dist2 = GetDist(v[0],v[1],v[2],center); + + if ( dist1 > dist2 ) + { + v[0] = px; + v[1] = py; + v[2] = pz; + } + + break; + } + } + + if ( j == vcount ) + { + float *dest = &vertices[vcount*3]; + dest[0] = px; + dest[1] = py; + dest[2] = pz; + vcount++; + } + } + } + + // ok..now make sure we didn't prune so many vertices it is now invalid. + { + float bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; + float bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; + + for (uint32_t i=0; i<vcount; i++) + { + const float *p = &vertices[i*3]; + for (int32_t j=0; j<3; j++) + { + if ( p[j] < bmin[j] ) bmin[j] = p[j]; + if ( p[j] > bmax[j] ) bmax[j] = p[j]; + } + } + + float dx = bmax[0] - bmin[0]; + float dy = bmax[1] - bmin[1]; + float dz = bmax[2] - bmin[2]; + + if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3) + { + float cx = dx*0.5f + bmin[0]; + float cy = dy*0.5f + bmin[1]; + float cz = dz*0.5f + bmin[2]; + + float len = FLT_MAX; + + if ( dx >= EPSILON && dx < len ) len = dx; + if ( dy >= EPSILON && dy < len ) len = dy; + if ( dz >= EPSILON && dz < len ) len = dz; + + if ( len == FLT_MAX ) + { + dx = dy = dz = 0.01f; // one centimeter + } + else + { + if ( dx < EPSILON ) dx = len * 0.05f; // 1/5th the shortest non-zero edge. + if ( dy < EPSILON ) dy = len * 0.05f; + if ( dz < EPSILON ) dz = len * 0.05f; + } + + float x1 = cx - dx; + float x2 = cx + dx; + + float y1 = cy - dy; + float y2 = cy + dy; + + float z1 = cz - dz; + float z2 = cz + dz; + + vcount = 0; // add box + + AddPoint(vcount,vertices,x1,y1,z1); + AddPoint(vcount,vertices,x2,y1,z1); + AddPoint(vcount,vertices,x2,y2,z1); + AddPoint(vcount,vertices,x1,y2,z1); + AddPoint(vcount,vertices,x1,y1,z2); + AddPoint(vcount,vertices,x2,y1,z2); + AddPoint(vcount,vertices,x2,y2,z2); + AddPoint(vcount,vertices,x1,y2,z2); + + return true; + } + } + + return true; +} + +void HullLibrary::BringOutYourDead(const float *verts,uint32_t vcount, float *overts,uint32_t &ocount,uint32_t *indices,uint32_t indexcount) +{ + uint32_t *used = (uint32_t *)PX_ALLOC(sizeof(uint32_t)*vcount, PX_DEBUG_EXP("HullLibrary::BringOutYourDead")); + memset(used,0,sizeof(uint32_t)*vcount); + + ocount = 0; + + for (uint32_t i=0; i<indexcount; i++) + { + uint32_t v = indices[i]; // original array index + + PX_ASSERT( v < vcount ); + + if ( used[v] ) // if already remapped + { + indices[i] = used[v]-1; // index to new array + } + else + { + + indices[i] = ocount; // new index mapping + + overts[ocount*3+0] = verts[v*3+0]; // copy old vert to new vert array + overts[ocount*3+1] = verts[v*3+1]; + overts[ocount*3+2] = verts[v*3+2]; + + ocount++; // increment output vert count + + PX_ASSERT( ocount <= vcount ); + + used[v] = ocount; // assign new index remapping + } + } + + PX_FREE(used); +} + +//================================================================================== +HullError HullLibrary::CreateTriangleMesh(HullResult &answer,ConvexHullTriangleInterface *iface) +{ + HullError ret = QE_FAIL; + + + const float *p = answer.mOutputVertices; + const uint32_t *idx = answer.mIndices; + uint32_t fcount = answer.mNumFaces; + + if ( p && idx && fcount ) + { + ret = QE_OK; + + for (uint32_t i=0; i<fcount; i++) + { + uint32_t pcount = *idx++; + + uint32_t i1 = *idx++; + uint32_t i2 = *idx++; + uint32_t i3 = *idx++; + + const float *p1 = &p[i1*3]; + const float *p2 = &p[i2*3]; + const float *p3 = &p[i3*3]; + + AddConvexTriangle(iface,p1,p2,p3); + + pcount-=3; + while ( pcount ) + { + i3 = *idx++; + p2 = p3; + p3 = &p[i3*3]; + + AddConvexTriangle(iface,p1,p2,p3); + pcount--; + } + + } + } + + return ret; +} + +//================================================================================== +void HullLibrary::AddConvexTriangle(ConvexHullTriangleInterface *callback,const float *p1,const float *p2,const float *p3) +{ + ConvexHullVertex v1,v2,v3; + + #define TSCALE1 (1.0f/4.0f) + + v1.mPos[0] = p1[0]; + v1.mPos[1] = p1[1]; + v1.mPos[2] = p1[2]; + + v2.mPos[0] = p2[0]; + v2.mPos[1] = p2[1]; + v2.mPos[2] = p2[2]; + + v3.mPos[0] = p3[0]; + v3.mPos[1] = p3[1]; + v3.mPos[2] = p3[2]; + + float n[3]; + ComputeNormal(n,p1,p2,p3); + + v1.mNormal[0] = n[0]; + v1.mNormal[1] = n[1]; + v1.mNormal[2] = n[2]; + + v2.mNormal[0] = n[0]; + v2.mNormal[1] = n[1]; + v2.mNormal[2] = n[2]; + + v3.mNormal[0] = n[0]; + v3.mNormal[1] = n[1]; + v3.mNormal[2] = n[2]; + + const float *tp1 = p1; + const float *tp2 = p2; + const float *tp3 = p3; + + int32_t i1 = 0; + int32_t i2 = 0; + + float nx = fabsf(n[0]); + float ny = fabsf(n[1]); + float nz = fabsf(n[2]); + + if ( nx <= ny && nx <= nz ) + i1 = 0; + if ( ny <= nx && ny <= nz ) + i1 = 1; + if ( nz <= nx && nz <= ny ) + i1 = 2; + + switch ( i1 ) + { + case 0: + if ( ny < nz ) + i2 = 1; + else + i2 = 2; + break; + case 1: + if ( nx < nz ) + i2 = 0; + else + i2 = 2; + break; + case 2: + if ( nx < ny ) + i2 = 0; + else + i2 = 1; + break; + } + + v1.mTexel[0] = tp1[i1]*TSCALE1; + v1.mTexel[1] = tp1[i2]*TSCALE1; + + v2.mTexel[0] = tp2[i1]*TSCALE1; + v2.mTexel[1] = tp2[i2]*TSCALE1; + + v3.mTexel[0] = tp3[i1]*TSCALE1; + v3.mTexel[1] = tp3[i2]*TSCALE1; + + callback->ConvexHullTriangle(v3,v2,v1); +} + +//================================================================================== +float HullLibrary::ComputeNormal(float *n,const float *A,const float *B,const float *C) +{ + float vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag; + + vx = (B[0] - C[0]); + vy = (B[1] - C[1]); + vz = (B[2] - C[2]); + + wx = (A[0] - B[0]); + wy = (A[1] - B[1]); + wz = (A[2] - B[2]); + + vw_x = vy * wz - vz * wy; + vw_y = vz * wx - vx * wz; + vw_z = vx * wy - vy * wx; + + mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); + + if ( mag < 0.000001f ) + { + mag = 0; + } + else + { + mag = 1.0f/mag; + } + + n[0] = vw_x * mag; + n[1] = vw_y * mag; + n[2] = vw_z * mag; + + return mag; +} + +}; // End of namespace +}; |