#pragma once #include "bytebool.h" #include "math/vector.h" #include "math/plane.h" #define VectorCopy( a,b ) ( ( b )[0] = ( a )[0],( b )[1] = ( a )[1],( b )[2] = ( a )[2] ) #define RGBTOGRAY( x ) ( (float)( ( x )[0] ) * 0.2989f + (float)( ( x )[1] ) * 0.5870f + (float)( ( x )[2] ) * 0.1140f ) #define VectorFastNormalize VectorNormalize template inline void value_maximize( T& value, const T& other ){ value = std::max( value, other ); } template inline void value_minimize( T& value, const T& other ){ value = std::min( value, other ); } template struct MinMax___ { BasicVector3 mins; BasicVector3 maxs; MinMax___(){ clear(); } template MinMax___( const BasicVector3& min, const BasicVector3& max ) : mins( min ), maxs( max ){ } void clear(){ mins.x() = mins.y() = mins.z() = std::numeric_limits::max(); maxs.x() = maxs.y() = maxs.z() = std::numeric_limits::lowest(); } bool valid() const { return mins.x() < maxs.x() && mins.y() < maxs.y() && mins.z() < maxs.z(); } template void extend( const BasicVector3& point ){ for ( size_t i = 0; i < 3; ++i ){ const auto val = point[i]; if ( val < mins[i] ) { mins[i] = val; } if ( val > maxs[i] ) { maxs[i] = val; } } } template void extend( const MinMax___& other ){ extend( other.mins ); extend( other.maxs ); } // true, if point is within the bounds template bool test( const BasicVector3& point ) const { return point.x() >= mins.x() && point.y() >= mins.y() && point.z() >= mins.z() && point.x() <= maxs.x() && point.y() <= maxs.y() && point.z() <= maxs.z(); } // true, if there is an intersection template bool test( const MinMax___& other ) const { return other.maxs.x() >= mins.x() && other.maxs.y() >= mins.y() && other.maxs.z() >= mins.z() && other.mins.x() <= maxs.x() && other.mins.y() <= maxs.y() && other.mins.z() <= maxs.z(); } // true, if other is completely enclosed by this template bool surrounds( const MinMax___& other ) const { return other.mins.x() >= mins.x() && other.mins.y() >= mins.y() && other.mins.z() >= mins.z() && other.maxs.x() <= maxs.x() && other.maxs.y() <= maxs.y() && other.maxs.z() <= maxs.z(); } BasicVector3 origin() const { return ( mins + maxs ) * 0.5; } }; using MinMax = MinMax___; template struct Color4___ : public BasicVector4 { using BasicVector4::BasicVector4; Color4___( const BasicVector4& vector ) : BasicVector4( vector ){ } BasicVector3& rgb(){ return this->vec3(); } const BasicVector3& rgb() const { return this->vec3(); } T& alpha(){ return this->w(); } const T& alpha() const { return this->w(); } }; using Color4f = Color4___; using Color4b = Color4___; template T VectorNormalize( BasicVector3& vector ) { const double length = vector3_length( DoubleVector3( vector ) ); if ( length == 0 ) { vector.set( 0 ); return 0; } vector /= length; return length; } template BasicVector3 VectorNormalized( const BasicVector3& vector ) { BasicVector3 vec( vector ); VectorNormalize( vec ); return vec; } const float EQUAL_EPSILON = 0.001; inline bool VectorCompare( const Vector3& v1, const Vector3& v2 ){ return vector3_equal_epsilon( v1, v2, EQUAL_EPSILON ); } template T VectorMax( const BasicVector3& v ){ return ( v[0] > v[1] ) ? ( ( v[0] > v[2] ) ? v[0] : v[2] ) : ( ( v[1] > v[2] ) ? v[1] : v[2] ); } inline bool VectorIsOnAxis( const Vector3& v ){ int zeroComponentCount = 0; for ( int i = 0; i < 3; ++i ) { if ( v[i] == 0.0 ) { zeroComponentCount++; } } return zeroComponentCount > 1; // The zero vector will be on axis. } /* ===================== PlaneFromPoints Returns false if the triangle is degenrate. The normal will point out of the clock for clockwise ordered points ===================== */ template bool PlaneFromPoints( Plane3___

