2012-09-19 15:15:01 +00:00
/*
NvStanHull . cpp : A convex hull generator written by Stan Melax
*/
/*!
* *
* * Copyright ( c ) 2009 by John W . Ratcliff mailto : jratcliffscarab @ gmail . com
* *
* * Portions of this source has been released with the PhysXViewer application , as well as
* * Rocket , CreateDynamics , ODF , and as a number of sample code snippets .
* *
* * If you find this code useful or you are feeling particularily generous I would
* * ask that you please go to http : //www.amillionpixels.us and make a donation
* * to Troy DeMolay .
* *
* * DeMolay is a youth group for young men between the ages of 12 and 21.
* * It teaches strong moral principles , as well as leadership skills and
* * public speaking . The donations page uses the ' pay for pixels ' paradigm
* * where , in this case , a pixel is only a single penny . Donations can be
* * made for as small as $ 4 or as high as a $ 100 block . Each person who donates
* * will get a link to their own site as well as acknowledgement on the
* * donations blog located here http : //www.amillionpixels.blogspot.com/
* *
* * If you wish to contact me you can use the following methods :
* *
* * Skype ID : jratcliff63367
* * Yahoo : jratcliff63367
* * AOL : jratcliff1961
* * email : jratcliffscarab @ gmail . com
* *
* *
* * The MIT license :
* *
* * Permission is hereby granted , free of charge , to any person obtaining a copy
* * of this software and associated documentation files ( the " Software " ) , to deal
* * in the Software without restriction , including without limitation the rights
* * to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* * copies of the Software , and to permit persons to whom the Software is furnished
* * to do so , subject to the following conditions :
* *
* * The above copyright notice and this permission notice shall be included in all
* * copies or substantial portions of the Software .
* * THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* * IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* * WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <math.h>
# include <float.h>
# include <stdarg.h>
# include <setjmp.h>
# include "NvStanHull.h"
namespace CONVEX_DECOMPOSITION
{
//*****************************************************
//*** DARRAY.H
//*****************************************************
template < class Type > class ArrayRet ;
template < class Type > class Array
{
public :
Array ( NxI32 s = 0 ) ;
Array ( Array < Type > & array ) ;
Array ( ArrayRet < Type > & array ) ;
~ Array ( ) ;
void allocate ( NxI32 s ) ;
void SetSize ( NxI32 s ) ;
void Pack ( ) ;
Type & Add ( Type ) ;
void AddUnique ( Type ) ;
NxI32 Contains ( Type ) ;
void Insert ( Type , NxI32 ) ;
NxI32 IndexOf ( Type ) ;
void Remove ( Type ) ;
void DelIndex ( NxI32 i ) ;
Type * element ;
NxI32 count ;
NxI32 array_size ;
const Type & operator [ ] ( NxI32 i ) const { assert ( i > = 0 & & i < count ) ; return element [ i ] ; }
Type & operator [ ] ( NxI32 i ) { assert ( i > = 0 & & i < count ) ; return element [ i ] ; }
Type & Pop ( ) { assert ( count ) ; count - - ; return element [ count ] ; }
Array < Type > & operator = ( Array < Type > & array ) ;
Array < 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 Array < Type >
{
} ;
template < class Type > Array < Type > : : Array ( NxI32 s )
{
count = 0 ;
array_size = 0 ;
element = NULL ;
if ( s )
{
allocate ( s ) ;
}
}
template < class Type > Array < Type > : : Array ( Array < Type > & array )
{
count = 0 ;
array_size = 0 ;
element = NULL ;
for ( NxI32 i = 0 ; i < array . count ; i + + )
{
Add ( array [ i ] ) ;
}
}
template < class Type > Array < Type > : : Array ( ArrayRet < Type > & array )
{
* this = array ;
}
template < class Type > Array < Type > & Array < 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 > Array < Type > & Array < Type > : : operator = ( Array < Type > & array )
{
count = 0 ;
for ( NxI32 i = 0 ; i < array . count ; i + + )
{
Add ( array [ i ] ) ;
}
return * this ;
}
template < class Type > Array < Type > : : ~ Array ( )
{
if ( element ! = NULL )
{
MEMALLOC_FREE ( element ) ;
}
count = 0 ; array_size = 0 ; element = NULL ;
}
template < class Type > void Array < Type > : : allocate ( NxI32 s )
{
assert ( s > 0 ) ;
assert ( s > = count ) ;
Type * old = element ;
array_size = s ;
element = ( Type * ) MEMALLOC_MALLOC ( sizeof ( Type ) * array_size ) ;
assert ( element ) ;
for ( NxI32 i = 0 ; i < count ; i + + )
{
element [ i ] = old [ i ] ;
}
if ( old )
{
MEMALLOC_FREE ( old ) ;
}
}
template < class Type > void Array < Type > : : SetSize ( NxI32 s )
{
if ( s = = 0 )
{
if ( element )
{
MEMALLOC_FREE ( element ) ;
element = NULL ;
}
array_size = s ;
}
else
{
allocate ( s ) ;
}
count = s ;
}
template < class Type > void Array < Type > : : Pack ( )
{
allocate ( count ) ;
}
template < class Type > Type & Array < Type > : : Add ( Type t )
{
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 > NxI32 Array < Type > : : Contains ( Type t )
{
NxI32 i ;
NxI32 found = 0 ;
for ( i = 0 ; i < count ; i + + )
{
if ( element [ i ] = = t ) found + + ;
}
return found ;
}
template < class Type > void Array < Type > : : AddUnique ( Type t )
{
if ( ! Contains ( t ) ) Add ( t ) ;
}
template < class Type > void Array < Type > : : DelIndex ( NxI32 i )
{
assert ( i < count ) ;
count - - ;
while ( i < count )
{
element [ i ] = element [ i + 1 ] ;
i + + ;
}
}
template < class Type > void Array < Type > : : Remove ( Type t )
{
NxI32 i ;
for ( i = 0 ; i < count ; i + + )
{
if ( element [ i ] = = t )
{
break ;
}
}
assert ( i < count ) ; // assert object t is in the array.
DelIndex ( i ) ;
for ( i = 0 ; i < count ; i + + )
{
assert ( element [ i ] ! = t ) ;
}
}
template < class Type > void Array < Type > : : Insert ( Type t , NxI32 k )
{
NxI32 i = count ;
Add ( t ) ; // to allocate space
while ( i > k )
{
element [ i ] = element [ i - 1 ] ;
i - - ;
}
assert ( i = = k ) ;
element [ k ] = t ;
}
template < class Type > NxI32 Array < Type > : : IndexOf ( Type t )
{
NxI32 i ;
for ( i = 0 ; i < count ; i + + )
{
if ( element [ i ] = = t )
{
return i ;
}
}
assert ( 0 ) ;
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))
NxI32 argmin ( NxF32 a [ ] , NxI32 n ) ;
2023-05-12 09:42:06 +00:00
NxF32 sqr ( NxF32 a ) ;
2012-09-19 15:15:01 +00:00
NxF32 clampf ( NxF32 a ) ;
NxF32 Round ( NxF32 a , NxF32 precision ) ;
NxF32 Interpolate ( const NxF32 & f0 , const NxF32 & f1 , NxF32 alpha ) ;
template < class T >
2023-05-12 09:42:06 +00:00
void Swap ( T & a , T & b )
2012-09-19 15:15:01 +00:00
{
T tmp = a ;
a = b ;
b = tmp ;
}
template < class T >
2023-05-12 09:42:06 +00:00
T Max ( const T & a , const T & b )
2012-09-19 15:15:01 +00:00
{
return ( a > b ) ? a : b ;
}
template < class T >
2023-05-12 09:42:06 +00:00
T Min ( const T & a , const T & b )
2012-09-19 15:15:01 +00:00
{
return ( a < b ) ? a : b ;
}
//----------------------------------
class int3 : public Memalloc
{
public :
NxI32 x , y , z ;
int3 ( ) { } ;
int3 ( NxI32 _x , NxI32 _y , NxI32 _z ) { x = _x ; y = _y ; z = _z ; }
const NxI32 & operator [ ] ( NxI32 i ) const { return ( & x ) [ i ] ; }
NxI32 & operator [ ] ( NxI32 i ) { return ( & x ) [ i ] ; }
} ;
//-------- 2D --------
class float2 : public Memalloc
{
public :
NxF32 x , y ;
float2 ( ) { x = 0 ; y = 0 ; } ;
float2 ( NxF32 _x , NxF32 _y ) { x = _x ; y = _y ; }
NxF32 & operator [ ] ( NxI32 i ) { assert ( i > = 0 & & i < 2 ) ; return ( ( NxF32 * ) this ) [ i ] ; }
const NxF32 & operator [ ] ( NxI32 i ) const { assert ( i > = 0 & & i < 2 ) ; return ( ( NxF32 * ) 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 Memalloc // 3D
{
public :
NxF32 x , y , z ;
float3 ( ) { x = 0 ; y = 0 ; z = 0 ; } ;
float3 ( NxF32 _x , NxF32 _y , NxF32 _z ) { x = _x ; y = _y ; z = _z ; } ;
//operator NxF32 *() { return &x;};
NxF32 & operator [ ] ( NxI32 i ) { assert ( i > = 0 & & i < 3 ) ; return ( ( NxF32 * ) this ) [ i ] ; }
const NxF32 & operator [ ] ( NxI32 i ) const { assert ( i > = 0 & & i < 3 ) ; return ( ( NxF32 * ) this ) [ i ] ; }
} ;
float3 & operator + = ( float3 & a , const float3 & b ) ;
float3 & operator - = ( float3 & a , const float3 & b ) ;
float3 & operator * = ( float3 & v , const NxF32 s ) ;
float3 & operator / = ( float3 & v , const NxF32 s ) ;
NxF32 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 NxF32 s ) ;
float3 operator * ( const NxF32 s , const float3 & v ) ;
float3 operator / ( const float3 & v , const NxF32 s ) ;
inline NxI32 operator = = ( const float3 & a , const float3 & b ) { return ( a . x = = b . x & & a . y = = b . y & & a . z = = b . z ) ; }
inline NxI32 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.
NxF32 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 , NxF32 alpha ) ;
float3 Round ( const float3 & a , NxF32 precision ) ;
float3 VectorMax ( const float3 & a , const float3 & b ) ;
float3 VectorMin ( const float3 & a , const float3 & b ) ;
class float3x3 : public Memalloc
{
public :
float3 x , y , z ; // the 3 rows of the Matrix
float3x3 ( ) { }
float3x3 ( NxF32 xx , NxF32 xy , NxF32 xz , NxF32 yx , NxF32 yy , NxF32 yz , NxF32 zx , NxF32 zy , NxF32 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 [ ] ( NxI32 i ) { assert ( i > = 0 & & i < 3 ) ; return ( & x ) [ i ] ; }
const float3 & operator [ ] ( NxI32 i ) const { assert ( i > = 0 & & i < 3 ) ; return ( & x ) [ i ] ; }
NxF32 & operator ( ) ( NxI32 r , NxI32 c ) { assert ( r > = 0 & & r < 3 & & c > = 0 & & c < 3 ) ; return ( ( & x ) [ r ] ) [ c ] ; }
const NxF32 & operator ( ) ( NxI32 r , NxI32 c ) const { assert ( r > = 0 & & r < 3 & & c > = 0 & & c < 3 ) ; return ( ( & x ) [ r ] ) [ c ] ; }
2023-05-12 09:42:06 +00:00
} ;
2012-09-19 15:15:01 +00:00
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 NxF32 & s ) ;
float3x3 operator * ( const float3x3 & ma , const float3x3 & mb ) ;
float3x3 operator / ( const float3x3 & a , const NxF32 & 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 NxF32 & s ) ;
NxF32 Determinant ( const float3x3 & m ) ;
float3x3 Inverse ( const float3x3 & a ) ; // its just 3x3 so we simply do that cofactor method
//-------- 4D Math --------
class float4 : public Memalloc
{
public :
NxF32 x , y , z , w ;
float4 ( ) { x = 0 ; y = 0 ; z = 0 ; w = 0 ; } ;
float4 ( NxF32 _x , NxF32 _y , NxF32 _z , NxF32 _w ) { x = _x ; y = _y ; z = _z ; w = _w ; }
float4 ( const float3 & v , NxF32 _w ) { x = v . x ; y = v . y ; z = v . z ; w = _w ; }
//operator NxF32 *() { return &x;};
NxF32 & operator [ ] ( NxI32 i ) { assert ( i > = 0 & & i < 4 ) ; return ( ( NxF32 * ) this ) [ i ] ; }
const NxF32 & operator [ ] ( NxI32 i ) const { assert ( i > = 0 & & i < 4 ) ; return ( ( NxF32 * ) this ) [ i ] ; }
const float3 & xyz ( ) const { return * ( ( float3 * ) this ) ; }
float3 & xyz ( ) { return * ( ( float3 * ) this ) ; }
} ;
2023-05-12 09:42:06 +00:00
struct D3DXMATRIX ;
2012-09-19 15:15:01 +00:00
class float4x4 : public Memalloc
{
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 ) { }
2023-05-12 09:42:06 +00:00
float4x4 ( NxF32 m00 , NxF32 m01 , NxF32 m02 , NxF32 m03 ,
NxF32 m10 , NxF32 m11 , NxF32 m12 , NxF32 m13 ,
NxF32 m20 , NxF32 m21 , NxF32 m22 , NxF32 m23 ,
2012-09-19 15:15:01 +00:00
NxF32 m30 , NxF32 m31 , NxF32 m32 , NxF32 m33 )
: x ( m00 , m01 , m02 , m03 ) , y ( m10 , m11 , m12 , m13 ) , z ( m20 , m21 , m22 , m23 ) , w ( m30 , m31 , m32 , m33 ) { }
NxF32 & operator ( ) ( NxI32 r , NxI32 c ) { assert ( r > = 0 & & r < 4 & & c > = 0 & & c < 4 ) ; return ( ( & x ) [ r ] ) [ c ] ; }
const NxF32 & operator ( ) ( NxI32 r , NxI32 c ) const { assert ( r > = 0 & & r < 4 & & c > = 0 & & c < 4 ) ; return ( ( & x ) [ r ] ) [ c ] ; }
operator NxF32 * ( ) { return & x . x ; }
operator const NxF32 * ( ) const { return & x . x ; }
operator struct D3DXMATRIX * ( ) { return ( struct D3DXMATRIX * ) this ; }
operator const struct D3DXMATRIX * ( ) const { return ( struct D3DXMATRIX * ) this ; }
} ;
NxI32 operator = = ( const float4 & a , const float4 & b ) ;
float4 Homogenize ( const float3 & v3 , const NxF32 & 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 , NxF32 s ) ;
float4 operator * ( NxF32 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 ( NxF32 fovy , NxF32 Aspect , NxF32 zn , NxF32 zf ) ;
float4x4 MatrixTranslation ( const float3 & t ) ;
float4x4 MatrixRotationZ ( const NxF32 angle_radians ) ;
float4x4 MatrixLookAt ( const float3 & eye , const float3 & at , const float3 & up ) ;
NxI32 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 , NxF32 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 ( NxF32 _x , NxF32 _y , NxF32 _z , NxF32 _w ) { x = _x ; y = _y ; z = _z ; w = _w ; }
NxF32 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 , NxF32 s ) ;
Quaternion operator * ( const Quaternion & a , NxF32 s ) ;
Quaternion operator * ( const Quaternion & a , const Quaternion & b ) ;
Quaternion operator + ( const Quaternion & a , const Quaternion & b ) ;
Quaternion normalize ( Quaternion a ) ;
NxF32 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 , NxF32 interp ) ;
2023-05-12 09:42:06 +00:00
Quaternion Interpolate ( const Quaternion & q0 , const Quaternion & q1 , NxF32 alpha ) ;
2012-09-19 15:15:01 +00:00
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 ( NxF32 yaw , NxF32 pitch , NxF32 roll ) ;
NxF32 Yaw ( const Quaternion & q ) ;
NxF32 Pitch ( const Quaternion & q ) ;
NxF32 Roll ( Quaternion q ) ;
NxF32 Yaw ( const float3 & v ) ;
NxF32 Pitch ( const float3 & v ) ;
//------- Plane ----------
2023-05-12 09:42:06 +00:00
class Plane
2012-09-19 15:15:01 +00:00
{
public :
float3 normal ;
NxF32 dist ; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
Plane ( const float3 & n , NxF32 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 NxI32 operator = = ( const Plane & a , const Plane & b ) { return ( a . normal = = b . normal & & a . dist = = b . dist ) ; }
inline NxI32 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
NxF32 LineProjectTime ( const float3 & p0 , const float3 & p1 , const float3 & a ) ;
float3 ThreePlaneIntersection ( const Plane & p0 , const Plane & p1 , const Plane & p2 ) ;
NxI32 PolyHit ( const float3 * vert , const NxI32 n , const float3 & v0 , const float3 & v1 , float3 * impact = NULL , float3 * normal = NULL ) ;
NxI32 BoxInside ( const float3 & p , const float3 & bmin , const float3 & bmax ) ;
NxI32 BoxIntersect ( const float3 & v0 , const float3 & v1 , const float3 & bmin , const float3 & bmax , float3 * impact ) ;
NxF32 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 NxI32 n ) ;
Quaternion VirtualTrackBall ( const float3 & cop , const float3 & cor , const float3 & dir0 , const float3 & dir1 ) ;
//*****************************************************
// ** VECMATH.CPP
//*****************************************************
NxF32 sqr ( NxF32 a ) { return a * a ; }
NxF32 clampf ( NxF32 a ) { return Min ( 1.0f , Max ( 0.0f , a ) ) ; }
NxF32 Round ( NxF32 a , NxF32 precision )
{
return floorf ( 0.5f + a / precision ) * precision ;
}
2023-05-12 09:42:06 +00:00
NxF32 Interpolate ( const NxF32 & f0 , const NxF32 & f1 , NxF32 alpha )
2012-09-19 15:15:01 +00:00
{
return f0 * ( 1 - alpha ) + f1 * alpha ;
}
NxI32 argmin ( NxF32 a [ ] , NxI32 n )
{
NxI32 r = 0 ;
2023-05-12 09:42:06 +00:00
for ( NxI32 i = 1 ; i < n ; i + + )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
if ( a [ i ] < a [ r ] )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
r = i ;
2012-09-19 15:15:01 +00:00
}
}
return r ;
}
//------------ float3 (3D) --------------
2023-05-12 09:42:06 +00:00
float3 operator + ( const float3 & a , const float3 & b )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return float3 ( a . x + b . x , a . y + b . y , a . z + b . z ) ;
2012-09-19 15:15:01 +00:00
}
float3 operator - ( const float3 & a , const float3 & b )
{
2023-05-12 09:42:06 +00:00
return float3 ( a . x - b . x , a . y - b . y , a . z - b . z ) ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
float3 operator - ( const float3 & v )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return float3 ( - v . x , - v . y , - v . z ) ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
float3 operator * ( const float3 & v , NxF32 s )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return float3 ( v . x * s , v . y * s , v . z * s ) ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
float3 operator * ( NxF32 s , const float3 & v )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return float3 ( v . x * s , v . y * s , v . z * s ) ;
2012-09-19 15:15:01 +00:00
}
float3 operator / ( const float3 & v , NxF32 s )
2023-05-12 09:42:06 +00:00
{
return v * ( 1.0f / s ) ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
NxF32 dot ( const float3 & a , const float3 & b )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return a . x * b . x + a . y * b . y + a . z * b . z ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
float3 cmul ( const float3 & v1 , const float3 & v2 )
{
return float3 ( v1 . x * v2 . x , v1 . y * v2 . y , v1 . z * v2 . z ) ;
2012-09-19 15:15:01 +00:00
}
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 , NxF32 s )
{
v . x * = s ;
v . y * = s ;
v . z * = s ;
return v ;
}
float3 & operator / = ( float3 & v , NxF32 s )
{
NxF32 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 ) ) ;
}
NxF32 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!!
NxF32 d = magnitude ( v ) ;
2023-05-12 09:42:06 +00:00
if ( d = = 0 )
2012-09-19 15:15:01 +00:00
{
printf ( " Cant normalize ZERO vector \n " ) ;
assert ( 0 ) ; // 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 , NxF32 precision )
{
return float3 ( Round ( a . x , precision ) , Round ( a . y , precision ) , Round ( a . z , precision ) ) ;
}
2023-05-12 09:42:06 +00:00
float3 Interpolate ( const float3 & v0 , const float3 & v1 , NxF32 alpha )
2012-09-19 15:15:01 +00:00
{
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.
2023-05-12 09:42:06 +00:00
// So we will never see: float3 operator*(float3 a,float3 b)
2012-09-19 15:15:01 +00:00
//------------ float3x3 ---------------
NxF32 Determinant ( const float3x3 & m )
{
2023-05-12 09:42:06 +00:00
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
2012-09-19 15:15:01 +00:00
- 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 ;
NxF32 d = Determinant ( a ) ;
assert ( d ! = 0 ) ;
2023-05-12 09:42:06 +00:00
for ( NxI32 i = 0 ; i < 3 ; i + + )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
for ( NxI32 j = 0 ; j < 3 ; j + + )
2012-09-19 15:15:01 +00:00
{
NxI32 i1 = ( i + 1 ) % 3 ;
NxI32 i2 = ( i + 2 ) % 3 ;
NxI32 j1 = ( j + 1 ) % 3 ;
NxI32 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 ) {
2023-05-12 09:42:06 +00:00
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 ) ,
2012-09-19 15:15:01 +00:00
( m . x . z * v . x + m . y . z * v . y + m . z . z * v . z ) ) ;
}
2023-05-12 09:42:06 +00:00
float3 operator * ( const float3x3 & m , const float3 & v ) {
2012-09-19 15:15:01 +00:00
return float3 ( dot ( m . x , v ) , dot ( m . y , v ) , dot ( m . z , v ) ) ;
}
2023-05-12 09:42:06 +00:00
float3x3 operator * ( const float3x3 & a , const float3x3 & b )
{
2012-09-19 15:15:01 +00:00
return float3x3 ( a . x * b , a . y * b , a . z * b ) ;
}
2023-05-12 09:42:06 +00:00
float3x3 operator * ( const float3x3 & a , const NxF32 & s )
{
return float3x3 ( a . x * s , a . y * s , a . z * s ) ;
2012-09-19 15:15:01 +00:00
}
2023-05-12 09:42:06 +00:00
float3x3 operator / ( const float3x3 & a , const NxF32 & s )
{
2012-09-19 15:15:01 +00:00
NxF32 t = 1 / s ;
2023-05-12 09:42:06 +00:00
return float3x3 ( a . x * t , a . y * t , a . z * t ) ;
2012-09-19 15:15:01 +00:00
}
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 NxF32 & 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
}
2023-05-12 09:42:06 +00:00
NxI32 operator = = ( const float4 & a , const float4 & b )
2012-09-19 15:15:01 +00:00
{
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));
//}
2023-05-12 09:42:06 +00:00
float4 cmul ( const float4 & a , const float4 & b )
2012-09-19 15:15:01 +00:00
{
return float4 ( a . x * b . x , a . y * b . y , a . z * b . z , a . w * b . w ) ;
}
2023-05-12 09:42:06 +00:00
float4 operator * ( const float4 & v , NxF32 s )
2012-09-19 15:15:01 +00:00
{
return float4 ( v . x * s , v . y * s , v . z * s , v . w * s ) ;
}
2023-05-12 09:42:06 +00:00
float4 operator * ( NxF32 s , const float4 & v )
2012-09-19 15:15:01 +00:00
{
return float4 ( v . x * s , v . y * s , v . z * s , v . w * s ) ;
}
2023-05-12 09:42:06 +00:00
float4 operator + ( const float4 & a , const float4 & b )
2012-09-19 15:15:01 +00:00
{
return float4 ( a . x + b . x , a . y + b . y , a . z + b . z , a . w + b . w ) ;
}
2023-05-12 09:42:06 +00:00
float4 operator - ( const float4 & a , const float4 & b )
2012-09-19 15:15:01 +00:00
{
return float4 ( a . x - b . x , a . y - b . y , a . z - b . z , a . w - b . w ) ;
}
float4 Homogenize ( const float3 & v3 , const NxF32 & 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 ( NxF32 fovy , NxF32 aspect , NxF32 zn , NxF32 zf )
{
NxF32 h = 1.0f / tanf ( fovy / 2.0f ) ; // view space height
NxF32 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 NxF32 angle_radians )
{
NxF32 s = sinf ( angle_radians ) ;
NxF32 c = cosf ( angle_radians ) ;
return float4x4 (
c , s , 0 , 0 ,
- s , c , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
}
NxI32 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 ;
NxF32 * dst = & d . x . x ;
NxF32 tmp [ 12 ] ; /* temp array for pairs */
NxF32 src [ 16 ] ; /* array of transpose source matrix */
NxF32 det ; /* determinant */
/* transpose matrix */
for ( NxI32 i = 0 ; i < 4 ; i + + ) {
src [ i ] = m ( i , 0 ) ;
src [ i + 4 ] = m ( i , 1 ) ;
src [ i + 8 ] = m ( i , 2 ) ;
2023-05-12 09:42:06 +00:00
src [ i + 12 ] = m ( i , 3 ) ;
2012-09-19 15:15:01 +00:00
}
/* 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 ( NxI32 j = 0 ; j < 16 ; j + + )
dst [ j ] * = det ;
return d ;
}
//--------- Quaternion --------------
2023-05-12 09:42:06 +00:00
2012-09-19 15:15:01 +00:00
Quaternion operator * ( const Quaternion & a , const Quaternion & b )
{
Quaternion c ;
2023-05-12 09:42:06 +00:00
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 ;
2012-09-19 15:15:01 +00:00
return c ;
}
Quaternion operator * ( const Quaternion & a , NxF32 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 NxF32 s )
{
q . x * = s ;
q . y * = s ;
q . z * = s ;
q . w * = s ;
return q ;
}
void Quaternion : : Normalize ( )
{
NxF32 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 )
{
2023-05-12 09:42:06 +00:00
// The following is equivalent to:
//return (q.getmatrix() * v);
2012-09-19 15:15:01 +00:00
NxF32 qx2 = q . x * q . x ;
NxF32 qy2 = q . y * q . y ;
NxF32 qz2 = q . z * q . z ;
NxF32 qxqy = q . x * q . y ;
NxF32 qxqz = q . x * q . z ;
NxF32 qxqw = q . x * q . w ;
NxF32 qyqz = q . y * q . z ;
NxF32 qyqw = q . y * q . w ;
NxF32 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 ) ;
}
NxF32 dot ( const Quaternion & a , const Quaternion & b )
{
2023-05-12 09:42:06 +00:00
return ( a . w * b . w + a . x * b . x + a . y * b . y + a . z * b . z ) ;
2012-09-19 15:15:01 +00:00
}
Quaternion normalize ( Quaternion a )
{
NxF32 m = sqrtf ( sqr ( a . w ) + sqr ( a . x ) + sqr ( a . y ) + sqr ( a . z ) ) ;
2023-05-12 09:42:06 +00:00
if ( m < 0.000000001 )
{
2012-09-19 15:15:01 +00:00
a . w = 1 ;
a . x = a . y = a . z = 0 ;
return a ;
}
return a * ( 1 / m ) ;
}
Quaternion slerp ( Quaternion a , const Quaternion & b , NxF32 interp )
{
2023-05-12 09:42:06 +00:00
if ( dot ( a , b ) < 0.0 )
2012-09-19 15:15:01 +00:00
{
a . w = - a . w ;
a . x = - a . x ;
a . y = - a . y ;
a . z = - a . z ;
}
NxF32 d = dot ( a , b ) ;
if ( d > = 1.0 ) {
return a ;
}
NxF32 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 , NxF32 alpha ) {
return slerp ( q0 , q1 , alpha ) ;
}
2023-05-12 09:42:06 +00:00
Quaternion YawPitchRoll ( NxF32 yaw , NxF32 pitch , NxF32 roll )
2012-09-19 15:15:01 +00:00
{
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 ) ;
}
NxF32 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 ;
}
NxF32 Pitch ( const Quaternion & q )
{
static float3 v ;
v = q . ydir ( ) ;
return atan2f ( v . z , sqrtf ( sqr ( v . x ) + sqr ( v . y ) ) ) * RAD2DEG ;
}
NxF32 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 ;
}
NxF32 Yaw ( const float3 & v )
{
return ( v . y = = 0.0 & & v . x = = 0.0 ) ? 0.0f : atan2f ( - v . x , v . y ) * RAD2DEG ;
}
NxF32 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 ) {
2023-05-12 09:42:06 +00:00
// Transforms the plane to the space defined by the
2012-09-19 15:15:01 +00:00
// 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 ) ;
NxF32 d = dot ( v0 , v1 ) ;
if ( d < = - 1.0f ) { return Quaternion ( 1 , 0 , 0 , 0 ) ; } // 180 about x axis
NxF32 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 ;
}
2023-05-12 09:42:06 +00:00
float4x4 MatrixFromQuatVec ( const Quaternion & q , const float3 & v )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
// builds a 4x4 transformation matrix based on orientation q and translation v
2012-09-19 15:15:01 +00:00
NxF32 qx2 = q . x * q . x ;
NxF32 qy2 = q . y * q . y ;
NxF32 qz2 = q . z * q . z ;
NxF32 qxqy = q . x * q . y ;
NxF32 qxqz = q . x * q . z ;
NxF32 qxqw = q . x * q . w ;
NxF32 qyqz = q . y * q . z ;
NxF32 qyqw = q . y * q . w ;
NxF32 qzqw = q . z * q . w ;
return float4x4 (
2023-05-12 09:42:06 +00:00
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 ,
2012-09-19 15:15:01 +00:00
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 ;
NxF32 dn = dot ( plane . normal , dif ) ;
NxF32 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 ;
NxF32 t = dot ( w , ( a - p0 ) ) / ( sqr ( w . x ) + sqr ( w . y ) + sqr ( w . z ) ) ;
return p0 + w * t ;
}
NxF32 LineProjectTime ( const float3 & p0 , const float3 & p1 , const float3 & a )
{
float3 w ;
w = p1 - p0 ;
NxF32 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 ) ;
NxF32 m = magnitude ( cp ) ;
if ( m = = 0 ) return float3 ( 1 , 0 , 0 ) ;
return cp * ( 1.0f / m ) ;
}
2023-05-12 09:42:06 +00:00
NxI32 BoxInside ( const float3 & p , const float3 & bmin , const float3 & bmax )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
return ( p . x > = bmin . x & & p . x < = bmax . x & &
p . y > = bmin . y & & p . y < = bmax . y & &
2012-09-19 15:15:01 +00:00
p . z > = bmin . z & & p . z < = bmax . z ) ;
}
NxI32 BoxIntersect ( const float3 & v0 , const float3 & v1 , const float3 & bmin , const float3 & bmax , float3 * impact )
{
if ( BoxInside ( v0 , bmin , bmax ) )
{
* impact = v0 ;
return 1 ;
}
2023-05-12 09:42:06 +00:00
if ( v0 . x < = bmin . x & & v1 . x > = bmin . x )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmin . x - v0 . x ) / ( v1 . x - v0 . x ) ;
//v.x = bmin.x;
NxF32 vy = ( 1 - a ) * v0 . y + a * v1 . y ;
NxF32 vz = ( 1 - a ) * v0 . z + a * v1 . z ;
2023-05-12 09:42:06 +00:00
if ( vy > = bmin . y & & vy < = bmax . y & & vz > = bmin . z & & vz < = bmax . z )
2012-09-19 15:15:01 +00:00
{
impact - > x = bmin . x ;
impact - > y = vy ;
impact - > z = vz ;
return 1 ;
}
}
2023-05-12 09:42:06 +00:00
else if ( v0 . x > = bmax . x & & v1 . x < = bmax . x )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmax . x - v0 . x ) / ( v1 . x - v0 . x ) ;
//v.x = bmax.x;
NxF32 vy = ( 1 - a ) * v0 . y + a * v1 . y ;
NxF32 vz = ( 1 - a ) * v0 . z + a * v1 . z ;
2023-05-12 09:42:06 +00:00
if ( vy > = bmin . y & & vy < = bmax . y & & vz > = bmin . z & & vz < = bmax . z )
2012-09-19 15:15:01 +00:00
{
impact - > x = bmax . x ;
impact - > y = vy ;
impact - > z = vz ;
return 1 ;
}
}
2023-05-12 09:42:06 +00:00
if ( v0 . y < = bmin . y & & v1 . y > = bmin . y )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmin . y - v0 . y ) / ( v1 . y - v0 . y ) ;
NxF32 vx = ( 1 - a ) * v0 . x + a * v1 . x ;
//v.y = bmin.y;
NxF32 vz = ( 1 - a ) * v0 . z + a * v1 . z ;
2023-05-12 09:42:06 +00:00
if ( vx > = bmin . x & & vx < = bmax . x & & vz > = bmin . z & & vz < = bmax . z )
2012-09-19 15:15:01 +00:00
{
impact - > x = vx ;
impact - > y = bmin . y ;
impact - > z = vz ;
return 1 ;
}
}
2023-05-12 09:42:06 +00:00
else if ( v0 . y > = bmax . y & & v1 . y < = bmax . y )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmax . y - v0 . y ) / ( v1 . y - v0 . y ) ;
NxF32 vx = ( 1 - a ) * v0 . x + a * v1 . x ;
// vy = bmax.y;
NxF32 vz = ( 1 - a ) * v0 . z + a * v1 . z ;
2023-05-12 09:42:06 +00:00
if ( vx > = bmin . x & & vx < = bmax . x & & vz > = bmin . z & & vz < = bmax . z )
2012-09-19 15:15:01 +00:00
{
impact - > x = vx ;
impact - > y = bmax . y ;
impact - > z = vz ;
return 1 ;
}
}
2023-05-12 09:42:06 +00:00
if ( v0 . z < = bmin . z & & v1 . z > = bmin . z )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmin . z - v0 . z ) / ( v1 . z - v0 . z ) ;
NxF32 vx = ( 1 - a ) * v0 . x + a * v1 . x ;
NxF32 vy = ( 1 - a ) * v0 . y + a * v1 . y ;
// v.z = bmin.z;
2023-05-12 09:42:06 +00:00
if ( vy > = bmin . y & & vy < = bmax . y & & vx > = bmin . x & & vx < = bmax . x )
2012-09-19 15:15:01 +00:00
{
impact - > x = vx ;
impact - > y = vy ;
impact - > z = bmin . z ;
return 1 ;
}
}
2023-05-12 09:42:06 +00:00
else if ( v0 . z > = bmax . z & & v1 . z < = bmax . z )
2012-09-19 15:15:01 +00:00
{
NxF32 a = ( bmax . z - v0 . z ) / ( v1 . z - v0 . z ) ;
NxF32 vx = ( 1 - a ) * v0 . x + a * v1 . x ;
NxF32 vy = ( 1 - a ) * v0 . y + a * v1 . y ;
// v.z = bmax.z;
2023-05-12 09:42:06 +00:00
if ( vy > = bmin . y & & vy < = bmax . y & & vx > = bmin . x & & vx < = bmax . x )
2012-09-19 15:15:01 +00:00
{
impact - > x = vx ;
impact - > y = vy ;
impact - > z = bmax . z ;
return 1 ;
}
}
return 0 ;
}
NxF32 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 ) ) ;
NxF32 distu = - dot ( cp , ustart ) ;
NxF32 distv = - dot ( cp , vstart ) ;
NxF32 dist = ( NxF32 ) fabs ( distu - distv ) ;
2023-05-12 09:42:06 +00:00
if ( upoint )
2012-09-19 15:15:01 +00:00
{
Plane plane ;
plane . normal = normalize ( cross ( vdir , cp ) ) ;
plane . dist = - dot ( plane . normal , vstart ) ;
* upoint = PlaneLineIntersection ( plane , ustart , ustart + udir ) ;
}
2023-05-12 09:42:06 +00:00
if ( vpoint )
2012-09-19 15:15:01 +00:00
{
Plane plane ;
plane . normal = normalize ( cross ( udir , cp ) ) ;
plane . dist = - dot ( plane . normal , ustart ) ;
* vpoint = PlaneLineIntersection ( plane , vstart , vstart + vdir ) ;
}
return dist ;
}
2023-05-12 09:42:06 +00:00
Quaternion VirtualTrackBall ( const float3 & cop , const float3 & cor , const float3 & dir1 , const float3 & dir2 )
2012-09-19 15:15:01 +00:00
{
// routine taken from game programming gems.
// Implement track ball functionality to spin stuf on the screen
// cop center of projection
// cor center of rotation
2023-05-12 09:42:06 +00:00
// dir1 old mouse direction
2012-09-19 15:15:01 +00:00
// 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.
NxF32 m ;
2023-05-12 09:42:06 +00:00
// compute plane
2012-09-19 15:15:01 +00:00
float3 nrml = cor - cop ;
NxF32 fudgefactor = 1.0f / ( magnitude ( nrml ) * 0.25f ) ; // since trackball proportional to distance from cop
nrml = normalize ( nrml ) ;
NxF32 dist = - dot ( nrml , cor ) ;
float3 u = PlaneLineIntersection ( Plane ( nrml , dist ) , cop , cop + dir1 ) ;
u = u - cor ;
u = u * fudgefactor ;
m = magnitude ( u ) ;
2023-05-12 09:42:06 +00:00
if ( m > 1 )
2012-09-19 15:15:01 +00:00
{
u / = m ;
}
2023-05-12 09:42:06 +00:00
else
2012-09-19 15:15:01 +00:00
{
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 ) ;
2023-05-12 09:42:06 +00:00
if ( m > 1 )
2012-09-19 15:15:01 +00:00
{
v / = m ;
}
else
{
v = v - ( nrml * sqrtf ( 1 - m * m ) ) ;
}
return RotationArc ( u , v ) ;
}
NxI32 countpolyhit = 0 ;
NxI32 PolyHit ( const float3 * vert , const NxI32 n , const float3 & v0 , const float3 & v1 , float3 * impact , float3 * normal )
{
countpolyhit + + ;
NxI32 i ;
float3 nrml ( 0 , 0 , 0 ) ;
2023-05-12 09:42:06 +00:00
for ( i = 0 ; i < n ; i + + )
2012-09-19 15:15:01 +00:00
{
NxI32 i1 = ( i + 1 ) % n ;
NxI32 i2 = ( i + 2 ) % n ;
nrml = nrml + cross ( vert [ i1 ] - vert [ i ] , vert [ i2 ] - vert [ i1 ] ) ;
}
NxF32 m = magnitude ( nrml ) ;
if ( m = = 0.0 )
{
return 0 ;
}
nrml = nrml * ( 1.0f / m ) ;
NxF32 dist = - dot ( nrml , vert [ 0 ] ) ;
NxF32 d0 , d1 ;
2023-05-12 09:42:06 +00:00
if ( ( d0 = dot ( v0 , nrml ) + dist ) < 0 | | ( d1 = dot ( v1 , nrml ) + dist ) > 0 )
{
2012-09-19 15:15:01 +00:00
return 0 ;
}
2023-05-12 09:42:06 +00:00
static float3 the_point ;
2012-09-19 15:15:01 +00:00
// By using the cached plane distances d0 and d1
// we can optimize the following:
// the_point = planelineintersection(nrml,dist,v0,v1);
NxF32 a = d0 / ( d0 - d1 ) ;
the_point = v0 * ( 1 - a ) + v1 * a ;
NxI32 inside = 1 ;
2023-05-12 09:42:06 +00:00
for ( NxI32 j = 0 ; inside & & j < n ; j + + )
2012-09-19 15:15:01 +00:00
{
// 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 ) ;
}
2023-05-12 09:42:06 +00:00
if ( inside )
2012-09-19 15:15:01 +00:00
{
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 = 0 ;
mIndices = 0 ;
}
NxU32 mVcount ;
NxU32 mIndexCount ;
NxU32 mFaceCount ;
NxF32 * mVertices ;
NxU32 * mIndices ;
} ;
bool ComputeHull ( NxU32 vcount , const NxF32 * vertices , PHullResult & result , NxU32 maxverts , NxF32 inflate ) ;
void ReleaseHull ( PHullResult & result ) ;
//*****************************************************
// HULL.cpp source code goes here
//*****************************************************
# define REAL3 float3
# define REAL NxF32
# define COPLANAR (0)
# define UNDER (1)
# define OVER (2)
# define SPLIT (OVER|UNDER)
# define PAPERWIDTH (0.001f)
# define VOLUME_EPSILON (1e-20f)
NxF32 planetestepsilon = PAPERWIDTH ;
class ConvexH : public Memalloc
{
public :
class HalfEdge
{
public :
short ea ; // the other half of the edge (index into edges list)
NxU8 v ; // the vertex at the start of this edge (index into vertices list)
NxU8 p ; // the facet on which this edge lies (index into facets list)
HalfEdge ( ) { }
HalfEdge ( short _ea , NxU8 _v , NxU8 _p ) : ea ( _ea ) , v ( _v ) , p ( _p ) { }
} ;
Array < REAL3 > vertices ;
Array < HalfEdge > edges ;
Array < Plane > facets ;
ConvexH ( NxI32 vertices_size , NxI32 edges_size , NxI32 facets_size ) ;
} ;
typedef ConvexH : : HalfEdge HalfEdge ;
ConvexH : : ConvexH ( NxI32 vertices_size , NxI32 edges_size , NxI32 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 = MEMALLOC_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 ;
}
NxI32 PlaneTest ( const Plane & p , const REAL3 & v ) {
REAL a = dot ( v , p . normal ) + p . dist ;
NxI32 flag = ( a > planetestepsilon ) ? OVER : ( ( a < - planetestepsilon ) ? UNDER : COPLANAR ) ;
return flag ;
}
NxI32 SplitTest ( ConvexH & convex , const Plane & plane ) {
NxI32 flag = 0 ;
for ( NxI32 i = 0 ; i < convex . vertices . count ; i + + ) {
flag | = PlaneTest ( plane , convex . vertices [ i ] ) ;
}
return flag ;
}
2023-05-12 09:42:06 +00:00
class VertFlag
2012-09-19 15:15:01 +00:00
{
public :
NxU8 planetest ;
NxU8 junk ;
NxU8 undermap ;
NxU8 overmap ;
} ;
2023-05-12 09:42:06 +00:00
class EdgeFlag
2012-09-19 15:15:01 +00:00
{
public :
NxU8 planetest ;
NxU8 fixes ;
short undermap ;
short overmap ;
} ;
2023-05-12 09:42:06 +00:00
class PlaneFlag
2012-09-19 15:15:01 +00:00
{
public :
NxU8 undermap ;
NxU8 overmap ;
} ;
class Coplanar {
public :
unsigned short ea ;
NxU8 v0 ;
NxU8 v1 ;
} ;
NxI32 AssertIntact ( ConvexH & convex ) {
NxI32 i ;
NxI32 estart = 0 ;
for ( i = 0 ; i < convex . edges . count ; i + + ) {
if ( convex . edges [ estart ] . p ! = convex . edges [ i ] . p ) {
estart = i ;
}
NxI32 inext = i + 1 ;
if ( inext > = convex . edges . count | | convex . edges [ inext ] . p ! = convex . edges [ i ] . p ) {
inext = estart ;
}
assert ( convex . edges [ inext ] . p = = convex . edges [ i ] . p ) ;
NxI32 nb = convex . edges [ i ] . ea ;
assert ( nb ! = 255 ) ;
if ( nb = = 255 | | nb = = - 1 ) return 0 ;
assert ( nb ! = - 1 ) ;
assert ( i = = convex . edges [ nb ] . ea ) ;
}
for ( i = 0 ; i < convex . edges . count ; i + + ) {
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 ;
}
NxI32 i1 = i + 1 ;
if ( i1 > = convex . edges . count | | convex . edges [ i1 ] . p ! = convex . edges [ i ] . p ) {
i1 = estart ;
}
NxI32 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 ] ) ;
//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 )
{
NxI32 i ;
NxI32 vertcountunder = 0 ;
NxI32 vertcountover = 0 ;
static Array < NxI32 > vertscoplanar ; // existing vertex members of convex that are coplanar
vertscoplanar . count = 0 ;
static Array < NxI32 > edgesplit ; // existing edges that members of convex that cross the splitplane
edgesplit . count = 0 ;
assert ( convex . edges . count < 480 ) ;
EdgeFlag edgeflag [ 512 ] ;
VertFlag vertflag [ 256 ] ;
PlaneFlag planeflag [ 128 ] ;
HalfEdge tmpunderedges [ 512 ] ;
Plane tmpunderplanes [ 128 ] ;
Coplanar coplanaredges [ 512 ] ;
NxI32 coplanaredges_num = 0 ;
Array < REAL3 > createdverts ;
// do the side-of-plane tests
for ( i = 0 ; i < convex . vertices . count ; i + + ) {
vertflag [ i ] . planetest = ( NxU8 ) PlaneTest ( slice , convex . vertices [ i ] ) ;
if ( vertflag [ i ] . planetest = = COPLANAR ) {
// ? vertscoplanar.Add(i);
vertflag [ i ] . undermap = ( NxU8 ) vertcountunder + + ;
vertflag [ i ] . overmap = ( NxU8 ) vertcountover + + ;
}
else if ( vertflag [ i ] . planetest = = UNDER ) {
vertflag [ i ] . undermap = ( NxU8 ) vertcountunder + + ;
}
else {
assert ( vertflag [ i ] . planetest = = OVER ) ;
vertflag [ i ] . overmap = ( NxU8 ) vertcountover + + ;
vertflag [ i ] . undermap = ( NxU8 ) - 1 ; // for debugging purposes
}
}
NxI32 under_edge_count = 0 ;
NxI32 underplanescount = 0 ;
NxI32 e0 = 0 ;
for ( NxI32 currentplane = 0 ; currentplane < convex . facets . count ; currentplane + + ) {
NxI32 estart = e0 ;
NxI32 enextface = 0 ;
NxI32 planeside = 0 ;
NxI32 e1 = e0 + 1 ;
NxI32 vout = - 1 ;
NxI32 vin = - 1 ;
NxI32 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) {
// 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
2023-05-12 09:42:06 +00:00
2012-09-19 15:15:01 +00:00
edgeflag [ e0 ] . undermap = ( short ) under_edge_count ;
tmpunderedges [ under_edge_count ] . v = ( NxU8 ) vertflag [ edge0 . v ] . undermap ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) underplanescount ;
if ( edge0 . ea < e0 ) {
// connect the neighbors
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 ) {
2023-05-12 09:42:06 +00:00
// both endpoints coplanar
2012-09-19 15:15:01 +00:00
// must check a 3rd point to see if UNDER
2023-05-12 09:42:06 +00:00
NxI32 e2 = e1 + 1 ;
2012-09-19 15:15:01 +00:00
if ( e2 > = convex . edges . count | | convex . edges [ e2 ] . p ! = currentplane ) {
e2 = estart ;
}
assert ( convex . edges [ e2 ] . p = = currentplane ) ;
HalfEdge & edge2 = convex . edges [ e2 ] ;
if ( vertflag [ edge2 . v ] . planetest = = UNDER ) {
2023-05-12 09:42:06 +00:00
2012-09-19 15:15:01 +00:00
edgeflag [ e0 ] . undermap = ( short ) under_edge_count ;
tmpunderedges [ under_edge_count ] . v = ( NxU8 ) vertflag [ edge0 . v ] . undermap ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) 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 ) {
2023-05-12 09:42:06 +00:00
// first is under 2nd is over
2012-09-19 15:15:01 +00:00
edgeflag [ e0 ] . undermap = ( short ) under_edge_count ;
tmpunderedges [ under_edge_count ] . v = ( NxU8 ) vertflag [ edge0 . v ] . undermap ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) underplanescount ;
if ( edge0 . ea < e0 ) {
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 + + ;
2023-05-12 09:42:06 +00:00
/// hmmm something to think about: i might be able to output this edge regarless of
2012-09-19 15:15:01 +00:00
// wheter or not we know v-in yet. ok i;ll try this now:
tmpunderedges [ under_edge_count ] . v = ( NxU8 ) vout ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) 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 ) {
2023-05-12 09:42:06 +00:00
// first is coplanar 2nd is over
2012-09-19 15:15:01 +00:00
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
NxI32 k = estart ;
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 = ( NxU8 ) vout ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) 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 + + ;
2023-05-12 09:42:06 +00:00
2012-09-19 15:15:01 +00:00
}
}
else if ( vertflag [ edge0 . v ] . planetest = = OVER & & vertflag [ edge1 . v ] . planetest = = UNDER ) {
2023-05-12 09:42:06 +00:00
// first is over next is under
2012-09-19 15:15:01 +00:00
// 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]
NxI32 nea = edgeflag [ edge0 . ea ] . undermap ;
assert ( tmpunderedges [ nea ] . p = = tmpunderedges [ nea + 1 ] . p ) ;
vin = tmpunderedges [ nea + 1 ] . v ;
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 = ( NxU8 ) vin ;
tmpunderedges [ under_edge_count ] . p = ( NxU8 ) underplanescount ;
edgeflag [ e0 ] . undermap = ( short ) under_edge_count ;
if ( e0 > edge0 . ea ) {
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 ;
}
assert ( edgeflag [ e0 ] . undermap = = under_edge_count ) ;
under_edge_count + + ;
}
else if ( vertflag [ edge0 . v ] . planetest = = OVER & & vertflag [ edge1 . v ] . planetest = = COPLANAR ) {
2023-05-12 09:42:06 +00:00
// first is over next is coplanar
2012-09-19 15:15:01 +00:00
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 {
assert ( 0 ) ;
}
2023-05-12 09:42:06 +00:00
2012-09-19 15:15:01 +00:00
e0 = e1 ;
e1 + + ; // do the modulo at the beginning of the loop
} while ( e0 ! = estart ) ;
e0 = enextface ;
if ( planeside & UNDER ) {
planeflag [ currentplane ] . undermap = ( NxU8 ) underplanescount ;
tmpunderplanes [ underplanescount ] = convex . facets [ currentplane ] ;
underplanescount + + ;
}
else {
planeflag [ currentplane ] . undermap = 0 ;
}
if ( vout > = 0 & & ( planeside & UNDER ) ) {
assert ( vin > = 0 ) ;
assert ( coplanaredge > = 0 ) ;
assert ( coplanaredge ! = 511 ) ;
coplanaredges [ coplanaredges_num ] . ea = ( short ) coplanaredge ;
coplanaredges [ coplanaredges_num ] . v0 = ( NxU8 ) vin ;
coplanaredges [ coplanaredges_num ] . v1 = ( NxU8 ) 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 ) {
NxI32 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 )
{
// assert(j<coplanaredges_num);
return NULL ;
}
}
}
ConvexH * punder = MEMALLOC_NEW ( ConvexH ) ( vertcountunder , under_edge_count + coplanaredges_num , underplanescount ) ;
ConvexH & under = * punder ;
NxI32 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 + + ] ;
}
assert ( i = = createdverts . count ) ;
for ( i = 0 ; i < coplanaredges_num ; i + + ) {
under . edges [ under_edge_count + i ] . p = ( NxU8 ) ( underplanescount - 1 ) ;
under . edges [ under_edge_count + i ] . ea = 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 ) ;
return punder ;
}
NxF32 minadjangle = 3.0f ; // in degrees - result wont have two adjacent facets within this angle of each other.
static NxI32 candidateplane ( Plane * planes , NxI32 planes_count , ConvexH * convex , NxF32 epsilon )
{
NxI32 p = - 1 ;
REAL md = 0 ;
NxI32 i , j ;
NxF32 maxdot_minang = cosf ( DEG2RAD * minadjangle ) ;
for ( i = 0 ; i < planes_count ; i + + )
{
NxF32 d = 0 ;
NxF32 dmax = 0 ;
NxF32 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 ) ;
}
NxF32 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 + + )
{
2023-05-12 09:42:06 +00:00
if ( planes [ i ] = = convex - > facets [ j ] )
2012-09-19 15:15:01 +00:00
{
d = 0 ; continue ;
}
if ( dot ( planes [ i ] . normal , convex - > facets [ j ] . normal ) > maxdot_minang )
{
for ( NxI32 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 NxI32 maxdir ( const T * p , NxI32 count , const T & dir )
{
assert ( count ) ;
NxI32 m = 0 ;
for ( NxI32 i = 1 ; i < count ; i + + )
{
if ( dot ( p [ i ] , dir ) > dot ( p [ m ] , dir ) ) m = i ;
}
return m ;
}
template < class T >
NxI32 maxdirfiltered ( const T * p , NxI32 count , const T & dir , Array < NxI32 > & allow )
{
assert ( count ) ;
NxI32 m = - 1 ;
for ( NxI32 i = 0 ; i < count ; i + + ) if ( allow [ i ] )
{
if ( m = = - 1 | | dot ( p [ i ] , dir ) > dot ( p [ m ] , dir ) ) m = i ;
}
assert ( m ! = - 1 ) ;
return m ;
2023-05-12 09:42:06 +00:00
}
2012-09-19 15:15:01 +00:00
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 >
NxI32 maxdirsterid ( const T * p , NxI32 count , const T & dir , Array < NxI32 > & allow )
{
NxI32 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 ) ;
NxI32 ma = - 1 ;
for ( NxF32 x = 0.0f ; x < = 360.0f ; x + = 45.0f )
{
NxF32 s = sinf ( DEG2RAD * ( x ) ) ;
NxF32 c = cosf ( DEG2RAD * ( x ) ) ;
NxI32 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
{
NxI32 mc = ma ;
for ( NxF32 xx = x - 40.0f ; xx < = x ; xx + = 5.0f )
{
NxF32 s = sinf ( DEG2RAD * ( xx ) ) ;
NxF32 c = cosf ( DEG2RAD * ( xx ) ) ;
NxI32 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 ;
}
assert ( 0 ) ;
return m ;
2023-05-12 09:42:06 +00:00
}
2012-09-19 15:15:01 +00:00
2023-05-12 09:42:06 +00:00
NxI32 operator = = ( const int3 & a , const int3 & b )
2012-09-19 15:15:01 +00:00
{
2023-05-12 09:42:06 +00:00
for ( NxI32 i = 0 ; i < 3 ; i + + )
2012-09-19 15:15:01 +00:00
{
if ( a [ i ] ! = b [ i ] ) return 0 ;
}
return 1 ;
}
2023-05-12 09:42:06 +00:00
int3 roll3 ( int3 a )
2012-09-19 15:15:01 +00:00
{
NxI32 tmp = a [ 0 ] ;
a [ 0 ] = a [ 1 ] ;
a [ 1 ] = a [ 2 ] ;
a [ 2 ] = tmp ;
return a ;
}
2023-05-12 09:42:06 +00:00
NxI32 isa ( const int3 & a , const int3 & b )
2012-09-19 15:15:01 +00:00
{
return ( a = = b | | roll3 ( a ) = = b | | a = = roll3 ( b ) ) ;
}
2023-05-12 09:42:06 +00:00
NxI32 b2b ( const int3 & a , const int3 & b )
2012-09-19 15:15:01 +00:00
{
return isa ( a , int3 ( b [ 2 ] , b [ 1 ] , b [ 0 ] ) ) ;
}
2023-05-12 09:42:06 +00:00
NxI32 above ( float3 * vertices , const int3 & t , const float3 & p , NxF32 epsilon )
2012-09-19 15:15:01 +00:00
{
float3 n = TriNormal ( vertices [ t [ 0 ] ] , vertices [ t [ 1 ] ] , vertices [ t [ 2 ] ] ) ;
return ( dot ( n , p - vertices [ t [ 0 ] ] ) > epsilon ) ; // EPSILON???
}
NxI32 hasedge ( const int3 & t , NxI32 a , NxI32 b )
{
for ( NxI32 i = 0 ; i < 3 ; i + + )
{
NxI32 i1 = ( i + 1 ) % 3 ;
if ( t [ i ] = = a & & t [ i1 ] = = b ) return 1 ;
}
return 0 ;
}
NxI32 hasvert ( const int3 & t , NxI32 v )
{
return ( t [ 0 ] = = v | | t [ 1 ] = = v | | t [ 2 ] = = v ) ;
}
NxI32 shareedge ( const int3 & a , const int3 & b )
{
NxI32 i ;
for ( i = 0 ; i < 3 ; i + + )
{
NxI32 i1 = ( i + 1 ) % 3 ;
if ( hasedge ( a , b [ i1 ] , b [ i ] ) ) return 1 ;
}
return 0 ;
}
class Tri ;
static Array < Tri * > tris ; // djs: For heaven's sake!!!!
class Tri : public int3
{
public :
int3 n ;
NxI32 id ;
NxI32 vmax ;
NxF32 rise ;
Tri ( NxI32 a , NxI32 b , NxI32 c ) : int3 ( a , b , c ) , n ( - 1 , - 1 , - 1 )
{
id = tris . count ;
tris . Add ( this ) ;
vmax = - 1 ;
rise = 0.0f ;
}
~ Tri ( )
{
assert ( tris [ id ] = = this ) ;
tris [ id ] = NULL ;
}
NxI32 & neib ( NxI32 a , NxI32 b ) ;
} ;
NxI32 & Tri : : neib ( NxI32 a , NxI32 b )
{
static NxI32 er = - 1 ;
NxI32 i ;
2023-05-12 09:42:06 +00:00
for ( i = 0 ; i < 3 ; i + + )
2012-09-19 15:15:01 +00:00
{
NxI32 i1 = ( i + 1 ) % 3 ;
NxI32 i2 = ( i + 2 ) % 3 ;
if ( ( * this ) [ i ] = = a & & ( * this ) [ i1 ] = = b ) return n [ i2 ] ;
if ( ( * this ) [ i ] = = b & & ( * this ) [ i1 ] = = a ) return n [ i2 ] ;
}
assert ( 0 ) ;
return er ;
}
void b2bfix ( Tri * s , Tri * t )
{
NxI32 i ;
2023-05-12 09:42:06 +00:00
for ( i = 0 ; i < 3 ; i + + )
2012-09-19 15:15:01 +00:00
{
NxI32 i1 = ( i + 1 ) % 3 ;
NxI32 i2 = ( i + 2 ) % 3 ;
NxI32 a = ( * s ) [ i1 ] ;
NxI32 b = ( * s ) [ i2 ] ;
assert ( tris [ s - > neib ( a , b ) ] - > neib ( b , a ) = = s - > id ) ;
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 , NxI32 v )
{
int3 t = * t0 ;
NxI32 n = tris . count ;
Tri * ta = MEMALLOC_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 = MEMALLOC_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 = MEMALLOC_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 ( NxF32 epsilon )
{
NxI32 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 :
NxI32 x , y , z , w ;
int4 ( ) { } ;
int4 ( NxI32 _x , NxI32 _y , NxI32 _z , NxI32 _w ) { x = _x ; y = _y ; z = _z ; w = _w ; }
const NxI32 & operator [ ] ( NxI32 i ) const { return ( & x ) [ i ] ; }
NxI32 & operator [ ] ( NxI32 i ) { return ( & x ) [ i ] ; }
} ;
bool hasVolume ( float3 * verts , NxI32 p0 , NxI32 p1 , NxI32 p2 , NxI32 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 ;
NxF32 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 , NxI32 verts_count , Array < NxI32 > & allow )
{
float3 basis [ 3 ] ;
2023-05-12 09:42:06 +00:00
basis [ 0 ] = float3 ( 0.01f , 0.02f , 1.0f ) ;
2012-09-19 15:15:01 +00:00
NxI32 p0 = maxdirsterid ( verts , verts_count , basis [ 0 ] , allow ) ;
NxI32 p1 = maxdirsterid ( verts , verts_count , - basis [ 0 ] , allow ) ;
basis [ 0 ] = verts [ p0 ] - verts [ p1 ] ;
2023-05-12 09:42:06 +00:00
if ( p0 = = p1 | | basis [ 0 ] = = float3 ( 0 , 0 , 0 ) )
2012-09-19 15:15:01 +00:00
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 ] ) ;
NxI32 p2 = maxdirsterid ( verts , verts_count , basis [ 1 ] , allow ) ;
if ( p2 = = p0 | | p2 = = p1 )
{
p2 = maxdirsterid ( verts , verts_count , - basis [ 1 ] , allow ) ;
}
2023-05-12 09:42:06 +00:00
if ( p2 = = p0 | | p2 = = p1 )
2012-09-19 15:15:01 +00:00
return int4 ( - 1 , - 1 , - 1 , - 1 ) ;
basis [ 1 ] = verts [ p2 ] - verts [ p0 ] ;
basis [ 2 ] = normalize ( cross ( basis [ 1 ] , basis [ 0 ] ) ) ;
NxI32 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 ) ;
2023-05-12 09:42:06 +00:00
if ( p3 = = p0 | | p3 = = p1 | | p3 = = p2 )
2012-09-19 15:15:01 +00:00
return int4 ( - 1 , - 1 , - 1 , - 1 ) ;
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)
2023-05-12 09:42:06 +00:00
NxI32 calchullgen ( float3 * verts , NxI32 verts_count , NxI32 vlimit )
2012-09-19 15:15:01 +00:00
{
if ( verts_count < 4 ) return 0 ;
if ( vlimit = = 0 ) vlimit = 1000000000 ;
NxI32 j ;
float3 bmin ( * verts ) , bmax ( * verts ) ;
Array < NxI32 > isextreme ( verts_count ) ;
Array < NxI32 > allow ( verts_count ) ;
2023-05-12 09:42:06 +00:00
for ( j = 0 ; j < verts_count ; j + + )
2012-09-19 15:15:01 +00:00
{
allow . Add ( 1 ) ;
isextreme . Add ( 0 ) ;
bmin = VectorMin ( bmin , verts [ j ] ) ;
bmax = VectorMax ( bmax , verts [ j ] ) ;
}
NxF32 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 = MEMALLOC_NEW ( Tri ) ( p [ 2 ] , p [ 3 ] , p [ 1 ] ) ; t0 - > n = int3 ( 2 , 3 , 1 ) ;
Tri * t1 = MEMALLOC_NEW ( Tri ) ( p [ 3 ] , p [ 2 ] , p [ 0 ] ) ; t1 - > n = int3 ( 3 , 2 , 0 ) ;
Tri * t2 = MEMALLOC_NEW ( Tri ) ( p [ 0 ] , p [ 1 ] , p [ 3 ] ) ; t2 - > n = int3 ( 0 , 1 , 3 ) ;
Tri * t3 = MEMALLOC_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 ] ;
assert ( t ) ;
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 ) ) )
{
int3 ti = * te ;
NxI32 v = te - > vmax ;
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 ] ] ;
assert ( nb ) ; assert ( ! hasvert ( * nb , v ) ) ; 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 ) ;
2023-05-12 09:42:06 +00:00
if ( isextreme [ t - > vmax ] )
2012-09-19 15:15:01 +00:00
{
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)
2023-05-12 09:42:06 +00:00
NxI32 calchull ( float3 * verts , NxI32 verts_count , NxI32 * & tris_out , NxI32 & tris_count , NxI32 vlimit )
2012-09-19 15:15:01 +00:00
{
NxI32 rc = calchullgen ( verts , verts_count , vlimit ) ;
if ( ! rc ) return 0 ;
Array < NxI32 > ts ;
for ( NxI32 i = 0 ; i < tris . count ; i + + ) if ( tris [ i ] )
{
for ( NxI32 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 NxCooking library
tris . SetSize ( 0 ) ;
return 1 ;
}
static NxF32 area2 ( const float3 & v0 , const float3 & v1 , const float3 & v2 )
{
float3 cp = cross ( v0 - v1 , v2 - v0 ) ;
return dot ( cp , cp ) ;
}
2023-05-12 09:42:06 +00:00
NxI32 calchullpbev ( float3 * verts , NxI32 verts_count , NxI32 vlimit , Array < Plane > & planes , NxF32 bevangle )
2012-09-19 15:15:01 +00:00
{
NxI32 i , j ;
Array < Plane > bplanes ;
planes . count = 0 ;
NxI32 rc = calchullgen ( verts , verts_count , vlimit ) ;
if ( ! rc ) return 0 ;
extern NxF32 minadjangle ; // default is 3.0f; // in degrees - result wont have two adjacent facets within this angle of each other.
NxF32 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 ;
assert ( n ! = REAL3 ( 0 , 0 , 0 ) ) ;
2023-05-12 09:42:06 +00:00
if ( n = = REAL3 ( 0 , 0 , 0 ) ) return 0 ;
2012-09-19 15:15:01 +00:00
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 = MEMALLOC_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 NxI32 overhull ( Plane * planes , NxI32 planes_count , float3 * verts , NxI32 verts_count , NxI32 maxplanes ,
float3 * & verts_out , NxI32 & verts_count_out , NxI32 * & faces_out , NxI32 & faces_count_out , NxF32 inflate )
{
NxI32 i , j ;
2023-05-12 09:42:06 +00:00
if ( verts_count < 4 ) return 0 ;
2012-09-19 15:15:01 +00:00
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 ] ) ;
}
NxF32 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));
NxF32 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));
NxF32 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 ) ) ;
NxI32 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 ) ) { c = tmp ; break ; } // might want to debug this case better too!!!
delete tmp ;
}
assert ( AssertIntact ( * c ) ) ;
//return c;
faces_out = ( NxI32 * ) MEMALLOC_MALLOC ( sizeof ( NxI32 ) * ( 1 + c - > facets . count + c - > edges . count ) ) ; // new NxI32[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.
assert ( k = = c - > facets . count ) ;
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 NxI32 overhullv ( float3 * verts , NxI32 verts_count , NxI32 maxplanes ,
float3 * & verts_out , NxI32 & verts_count_out , NxI32 * & faces_out , NxI32 & faces_count_out , NxF32 inflate , NxF32 bevangle , NxI32 vlimit )
{
if ( ! verts_count ) return 0 ;
extern NxI32 calchullpbev ( float3 * verts , NxI32 verts_count , NxI32 vlimit , Array < Plane > & planes , NxF32 bevangle ) ;
Array < Plane > planes ;
NxI32 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 ( NxU32 vcount , const NxF32 * vertices , PHullResult & result , NxU32 vlimit , NxF32 inflate )
{
NxI32 index_count ;
NxI32 * faces ;
float3 * verts_out ;
NxI32 verts_count_out ;
if ( inflate = = 0.0f )
{
NxI32 * tris_out ;
NxI32 tris_count ;
NxI32 ret = calchull ( ( float3 * ) vertices , ( NxI32 ) vcount , tris_out , tris_count , vlimit ) ;
if ( ! ret ) return false ;
result . mIndexCount = ( NxU32 ) ( tris_count * 3 ) ;
result . mFaceCount = ( NxU32 ) tris_count ;
result . mVertices = ( NxF32 * ) vertices ;
result . mVcount = ( NxU32 ) vcount ;
result . mIndices = ( NxU32 * ) tris_out ;
return true ;
}
NxI32 ret = overhullv ( ( float3 * ) vertices , vcount , 35 , verts_out , verts_count_out , faces , index_count , inflate , 120.0f , 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 ;
}
Array < int3 > tris ;
NxI32 n = faces [ 0 ] ;
NxI32 k = 1 ;
for ( NxI32 i = 0 ; i < n ; i + + )
{
NxI32 pn = faces [ k + + ] ;
for ( NxI32 j = 2 ; j < pn ; j + + ) tris . Add ( int3 ( faces [ k ] , faces [ k + j - 1 ] , faces [ k + j ] ) ) ;
k + = pn ;
}
assert ( tris . count = = index_count - 1 - ( n * 3 ) ) ;
MEMALLOC_FREE ( faces ) ; // PT: I added that. Is it ok ?
result . mIndexCount = ( NxU32 ) ( tris . count * 3 ) ;
result . mFaceCount = ( NxU32 ) tris . count ;
result . mVertices = ( NxF32 * ) verts_out ;
result . mVcount = ( NxU32 ) verts_count_out ;
result . mIndices = ( NxU32 * ) tris . element ;
tris . element = NULL ; tris . count = tris . array_size = 0 ;
CONVEX_DECOMPOSITION : : tris . SetSize ( 0 ) ; //have to set the size to 0 in order to protect from a "pure virtual function call" problem
return true ;
}
void ReleaseHull ( PHullResult & result )
{
MEMALLOC_FREE ( result . mIndices ) ; // PT: I added that. Is it ok ?
MEMALLOC_FREE ( result . mVertices ) ; // PT: I added that. Is it ok ?
result . mVcount = 0 ;
result . mIndexCount = 0 ;
result . mIndices = 0 ;
result . mVertices = 0 ;
result . mIndices = 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 ;
NxU32 vcount = desc . mVcount ;
if ( vcount < 8 ) vcount = 8 ;
NxF32 * vsource = ( NxF32 * ) MEMALLOC_MALLOC ( sizeof ( NxF32 ) * vcount * 3 ) ;
NxF32 scale [ 3 ] ;
NxU32 ovcount ;
bool ok = CleanupVertices ( desc . mVcount , desc . mVertices , desc . mVertexStride , ovcount , vsource , desc . mNormalEpsilon , scale ) ; // normalize point cloud, remove duplicates!
if ( ok )
{
{
for ( NxU32 i = 0 ; i < ovcount ; i + + )
{
NxF32 * v = & vsource [ i * 3 ] ;
v [ 0 ] * = scale [ 0 ] ;
v [ 1 ] * = scale [ 1 ] ;
v [ 2 ] * = scale [ 2 ] ;
}
}
NxF32 skinwidth = 0 ;
2023-05-12 09:42:06 +00:00
if ( desc . HasHullFlag ( QF_SKIN_WIDTH ) )
2012-09-19 15:15:01 +00:00
skinwidth = desc . mSkinWidth ;
ok = ComputeHull ( ovcount , vsource , hr , desc . mMaxVertices , skinwidth ) ;
if ( ok )
{
// re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
NxF32 * vscratch = ( NxF32 * ) MEMALLOC_MALLOC ( sizeof ( NxF32 ) * hr . mVcount * 3 ) ;
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 = ( NxF32 * ) MEMALLOC_MALLOC ( sizeof ( NxF32 ) * ovcount * 3 ) ;
result . mNumFaces = hr . mFaceCount ;
result . mNumIndices = hr . mIndexCount ;
result . mIndices = ( NxU32 * ) MEMALLOC_MALLOC ( sizeof ( NxU32 ) * hr . mIndexCount ) ;
memcpy ( result . mOutputVertices , vscratch , sizeof ( NxF32 ) * 3 * ovcount ) ;
if ( desc . HasHullFlag ( QF_REVERSE_ORDER ) )
{
const NxU32 * source = hr . mIndices ;
NxU32 * dest = result . mIndices ;
for ( NxU32 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 ( NxU32 ) * hr . mIndexCount ) ;
}
}
else
{
result . mPolygons = true ;
result . mNumOutputVertices = ovcount ;
result . mOutputVertices = ( NxF32 * ) MEMALLOC_MALLOC ( sizeof ( NxF32 ) * ovcount * 3 ) ;
result . mNumFaces = hr . mFaceCount ;
result . mNumIndices = hr . mIndexCount + hr . mFaceCount ;
result . mIndices = ( NxU32 * ) MEMALLOC_MALLOC ( sizeof ( NxU32 ) * result . mNumIndices ) ;
memcpy ( result . mOutputVertices , vscratch , sizeof ( NxF32 ) * 3 * ovcount ) ;
{
const NxU32 * source = hr . mIndices ;
NxU32 * dest = result . mIndices ;
for ( NxU32 i = 0 ; i < hr . mFaceCount ; i + + )
{
dest [ 0 ] = 3 ;
if ( desc . HasHullFlag ( QF_REVERSE_ORDER ) )
{
dest [ 1 ] = source [ 2 ] ;
dest [ 2 ] = source [ 1 ] ;
dest [ 3 ] = source [ 0 ] ;
}
else
{
dest [ 1 ] = source [ 0 ] ;
dest [ 2 ] = source [ 1 ] ;
dest [ 3 ] = source [ 2 ] ;
}
dest + = 4 ;
source + = 3 ;
}
}
}
// 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 )
{
MEMALLOC_FREE ( vscratch ) ;
}
}
}
// this pointer is usually freed in ReleaseHull()
if ( vsource )
{
MEMALLOC_FREE ( vsource ) ;
}
return ret ;
}
HullError HullLibrary : : ReleaseResult ( HullResult & result ) // release memory allocated for this result, we are done with it.
{
if ( result . mOutputVertices )
{
MEMALLOC_FREE ( result . mOutputVertices ) ;
result . mOutputVertices = 0 ;
}
if ( result . mIndices )
{
MEMALLOC_FREE ( result . mIndices ) ;
result . mIndices = 0 ;
}
return QE_OK ;
}
static void AddPoint ( NxU32 & vcount , NxF32 * p , NxF32 x , NxF32 y , NxF32 z )
{
NxF32 * dest = & p [ vcount * 3 ] ;
dest [ 0 ] = x ;
dest [ 1 ] = y ;
dest [ 2 ] = z ;
vcount + + ;
}
NxF32 GetDist ( NxF32 px , NxF32 py , NxF32 pz , const NxF32 * p2 )
{
NxF32 dx = px - p2 [ 0 ] ;
NxF32 dy = py - p2 [ 1 ] ;
NxF32 dz = pz - p2 [ 2 ] ;
return dx * dx + dy * dy + dz * dz ;
}
bool HullLibrary : : CleanupVertices ( NxU32 svcount ,
const NxF32 * svertices ,
NxU32 stride ,
NxU32 & vcount , // output number of vertices
NxF32 * vertices , // location to store the results.
NxF32 normalepsilon ,
NxF32 * scale )
{
if ( svcount = = 0 ) return false ;
# define EPSILON 0.000001f // close enough to consider two floating point numbers to be 'the same'.
vcount = 0 ;
NxF32 recip [ 3 ] ;
if ( scale )
{
scale [ 0 ] = 1 ;
scale [ 1 ] = 1 ;
scale [ 2 ] = 1 ;
}
NxF32 bmin [ 3 ] = { FLT_MAX , FLT_MAX , FLT_MAX } ;
NxF32 bmax [ 3 ] = { - FLT_MAX , - FLT_MAX , - FLT_MAX } ;
const char * vtx = ( const char * ) svertices ;
{
for ( NxU32 i = 0 ; i < svcount ; i + + )
{
const NxF32 * p = ( const NxF32 * ) vtx ;
vtx + = stride ;
for ( NxI32 j = 0 ; j < 3 ; j + + )
{
if ( p [ j ] < bmin [ j ] ) bmin [ j ] = p [ j ] ;
if ( p [ j ] > bmax [ j ] ) bmax [ j ] = p [ j ] ;
}
}
}
NxF32 dx = bmax [ 0 ] - bmin [ 0 ] ;
NxF32 dy = bmax [ 1 ] - bmin [ 1 ] ;
NxF32 dz = bmax [ 2 ] - bmin [ 2 ] ;
NxF32 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 )
{
NxF32 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 ;
}
NxF32 x1 = center [ 0 ] - dx ;
NxF32 x2 = center [ 0 ] + dx ;
NxF32 y1 = center [ 1 ] - dy ;
NxF32 y2 = center [ 1 ] + dy ;
NxF32 z1 = center [ 2 ] - dz ;
NxF32 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 ( NxU32 i = 0 ; i < svcount ; i + + )
{
const NxF32 * p = ( const NxF32 * ) vtx ;
vtx + = stride ;
NxF32 px = p [ 0 ] ;
NxF32 py = p [ 1 ] ;
NxF32 pz = p [ 2 ] ;
if ( scale )
{
px = px * recip [ 0 ] ; // normalize
py = py * recip [ 1 ] ; // normalize
pz = pz * recip [ 2 ] ; // normalize
}
{
NxU32 j ;
for ( j = 0 ; j < vcount ; j + + )
{
NxF32 * v = & vertices [ j * 3 ] ;
NxF32 x = v [ 0 ] ;
NxF32 y = v [ 1 ] ;
NxF32 z = v [ 2 ] ;
NxF32 dx = fabsf ( x - px ) ;
NxF32 dy = fabsf ( y - py ) ;
NxF32 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.
NxF32 dist1 = GetDist ( px , py , pz , center ) ;
NxF32 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 )
{
NxF32 * 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.
{
NxF32 bmin [ 3 ] = { FLT_MAX , FLT_MAX , FLT_MAX } ;
NxF32 bmax [ 3 ] = { - FLT_MAX , - FLT_MAX , - FLT_MAX } ;
for ( NxU32 i = 0 ; i < vcount ; i + + )
{
const NxF32 * p = & vertices [ i * 3 ] ;
for ( NxI32 j = 0 ; j < 3 ; j + + )
{
if ( p [ j ] < bmin [ j ] ) bmin [ j ] = p [ j ] ;
if ( p [ j ] > bmax [ j ] ) bmax [ j ] = p [ j ] ;
}
}
NxF32 dx = bmax [ 0 ] - bmin [ 0 ] ;
NxF32 dy = bmax [ 1 ] - bmin [ 1 ] ;
NxF32 dz = bmax [ 2 ] - bmin [ 2 ] ;
if ( dx < EPSILON | | dy < EPSILON | | dz < EPSILON | | vcount < 3 )
{
NxF32 cx = dx * 0.5f + bmin [ 0 ] ;
NxF32 cy = dy * 0.5f + bmin [ 1 ] ;
NxF32 cz = dz * 0.5f + bmin [ 2 ] ;
NxF32 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 ;
}
NxF32 x1 = cx - dx ;
NxF32 x2 = cx + dx ;
NxF32 y1 = cy - dy ;
NxF32 y2 = cy + dy ;
NxF32 z1 = cz - dz ;
NxF32 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 NxF32 * verts , NxU32 vcount , NxF32 * overts , NxU32 & ocount , NxU32 * indices , NxU32 indexcount )
{
NxU32 * used = ( NxU32 * ) MEMALLOC_MALLOC ( sizeof ( NxU32 ) * vcount ) ;
memset ( used , 0 , sizeof ( NxU32 ) * vcount ) ;
ocount = 0 ;
for ( NxU32 i = 0 ; i < indexcount ; i + + )
{
NxU32 v = indices [ i ] ; // original array index
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
assert ( ocount < = vcount ) ;
used [ v ] = ocount ; // assign new index remapping
}
}
MEMALLOC_FREE ( used ) ;
}
//==================================================================================
HullError HullLibrary : : CreateTriangleMesh ( HullResult & answer , ConvexHullTriangleInterface * iface )
{
HullError ret = QE_FAIL ;
const NxF32 * p = answer . mOutputVertices ;
const NxU32 * idx = answer . mIndices ;
NxU32 fcount = answer . mNumFaces ;
if ( p & & idx & & fcount )
{
ret = QE_OK ;
for ( NxU32 i = 0 ; i < fcount ; i + + )
{
NxU32 pcount = * idx + + ;
NxU32 i1 = * idx + + ;
NxU32 i2 = * idx + + ;
NxU32 i3 = * idx + + ;
const NxF32 * p1 = & p [ i1 * 3 ] ;
const NxF32 * p2 = & p [ i2 * 3 ] ;
const NxF32 * 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 NxF32 * p1 , const NxF32 * p2 , const NxF32 * 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 ] ;
NxF32 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 NxF32 * tp1 = p1 ;
const NxF32 * tp2 = p2 ;
const NxF32 * tp3 = p3 ;
NxI32 i1 = 0 ;
NxI32 i2 = 0 ;
NxF32 nx = fabsf ( n [ 0 ] ) ;
NxF32 ny = fabsf ( n [ 1 ] ) ;
NxF32 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 ) ;
}
//==================================================================================
NxF32 HullLibrary : : ComputeNormal ( NxF32 * n , const NxF32 * A , const NxF32 * B , const NxF32 * C )
{
NxF32 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