& plane, const BasicVector3& p0, const BasicVector3& p1, const BasicVector3& p2 ) { plane.normal() = vector3_cross( p2 - p0, p1 - p0 ); if ( VectorNormalize( plane.normal() ) == 0 ) { return false; } plane.dist() = vector3_dot( p0, plane.normal() ); return true; } template bool PlaneFromPoints( Plane3___

& plane, const BasicVector3 planepts[3] ) { return PlaneFromPoints( plane, planepts[0], planepts[1], planepts[2] ); } /* ComputeAxisBase() computes the base texture axis for brush primitive texturing note: ComputeAxisBase here and in editor code must always BE THE SAME! warning: special case behaviour of atan2( y, x ) <-> atan( y / x ) might not be the same everywhere when x == 0 rotation by (0,RotY,RotZ) assigns X to normal */ template inline void ComputeAxisBase( const BasicVector3& normal, BasicVector3& texS, BasicVector3& texT ){ #if 1 const BasicVector3 up( 0, 0, 1 ); const BasicVector3 down( 0, 0, -1 ); if ( vector3_equal_epsilon( normal, up, Element(1e-6) ) ) { texS = BasicVector3( 0, 1, 0 ); texT = BasicVector3( 1, 0, 0 ); } else if ( vector3_equal_epsilon( normal, down, Element(1e-6) ) ) { texS = BasicVector3( 0, 1, 0 ); texT = BasicVector3( -1, 0, 0 ); } else { texS = vector3_normalised( vector3_cross( normal, up ) ); texT = vector3_normalised( vector3_cross( normal, texS ) ); vector3_negate( texS ); } #else /* do some cleaning */ if ( fabs( normal[ 0 ] ) < 1e-6 ) { normal[ 0 ] = 0.0f; } if ( fabs( normal[ 1 ] ) < 1e-6 ) { normal[ 1 ] = 0.0f; } if ( fabs( normal[ 2 ] ) < 1e-6 ) { normal[ 2 ] = 0.0f; } /* compute the two rotations around y and z to rotate x to normal */ const float RotY = -atan2( normal[ 2 ], sqrt( normal[ 1 ] * normal[ 1 ] + normal[ 0 ] * normal[ 0 ] ) ); const float RotZ = atan2( normal[ 1 ], normal[ 0 ] ); /* rotate (0,1,0) and (0,0,1) to compute texS and texT */ texS[ 0 ] = -sin( RotZ ); texS[ 1 ] = cos( RotZ ); texS[ 2 ] = 0; /* the texT vector is along -z (t texture coorinates axis) */ texT[ 0 ] = -sin( RotY ) * cos( RotZ ); texT[ 1 ] = -sin( RotY ) * sin( RotZ ); texT[ 2 ] = -cos( RotY ); #endif } /* ================ MakeNormalVectors Given a normalized forward vector, create two other perpendicular vectors ================ */ inline void MakeNormalVectors( const Vector3& forward, Vector3& right, Vector3& up ){ // this rotate and negate guarantees a vector // not colinear with the original right[1] = -forward[0]; right[2] = forward[1]; right[0] = forward[2]; right = VectorNormalized( right - forward * vector3_dot( right, forward ) ); up = vector3_cross( right, forward ); } /* ** NormalToLatLong ** ** We use two byte encoded normals in some space critical applications. ** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format ** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format ** */ inline void NormalToLatLong( const Vector3& normal, byte bytes[2] ) { // check for singularities if ( normal[0] == 0 && normal[1] == 0 ) { if ( normal[2] > 0 ) { bytes[0] = 0; bytes[1] = 0; // lat = 0, long = 0 } else { bytes[0] = 128; bytes[1] = 0; // lat = 0, long = 128 } } else { const int a = radians_to_degrees( atan2( normal[1], normal[0] ) ) * ( 255.0 / 360.0 ); const int b = radians_to_degrees( acos( normal[2] ) ) * ( 255.0 / 360.0 ); bytes[0] = b & 0xff; // longitude bytes[1] = a & 0xff; // lattitude } } // plane types are used to speed some tests // 0-2 are axial planes enum EPlaneType : int { ePlaneX = 0, ePlaneY = 1, ePlaneZ = 2, ePlaneNonAxial = 3 }; inline EPlaneType PlaneTypeForNormal( const Vector3& normal ) { if ( normal[0] == 1.0 || normal[0] == -1.0 ) { return ePlaneX; } if ( normal[1] == 1.0 || normal[1] == -1.0 ) { return ePlaneY; } if ( normal[2] == 1.0 || normal[2] == -1.0 ) { return ePlaneZ; } return ePlaneNonAxial; } inline void ColorNormalize( Vector3& color ) { const float max = VectorMax( color ); if ( max == 0 ) { color.set( 1 ); } else{ color *= ( 1.f / max ); } }