fix: some file didn't have the svn:eol-style native yet

This commit is contained in:
erwin.coumans
2010-03-06 15:23:36 +00:00
parent 4fd48ac691
commit 81f04a4d48
641 changed files with 301123 additions and 301123 deletions

View File

@@ -1,422 +1,422 @@
/*
* ICE OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains AABB-related code.
* \file IceAABB.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* AABB class.
* \class AABB
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the sum of two AABBs.
* \param aabb [in] the other AABB
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AABB& AABB::Add(const AABB& aabb)
{
// Compute new min & max values
Point Min; GetMin(Min);
Point Tmp; aabb.GetMin(Tmp);
Min.Min(Tmp);
Point Max; GetMax(Max);
aabb.GetMax(Tmp);
Max.Max(Tmp);
// Update this
SetMinMax(Min, Max);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Makes a cube from the AABB.
* \param cube [out] the cube AABB
* \return cube edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float AABB::MakeCube(AABB& cube) const
{
Point Ext; GetExtents(Ext);
float Max = Ext.Max();
Point Cnt; GetCenter(Cnt);
cube.SetCenterExtents(Cnt, Point(Max, Max, Max));
return Max;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Makes a sphere from the AABB.
* \param sphere [out] sphere containing the AABB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABB::MakeSphere(Sphere& sphere) const
{
GetExtents(sphere.mCenter);
sphere.mRadius = sphere.mCenter.Magnitude() * 1.00001f; // To make sure sphere::Contains(*this) succeeds
GetCenter(sphere.mCenter);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other AABB
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::IsInside(const AABB& box) const
{
if(box.GetMin(0)>GetMin(0)) return false;
if(box.GetMin(1)>GetMin(1)) return false;
if(box.GetMin(2)>GetMin(2)) return false;
if(box.GetMax(0)<GetMax(0)) return false;
if(box.GetMax(1)<GetMax(1)) return false;
if(box.GetMax(2)<GetMax(2)) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the AABB planes.
* \param planes [out] 6 planes surrounding the box
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::ComputePlanes(Plane* planes) const
{
// Checkings
if(!planes) return false;
Point Center, Extents;
GetCenter(Center);
GetExtents(Extents);
// Writes normals
planes[0].n = Point(1.0f, 0.0f, 0.0f);
planes[1].n = Point(-1.0f, 0.0f, 0.0f);
planes[2].n = Point(0.0f, 1.0f, 0.0f);
planes[3].n = Point(0.0f, -1.0f, 0.0f);
planes[4].n = Point(0.0f, 0.0f, 1.0f);
planes[5].n = Point(0.0f, 0.0f, -1.0f);
// Compute a point on each plane
Point p0 = Point(Center.x+Extents.x, Center.y, Center.z);
Point p1 = Point(Center.x-Extents.x, Center.y, Center.z);
Point p2 = Point(Center.x, Center.y+Extents.y, Center.z);
Point p3 = Point(Center.x, Center.y-Extents.y, Center.z);
Point p4 = Point(Center.x, Center.y, Center.z+Extents.z);
Point p5 = Point(Center.x, Center.y, Center.z-Extents.z);
// Compute d
planes[0].d = -(planes[0].n|p0);
planes[1].d = -(planes[1].n|p1);
planes[2].d = -(planes[2].n|p2);
planes[3].d = -(planes[3].n|p3);
planes[4].d = -(planes[4].n|p4);
planes[5].d = -(planes[5].n|p5);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the aabb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::ComputePoints(Point* pts) const
{
// Checkings
if(!pts) return false;
// Get box corners
Point min; GetMin(min);
Point max; GetMax(max);
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
// Generate 8 corners of the bbox
pts[0] = Point(min.x, min.y, min.z);
pts[1] = Point(max.x, min.y, min.z);
pts[2] = Point(max.x, max.y, min.z);
pts[3] = Point(min.x, max.y, min.z);
pts[4] = Point(min.x, min.y, max.z);
pts[5] = Point(max.x, min.y, max.z);
pts[6] = Point(max.x, max.y, max.z);
pts[7] = Point(min.x, max.y, max.z);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* AABB::GetVertexNormals() const
{
static float VertexNormals[] =
{
-INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, INVSQRT3, INVSQRT3,
-INVSQRT3, INVSQRT3, INVSQRT3
};
return (const Point*)VertexNormals;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* AABB::GetEdges() const
{
static udword Indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
7, 6, 6, 5, 5, 4, 4, 7,
1, 5, 6, 2,
3, 7, 4, 0
};
return Indices;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* AABB::GetEdgeNormals() const
{
static float EdgeNormals[] =
{
0, -INVSQRT2, -INVSQRT2, // 0-1
INVSQRT2, 0, -INVSQRT2, // 1-2
0, INVSQRT2, -INVSQRT2, // 2-3
-INVSQRT2, 0, -INVSQRT2, // 3-0
0, INVSQRT2, INVSQRT2, // 7-6
INVSQRT2, 0, INVSQRT2, // 6-5
0, -INVSQRT2, INVSQRT2, // 5-4
-INVSQRT2, 0, INVSQRT2, // 4-7
INVSQRT2, -INVSQRT2, 0, // 1-5
INVSQRT2, INVSQRT2, 0, // 6-2
-INVSQRT2, INVSQRT2, 0, // 3-7
-INVSQRT2, -INVSQRT2, 0 // 4-0
};
return (const Point*)EdgeNormals;
}
// ===========================================================================
// (C) 1996-98 Vienna University of Technology
// ===========================================================================
// NAME: bboxarea
// TYPE: c++ code
// PROJECT: Bounding Box Area
// CONTENT: Computes area of 2D projection of 3D oriented bounding box
// VERSION: 1.0
// ===========================================================================
// AUTHORS: ds Dieter Schmalstieg
// ep Erik Pojar
// ===========================================================================
// HISTORY:
//
// 19-sep-99 15:23:03 ds last modification
// 01-dec-98 15:23:03 ep created
// ===========================================================================
//----------------------------------------------------------------------------
// SAMPLE CODE STARTS HERE
//----------------------------------------------------------------------------
// NOTE: This sample program requires OPEN INVENTOR!
//indexlist: this table stores the 64 possible cases of classification of
//the eyepoint with respect to the 6 defining planes of the bbox (2^6=64)
//only 26 (3^3-1, where 1 is "inside" cube) of these cases are valid.
//the first 6 numbers in each row are the indices of the bbox vertices that
//form the outline of which we want to compute the area (counterclockwise
//ordering), the 7th entry means the number of vertices in the outline.
//there are 6 cases with a single face and and a 4-vertex outline, and
//20 cases with 2 or 3 faces and a 6-vertex outline. a value of 0 indicates
//an invalid case.
// Original list was made of 7 items, I added an 8th element:
// - to padd on a cache line
// - to repeat the first entry to avoid modulos
//
// I also replaced original ints with sbytes.
static const sbyte gIndexList[64][8] =
{
{-1,-1,-1,-1,-1,-1,-1, 0}, // 0 inside
{ 0, 4, 7, 3, 0,-1,-1, 4}, // 1 left
{ 1, 2, 6, 5, 1,-1,-1, 4}, // 2 right
{-1,-1,-1,-1,-1,-1,-1, 0}, // 3 -
{ 0, 1, 5, 4, 0,-1,-1, 4}, // 4 bottom
{ 0, 1, 5, 4, 7, 3, 0, 6}, // 5 bottom, left
{ 0, 1, 2, 6, 5, 4, 0, 6}, // 6 bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, // 7 -
{ 2, 3, 7, 6, 2,-1,-1, 4}, // 8 top
{ 0, 4, 7, 6, 2, 3, 0, 6}, // 9 top, left
{ 1, 2, 3, 7, 6, 5, 1, 6}, //10 top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //11 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //12 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //13 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //14 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //15 -
{ 0, 3, 2, 1, 0,-1,-1, 4}, //16 front
{ 0, 4, 7, 3, 2, 1, 0, 6}, //17 front, left
{ 0, 3, 2, 6, 5, 1, 0, 6}, //18 front, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //19 -
{ 0, 3, 2, 1, 5, 4, 0, 6}, //20 front, bottom
{ 1, 5, 4, 7, 3, 2, 1, 6}, //21 front, bottom, left
{ 0, 3, 2, 6, 5, 4, 0, 6}, //22 front, bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //23 -
{ 0, 3, 7, 6, 2, 1, 0, 6}, //24 front, top
{ 0, 4, 7, 6, 2, 1, 0, 6}, //25 front, top, left
{ 0, 3, 7, 6, 5, 1, 0, 6}, //26 front, top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //27 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //28 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //29 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //30 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //31 -
{ 4, 5, 6, 7, 4,-1,-1, 4}, //32 back
{ 0, 4, 5, 6, 7, 3, 0, 6}, //33 back, left
{ 1, 2, 6, 7, 4, 5, 1, 6}, //34 back, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //35 -
{ 0, 1, 5, 6, 7, 4, 0, 6}, //36 back, bottom
{ 0, 1, 5, 6, 7, 3, 0, 6}, //37 back, bottom, left
{ 0, 1, 2, 6, 7, 4, 0, 6}, //38 back, bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //39 -
{ 2, 3, 7, 4, 5, 6, 2, 6}, //40 back, top
{ 0, 4, 5, 6, 2, 3, 0, 6}, //41 back, top, left
{ 1, 2, 3, 7, 4, 5, 1, 6}, //42 back, top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //43 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //44 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //45 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //46 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //47 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //48 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //49 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //50 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //51 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //52 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //53 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //54 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //55 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //56 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //57 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //58 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //59 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //60 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //61 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //62 invalid
{-1,-1,-1,-1,-1,-1,-1, 0} //63 invalid
};
const sbyte* AABB::ComputeOutline(const Point& local_eye, sdword& num) const
{
// Get box corners
Point min; GetMin(min);
Point max; GetMax(max);
// Compute 6-bit code to classify eye with respect to the 6 defining planes of the bbox
int pos = ((local_eye.x < min.x) ? 1 : 0) // 1 = left
+ ((local_eye.x > max.x) ? 2 : 0) // 2 = right
+ ((local_eye.y < min.y) ? 4 : 0) // 4 = bottom
+ ((local_eye.y > max.y) ? 8 : 0) // 8 = top
+ ((local_eye.z < min.z) ? 16 : 0) // 16 = front
+ ((local_eye.z > max.z) ? 32 : 0); // 32 = back
// Look up number of vertices in outline
num = (sdword)gIndexList[pos][7];
// Zero indicates invalid case
if(!num) return null;
return &gIndexList[pos][0];
}
// calculateBoxArea: computes the screen-projected 2D area of an oriented 3D bounding box
//const Point& eye, //eye point (in bbox object coordinates)
//const AABB& box, //3d bbox
//const Matrix4x4& mat, //free transformation for bbox
//float width, float height, int& num)
float AABB::ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const
{
const sbyte* Outline = ComputeOutline(eye, num);
if(!Outline) return -1.0f;
// Compute box vertices
Point vertexBox[8], dst[8];
ComputePoints(vertexBox);
// Transform all outline corners into 2D screen space
for(sdword i=0;i<num;i++)
{
HPoint Projected;
vertexBox[Outline[i]].ProjectToScreen(width, height, mat, Projected);
dst[i] = Projected;
}
float Sum = (dst[num-1][0] - dst[0][0]) * (dst[num-1][1] + dst[0][1]);
for(int i=0; i<num-1; i++)
Sum += (dst[i][0] - dst[i+1][0]) * (dst[i][1] + dst[i+1][1]);
return Sum * 0.5f; //return computed value corrected by 0.5
}
/*
* ICE OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains AABB-related code.
* \file IceAABB.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* AABB class.
* \class AABB
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the sum of two AABBs.
* \param aabb [in] the other AABB
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AABB& AABB::Add(const AABB& aabb)
{
// Compute new min & max values
Point Min; GetMin(Min);
Point Tmp; aabb.GetMin(Tmp);
Min.Min(Tmp);
Point Max; GetMax(Max);
aabb.GetMax(Tmp);
Max.Max(Tmp);
// Update this
SetMinMax(Min, Max);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Makes a cube from the AABB.
* \param cube [out] the cube AABB
* \return cube edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float AABB::MakeCube(AABB& cube) const
{
Point Ext; GetExtents(Ext);
float Max = Ext.Max();
Point Cnt; GetCenter(Cnt);
cube.SetCenterExtents(Cnt, Point(Max, Max, Max));
return Max;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Makes a sphere from the AABB.
* \param sphere [out] sphere containing the AABB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABB::MakeSphere(Sphere& sphere) const
{
GetExtents(sphere.mCenter);
sphere.mRadius = sphere.mCenter.Magnitude() * 1.00001f; // To make sure sphere::Contains(*this) succeeds
GetCenter(sphere.mCenter);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other AABB
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::IsInside(const AABB& box) const
{
if(box.GetMin(0)>GetMin(0)) return false;
if(box.GetMin(1)>GetMin(1)) return false;
if(box.GetMin(2)>GetMin(2)) return false;
if(box.GetMax(0)<GetMax(0)) return false;
if(box.GetMax(1)<GetMax(1)) return false;
if(box.GetMax(2)<GetMax(2)) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the AABB planes.
* \param planes [out] 6 planes surrounding the box
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::ComputePlanes(Plane* planes) const
{
// Checkings
if(!planes) return false;
Point Center, Extents;
GetCenter(Center);
GetExtents(Extents);
// Writes normals
planes[0].n = Point(1.0f, 0.0f, 0.0f);
planes[1].n = Point(-1.0f, 0.0f, 0.0f);
planes[2].n = Point(0.0f, 1.0f, 0.0f);
planes[3].n = Point(0.0f, -1.0f, 0.0f);
planes[4].n = Point(0.0f, 0.0f, 1.0f);
planes[5].n = Point(0.0f, 0.0f, -1.0f);
// Compute a point on each plane
Point p0 = Point(Center.x+Extents.x, Center.y, Center.z);
Point p1 = Point(Center.x-Extents.x, Center.y, Center.z);
Point p2 = Point(Center.x, Center.y+Extents.y, Center.z);
Point p3 = Point(Center.x, Center.y-Extents.y, Center.z);
Point p4 = Point(Center.x, Center.y, Center.z+Extents.z);
Point p5 = Point(Center.x, Center.y, Center.z-Extents.z);
// Compute d
planes[0].d = -(planes[0].n|p0);
planes[1].d = -(planes[1].n|p1);
planes[2].d = -(planes[2].n|p2);
planes[3].d = -(planes[3].n|p3);
planes[4].d = -(planes[4].n|p4);
planes[5].d = -(planes[5].n|p5);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the aabb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABB::ComputePoints(Point* pts) const
{
// Checkings
if(!pts) return false;
// Get box corners
Point min; GetMin(min);
Point max; GetMax(max);
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
// Generate 8 corners of the bbox
pts[0] = Point(min.x, min.y, min.z);
pts[1] = Point(max.x, min.y, min.z);
pts[2] = Point(max.x, max.y, min.z);
pts[3] = Point(min.x, max.y, min.z);
pts[4] = Point(min.x, min.y, max.z);
pts[5] = Point(max.x, min.y, max.z);
pts[6] = Point(max.x, max.y, max.z);
pts[7] = Point(min.x, max.y, max.z);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* AABB::GetVertexNormals() const
{
static float VertexNormals[] =
{
-INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, INVSQRT3, INVSQRT3,
-INVSQRT3, INVSQRT3, INVSQRT3
};
return (const Point*)VertexNormals;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* AABB::GetEdges() const
{
static udword Indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
7, 6, 6, 5, 5, 4, 4, 7,
1, 5, 6, 2,
3, 7, 4, 0
};
return Indices;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* AABB::GetEdgeNormals() const
{
static float EdgeNormals[] =
{
0, -INVSQRT2, -INVSQRT2, // 0-1
INVSQRT2, 0, -INVSQRT2, // 1-2
0, INVSQRT2, -INVSQRT2, // 2-3
-INVSQRT2, 0, -INVSQRT2, // 3-0
0, INVSQRT2, INVSQRT2, // 7-6
INVSQRT2, 0, INVSQRT2, // 6-5
0, -INVSQRT2, INVSQRT2, // 5-4
-INVSQRT2, 0, INVSQRT2, // 4-7
INVSQRT2, -INVSQRT2, 0, // 1-5
INVSQRT2, INVSQRT2, 0, // 6-2
-INVSQRT2, INVSQRT2, 0, // 3-7
-INVSQRT2, -INVSQRT2, 0 // 4-0
};
return (const Point*)EdgeNormals;
}
// ===========================================================================
// (C) 1996-98 Vienna University of Technology
// ===========================================================================
// NAME: bboxarea
// TYPE: c++ code
// PROJECT: Bounding Box Area
// CONTENT: Computes area of 2D projection of 3D oriented bounding box
// VERSION: 1.0
// ===========================================================================
// AUTHORS: ds Dieter Schmalstieg
// ep Erik Pojar
// ===========================================================================
// HISTORY:
//
// 19-sep-99 15:23:03 ds last modification
// 01-dec-98 15:23:03 ep created
// ===========================================================================
//----------------------------------------------------------------------------
// SAMPLE CODE STARTS HERE
//----------------------------------------------------------------------------
// NOTE: This sample program requires OPEN INVENTOR!
//indexlist: this table stores the 64 possible cases of classification of
//the eyepoint with respect to the 6 defining planes of the bbox (2^6=64)
//only 26 (3^3-1, where 1 is "inside" cube) of these cases are valid.
//the first 6 numbers in each row are the indices of the bbox vertices that
//form the outline of which we want to compute the area (counterclockwise
//ordering), the 7th entry means the number of vertices in the outline.
//there are 6 cases with a single face and and a 4-vertex outline, and
//20 cases with 2 or 3 faces and a 6-vertex outline. a value of 0 indicates
//an invalid case.
// Original list was made of 7 items, I added an 8th element:
// - to padd on a cache line
// - to repeat the first entry to avoid modulos
//
// I also replaced original ints with sbytes.
static const sbyte gIndexList[64][8] =
{
{-1,-1,-1,-1,-1,-1,-1, 0}, // 0 inside
{ 0, 4, 7, 3, 0,-1,-1, 4}, // 1 left
{ 1, 2, 6, 5, 1,-1,-1, 4}, // 2 right
{-1,-1,-1,-1,-1,-1,-1, 0}, // 3 -
{ 0, 1, 5, 4, 0,-1,-1, 4}, // 4 bottom
{ 0, 1, 5, 4, 7, 3, 0, 6}, // 5 bottom, left
{ 0, 1, 2, 6, 5, 4, 0, 6}, // 6 bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, // 7 -
{ 2, 3, 7, 6, 2,-1,-1, 4}, // 8 top
{ 0, 4, 7, 6, 2, 3, 0, 6}, // 9 top, left
{ 1, 2, 3, 7, 6, 5, 1, 6}, //10 top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //11 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //12 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //13 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //14 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //15 -
{ 0, 3, 2, 1, 0,-1,-1, 4}, //16 front
{ 0, 4, 7, 3, 2, 1, 0, 6}, //17 front, left
{ 0, 3, 2, 6, 5, 1, 0, 6}, //18 front, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //19 -
{ 0, 3, 2, 1, 5, 4, 0, 6}, //20 front, bottom
{ 1, 5, 4, 7, 3, 2, 1, 6}, //21 front, bottom, left
{ 0, 3, 2, 6, 5, 4, 0, 6}, //22 front, bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //23 -
{ 0, 3, 7, 6, 2, 1, 0, 6}, //24 front, top
{ 0, 4, 7, 6, 2, 1, 0, 6}, //25 front, top, left
{ 0, 3, 7, 6, 5, 1, 0, 6}, //26 front, top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //27 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //28 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //29 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //30 -
{-1,-1,-1,-1,-1,-1,-1, 0}, //31 -
{ 4, 5, 6, 7, 4,-1,-1, 4}, //32 back
{ 0, 4, 5, 6, 7, 3, 0, 6}, //33 back, left
{ 1, 2, 6, 7, 4, 5, 1, 6}, //34 back, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //35 -
{ 0, 1, 5, 6, 7, 4, 0, 6}, //36 back, bottom
{ 0, 1, 5, 6, 7, 3, 0, 6}, //37 back, bottom, left
{ 0, 1, 2, 6, 7, 4, 0, 6}, //38 back, bottom, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //39 -
{ 2, 3, 7, 4, 5, 6, 2, 6}, //40 back, top
{ 0, 4, 5, 6, 2, 3, 0, 6}, //41 back, top, left
{ 1, 2, 3, 7, 4, 5, 1, 6}, //42 back, top, right
{-1,-1,-1,-1,-1,-1,-1, 0}, //43 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //44 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //45 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //46 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //47 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //48 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //49 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //50 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //51 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //52 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //53 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //54 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //55 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //56 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //57 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //58 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //59 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //60 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //61 invalid
{-1,-1,-1,-1,-1,-1,-1, 0}, //62 invalid
{-1,-1,-1,-1,-1,-1,-1, 0} //63 invalid
};
const sbyte* AABB::ComputeOutline(const Point& local_eye, sdword& num) const
{
// Get box corners
Point min; GetMin(min);
Point max; GetMax(max);
// Compute 6-bit code to classify eye with respect to the 6 defining planes of the bbox
int pos = ((local_eye.x < min.x) ? 1 : 0) // 1 = left
+ ((local_eye.x > max.x) ? 2 : 0) // 2 = right
+ ((local_eye.y < min.y) ? 4 : 0) // 4 = bottom
+ ((local_eye.y > max.y) ? 8 : 0) // 8 = top
+ ((local_eye.z < min.z) ? 16 : 0) // 16 = front
+ ((local_eye.z > max.z) ? 32 : 0); // 32 = back
// Look up number of vertices in outline
num = (sdword)gIndexList[pos][7];
// Zero indicates invalid case
if(!num) return null;
return &gIndexList[pos][0];
}
// calculateBoxArea: computes the screen-projected 2D area of an oriented 3D bounding box
//const Point& eye, //eye point (in bbox object coordinates)
//const AABB& box, //3d bbox
//const Matrix4x4& mat, //free transformation for bbox
//float width, float height, int& num)
float AABB::ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const
{
const sbyte* Outline = ComputeOutline(eye, num);
if(!Outline) return -1.0f;
// Compute box vertices
Point vertexBox[8], dst[8];
ComputePoints(vertexBox);
// Transform all outline corners into 2D screen space
for(sdword i=0;i<num;i++)
{
HPoint Projected;
vertexBox[Outline[i]].ProjectToScreen(width, height, mat, Projected);
dst[i] = Projected;
}
float Sum = (dst[num-1][0] - dst[0][0]) * (dst[num-1][1] + dst[0][1]);
for(int i=0; i<num-1; i++)
Sum += (dst[i][0] - dst[i+1][0]) * (dst[i][1] + dst[i+1][1]);
return Sum * 0.5f; //return computed value corrected by 0.5
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an allocator base class.
* \file IceAllocator.h
* \author Pierre Terdiman
* \date December, 19, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEALLOCATOR_H
#define ICEALLOCATOR_H
enum MemoryType
{
MEMORY_PERSISTENT,
MEMORY_TEMP,
};
class ICECORE_API Allocator
{
public:
virtual void* malloc(size_t size, MemoryType type) = 0;
virtual void* mallocDebug(size_t size, const char* filename, udword line, const char* class_name, MemoryType type) = 0;
virtual void* realloc(void* memory, size_t size) = 0;
virtual void* shrink(void* memory, size_t size) = 0;
virtual void free(void* memory) = 0;
};
FUNCTION ICECORE_API Allocator* GetAllocator();
FUNCTION ICECORE_API bool SetAllocator(Allocator& allocator);
FUNCTION ICECORE_API void DumpMemory();
class ICECORE_API Allocateable
{
public:
#ifdef DONT_TRACK_MEMORY_LEAKS
inline_ void* operator new (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
inline_ void* operator new (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
inline_ void* operator new[] (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
inline_ void* operator new[] (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
inline_ void operator delete (void* p) { GetAllocator()->free(p); }
inline_ void operator delete (void* p, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
#endif
};
#endif // ICEALLOCATOR_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an allocator base class.
* \file IceAllocator.h
* \author Pierre Terdiman
* \date December, 19, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEALLOCATOR_H
#define ICEALLOCATOR_H
enum MemoryType
{
MEMORY_PERSISTENT,
MEMORY_TEMP,
};
class ICECORE_API Allocator
{
public:
virtual void* malloc(size_t size, MemoryType type) = 0;
virtual void* mallocDebug(size_t size, const char* filename, udword line, const char* class_name, MemoryType type) = 0;
virtual void* realloc(void* memory, size_t size) = 0;
virtual void* shrink(void* memory, size_t size) = 0;
virtual void free(void* memory) = 0;
};
FUNCTION ICECORE_API Allocator* GetAllocator();
FUNCTION ICECORE_API bool SetAllocator(Allocator& allocator);
FUNCTION ICECORE_API void DumpMemory();
class ICECORE_API Allocateable
{
public:
#ifdef DONT_TRACK_MEMORY_LEAKS
inline_ void* operator new (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
inline_ void* operator new (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
inline_ void* operator new[] (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
inline_ void* operator new[] (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
inline_ void operator delete (void* p) { GetAllocator()->free(p); }
inline_ void operator delete (void* p, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p, MemoryType) { GetAllocator()->free(p); }
inline_ void operator delete[] (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
#endif
};
#endif // ICEALLOCATOR_H

View File

@@ -1,48 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom assertion code.
* \file IceAssert.h
* \author Pierre Terdiman
* \date January, 14, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEASSERT_H
#define ICEASSERT_H
// Leave the {} so that you can write this kind of things safely in release mode:
// if(condition) ASSERT()
#ifndef ASSERT
#if defined( _DEBUG )
FUNCTION ICECORE_API bool CustomAssertFunction(int, char*, int, char*, bool&);
//! Custom ASSERT function. Various usages:
//! ASSERT(condition)
//! ASSERT(!"Not implemented")
//! ASSERT(condition && "error text")
#define ASSERT(exp) \
{ \
static bool IgnoreAlways = false; \
if(!IgnoreAlways) \
{ \
if(CustomAssertFunction((int)(exp), #exp, __LINE__, __FILE__, IgnoreAlways)) \
{ \
_asm { int 3 } \
} \
} \
}
#else
#define ASSERT(exp) {}
#endif
#endif
#ifndef assert
#define assert ASSERT
#endif
#define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ]
#endif // ICEASSERT_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom assertion code.
* \file IceAssert.h
* \author Pierre Terdiman
* \date January, 14, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEASSERT_H
#define ICEASSERT_H
// Leave the {} so that you can write this kind of things safely in release mode:
// if(condition) ASSERT()
#ifndef ASSERT
#if defined( _DEBUG )
FUNCTION ICECORE_API bool CustomAssertFunction(int, char*, int, char*, bool&);
//! Custom ASSERT function. Various usages:
//! ASSERT(condition)
//! ASSERT(!"Not implemented")
//! ASSERT(condition && "error text")
#define ASSERT(exp) \
{ \
static bool IgnoreAlways = false; \
if(!IgnoreAlways) \
{ \
if(CustomAssertFunction((int)(exp), #exp, __LINE__, __FILE__, IgnoreAlways)) \
{ \
_asm { int 3 } \
} \
} \
}
#else
#define ASSERT(exp) {}
#endif
#endif
#ifndef assert
#define assert ASSERT
#endif
#define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ]
#endif // ICEASSERT_H

View File

@@ -1,70 +1,70 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains axes definition.
* \file IceAxes.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEAXES_H__
#define __ICEAXES_H__
enum PointComponent
{
_X = 0,
_Y = 1,
_Z = 2,
_W = 3,
_FORCE_DWORD = 0x7fffffff
};
enum AxisOrder
{
AXES_XYZ = (_X)|(_Y<<2)|(_Z<<4),
AXES_XZY = (_X)|(_Z<<2)|(_Y<<4),
AXES_YXZ = (_Y)|(_X<<2)|(_Z<<4),
AXES_YZX = (_Y)|(_Z<<2)|(_X<<4),
AXES_ZXY = (_Z)|(_X<<2)|(_Y<<4),
AXES_ZYX = (_Z)|(_Y<<2)|(_X<<4),
AXES_FORCE_DWORD = 0x7fffffff
};
class ICEMATHS_API Axes
{
public:
inline_ Axes(AxisOrder order)
{
mAxis0 = (order ) & 3;
mAxis1 = (order>>2) & 3;
mAxis2 = (order>>4) & 3;
}
inline_ ~Axes() {}
udword mAxis0;
udword mAxis1;
udword mAxis2;
};
#endif // __ICEAXES_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains axes definition.
* \file IceAxes.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEAXES_H__
#define __ICEAXES_H__
enum PointComponent
{
_X = 0,
_Y = 1,
_Z = 2,
_W = 3,
_FORCE_DWORD = 0x7fffffff
};
enum AxisOrder
{
AXES_XYZ = (_X)|(_Y<<2)|(_Z<<4),
AXES_XZY = (_X)|(_Z<<2)|(_Y<<4),
AXES_YXZ = (_Y)|(_X<<2)|(_Z<<4),
AXES_YZX = (_Y)|(_Z<<2)|(_X<<4),
AXES_ZXY = (_Z)|(_X<<2)|(_Y<<4),
AXES_ZYX = (_Z)|(_Y<<2)|(_X<<4),
AXES_FORCE_DWORD = 0x7fffffff
};
class ICEMATHS_API Axes
{
public:
inline_ Axes(AxisOrder order)
{
mAxis0 = (order ) & 3;
mAxis1 = (order>>2) & 3;
mAxis2 = (order>>4) & 3;
}
inline_ ~Axes() {}
udword mAxis0;
udword mAxis1;
udword mAxis2;
};
#endif // __ICEAXES_H__

View File

@@ -1,73 +1,73 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for bit arrays.
* \file IceBitArray.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A simple array of bits stored as bytes.
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "StdAfx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::BitArray() : mSize(0), mBits(null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::BitArray(udword nb_bits) : mSize(0), mBits(null)
{
Init(nb_bits);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::~BitArray()
{
ICE_FREE(mBits);
mSize = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the bit array for a given number of entries
* \param nb_bits [in] max number of entries in the array
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BitArray::Init(udword nb_bits)
{
mSize = BitsToDwords(nb_bits);
// Get ram for n bits
ICE_FREE(mBits);
mBits = (udword*)ICE_ALLOC(sizeof(udword)*mSize);
// Set all bits to 0
ClearAll();
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for bit arrays.
* \file IceBitArray.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A simple array of bits stored as bytes.
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "StdAfx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::BitArray() : mSize(0), mBits(null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::BitArray(udword nb_bits) : mSize(0), mBits(null)
{
Init(nb_bits);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BitArray::~BitArray()
{
ICE_FREE(mBits);
mSize = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the bit array for a given number of entries
* \param nb_bits [in] max number of entries in the array
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BitArray::Init(udword nb_bits)
{
mSize = BitsToDwords(nb_bits);
// Get ram for n bits
ICE_FREE(mBits);
mBits = (udword*)ICE_ALLOC(sizeof(udword)*mSize);
// Set all bits to 0
ClearAll();
return true;
}

View File

@@ -1,82 +1,82 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for bit arrays.
* \file IceBitArray.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEBITARRAY_H
#define ICEBITARRAY_H
inline_ udword BitsToBytes(udword nb_bits)
{
return (nb_bits>>3) + ((nb_bits&7) ? 1 : 0);
}
inline_ udword BitsToDwords(udword nb_bits)
{
return (nb_bits>>5) + ((nb_bits&31) ? 1 : 0);
}
// Use that one instead of an array of bools. Takes less ram, nearly as fast [no bounds checkings and so on].
class ICECORE_API BitArray
{
public:
//! Constructor
BitArray();
BitArray(udword nb_bits);
//! Destructor
~BitArray();
bool Init(udword nb_bits);
// Data management
inline_ void SetBit(udword bit_number) { mBits[bit_number>>5] |= 1<<(bit_number&31); }
inline_ void ClearBit(udword bit_number) { mBits[bit_number>>5] &= ~(1<<(bit_number&31)); }
inline_ void ToggleBit(udword bit_number) { mBits[bit_number>>5] ^= 1<<(bit_number&31); }
inline_ void ClearAll() { ZeroMemory(mBits, mSize*4); }
inline_ void SetAll() { FillMemory(mBits, mSize*4, 0xff); }
// Data access
inline_ BOOL IsSet(udword bit_number) const { return mBits[bit_number>>5] & (1<<(bit_number&31)); }
inline_ const udword* GetBits() const { return mBits; }
inline_ udword GetSize() const { return mSize; }
protected:
udword* mBits; //!< Array of bits
udword mSize; //!< Size of the array in dwords
};
// - We consider square symmetric N*N matrices
// - A N*N symmetric matrix has N(N+1)/2 elements
// - A boolean version needs N(N+1)/16 bytes
// N NbBits NbBytes
// 4 10 -
// 8 36 4.5
// 16 136 17 <= the one we select
// 32 528 66
static ubyte BitMasks[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
static ubyte NegBitMasks[] = { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F };
class ICECORE_API BoolSquareSymmetricMatrix16
{
public:
inline_ udword Index(udword x, udword y) const { if(x>y) Swap(x,y); return x + (y ? ((y-1)*y)>>1 : 0); }
inline_ void Set(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] |= BitMasks[i&7]; }
inline_ void Clear(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] &= NegBitMasks[i&7]; }
inline_ void Toggle(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] ^= BitMasks[i&7]; }
inline_ bool IsSet(udword x, udword y) const { udword i = Index(x, y); return (mBits[i>>3] & BitMasks[i&7])!=0; }
inline_ void ClearAll() { ZeroMemory(mBits, 17); }
inline_ void SetAll() { FillMemory(mBits, 17, 0xff); }
ubyte mBits[17];
};
#endif // ICEBITARRAY_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for bit arrays.
* \file IceBitArray.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEBITARRAY_H
#define ICEBITARRAY_H
inline_ udword BitsToBytes(udword nb_bits)
{
return (nb_bits>>3) + ((nb_bits&7) ? 1 : 0);
}
inline_ udword BitsToDwords(udword nb_bits)
{
return (nb_bits>>5) + ((nb_bits&31) ? 1 : 0);
}
// Use that one instead of an array of bools. Takes less ram, nearly as fast [no bounds checkings and so on].
class ICECORE_API BitArray
{
public:
//! Constructor
BitArray();
BitArray(udword nb_bits);
//! Destructor
~BitArray();
bool Init(udword nb_bits);
// Data management
inline_ void SetBit(udword bit_number) { mBits[bit_number>>5] |= 1<<(bit_number&31); }
inline_ void ClearBit(udword bit_number) { mBits[bit_number>>5] &= ~(1<<(bit_number&31)); }
inline_ void ToggleBit(udword bit_number) { mBits[bit_number>>5] ^= 1<<(bit_number&31); }
inline_ void ClearAll() { ZeroMemory(mBits, mSize*4); }
inline_ void SetAll() { FillMemory(mBits, mSize*4, 0xff); }
// Data access
inline_ BOOL IsSet(udword bit_number) const { return mBits[bit_number>>5] & (1<<(bit_number&31)); }
inline_ const udword* GetBits() const { return mBits; }
inline_ udword GetSize() const { return mSize; }
protected:
udword* mBits; //!< Array of bits
udword mSize; //!< Size of the array in dwords
};
// - We consider square symmetric N*N matrices
// - A N*N symmetric matrix has N(N+1)/2 elements
// - A boolean version needs N(N+1)/16 bytes
// N NbBits NbBytes
// 4 10 -
// 8 36 4.5
// 16 136 17 <= the one we select
// 32 528 66
static ubyte BitMasks[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
static ubyte NegBitMasks[] = { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F };
class ICECORE_API BoolSquareSymmetricMatrix16
{
public:
inline_ udword Index(udword x, udword y) const { if(x>y) Swap(x,y); return x + (y ? ((y-1)*y)>>1 : 0); }
inline_ void Set(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] |= BitMasks[i&7]; }
inline_ void Clear(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] &= NegBitMasks[i&7]; }
inline_ void Toggle(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] ^= BitMasks[i&7]; }
inline_ bool IsSet(udword x, udword y) const { udword i = Index(x, y); return (mBits[i>>3] & BitMasks[i&7])!=0; }
inline_ void ClearAll() { ZeroMemory(mBits, 17); }
inline_ void SetAll() { FillMemory(mBits, 17, 0xff); }
ubyte mBits[17];
};
#endif // ICEBITARRAY_H

View File

@@ -1,158 +1,158 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to compute the minimal bounding sphere.
* \file IceBoundingSphere.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEBOUNDINGSPHERE_H__
#define __ICEBOUNDINGSPHERE_H__
enum BSphereMethod
{
BS_NONE,
BS_GEMS,
BS_MINIBALL,
BS_FORCE_DWORD = 0x7fffffff
};
class ICEMATHS_API Sphere
{
public:
//! Constructor
inline_ Sphere() {}
//! Constructor
inline_ Sphere(const Point& center, float radius) : mCenter(center), mRadius(radius) {}
//! Constructor
Sphere(udword nb_verts, const Point* verts);
//! Copy constructor
inline_ Sphere(const Sphere& sphere) : mCenter(sphere.mCenter), mRadius(sphere.mRadius) {}
//! Destructor
inline_ ~Sphere() {}
BSphereMethod Compute(udword nb_verts, const Point* verts);
bool FastCompute(udword nb_verts, const Point* verts);
// Access methods
inline_ const Point& GetCenter() const { return mCenter; }
inline_ float GetRadius() const { return mRadius; }
inline_ const Point& Center() const { return mCenter; }
inline_ float Radius() const { return mRadius; }
inline_ Sphere& Set(const Point& center, float radius) { mCenter = center; mRadius = radius; return *this; }
inline_ Sphere& SetCenter(const Point& center) { mCenter = center; return *this; }
inline_ Sphere& SetRadius(float radius) { mRadius = radius; return *this; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the sphere.
* \param p [in] the point to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Point& p) const
{
return mCenter.SquareDistance(p) <= mRadius*mRadius;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a sphere is contained within the sphere.
* \param sphere [in] the sphere to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Sphere& sphere) const
{
// If our radius is the smallest, we can't possibly contain the other sphere
if(mRadius < sphere.mRadius) return false;
// So r is always positive or null now
float r = mRadius - sphere.mRadius;
return mCenter.SquareDistance(sphere.mCenter) <= r*r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a box is contained within the sphere.
* \param aabb [in] the box to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Contains(const AABB& aabb) const
{
// I assume if all 8 box vertices are inside the sphere, so does the whole box.
// Sounds ok but maybe there's a better way?
float R2 = mRadius * mRadius;
#ifdef USE_MIN_MAX
const Point& Max = ((ShadowAABB&)&aabb).mMax;
const Point& Min = ((ShadowAABB&)&aabb).mMin;
#else
Point Max; aabb.GetMax(Max);
Point Min; aabb.GetMin(Min);
#endif
Point p;
p.x=Max.x; p.y=Max.y; p.z=Max.z; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Max.y; p.z=Min.z; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if the sphere intersects another sphere
* \param sphere [in] the other sphere
* \return true if spheres overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Intersect(const Sphere& sphere) const
{
float r = mRadius + sphere.mRadius;
return mCenter.SquareDistance(sphere.mCenter) <= r*r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the sphere is valid.
* \return true if the box is valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsValid() const
{
// Consistency condition for spheres: Radius >= 0.0f
if(mRadius < 0.0f) return FALSE;
return TRUE;
}
public:
Point mCenter; //!< Sphere center
float mRadius; //!< Sphere radius
};
#endif // __ICEBOUNDINGSPHERE_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to compute the minimal bounding sphere.
* \file IceBoundingSphere.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEBOUNDINGSPHERE_H__
#define __ICEBOUNDINGSPHERE_H__
enum BSphereMethod
{
BS_NONE,
BS_GEMS,
BS_MINIBALL,
BS_FORCE_DWORD = 0x7fffffff
};
class ICEMATHS_API Sphere
{
public:
//! Constructor
inline_ Sphere() {}
//! Constructor
inline_ Sphere(const Point& center, float radius) : mCenter(center), mRadius(radius) {}
//! Constructor
Sphere(udword nb_verts, const Point* verts);
//! Copy constructor
inline_ Sphere(const Sphere& sphere) : mCenter(sphere.mCenter), mRadius(sphere.mRadius) {}
//! Destructor
inline_ ~Sphere() {}
BSphereMethod Compute(udword nb_verts, const Point* verts);
bool FastCompute(udword nb_verts, const Point* verts);
// Access methods
inline_ const Point& GetCenter() const { return mCenter; }
inline_ float GetRadius() const { return mRadius; }
inline_ const Point& Center() const { return mCenter; }
inline_ float Radius() const { return mRadius; }
inline_ Sphere& Set(const Point& center, float radius) { mCenter = center; mRadius = radius; return *this; }
inline_ Sphere& SetCenter(const Point& center) { mCenter = center; return *this; }
inline_ Sphere& SetRadius(float radius) { mRadius = radius; return *this; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the sphere.
* \param p [in] the point to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Point& p) const
{
return mCenter.SquareDistance(p) <= mRadius*mRadius;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a sphere is contained within the sphere.
* \param sphere [in] the sphere to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Sphere& sphere) const
{
// If our radius is the smallest, we can't possibly contain the other sphere
if(mRadius < sphere.mRadius) return false;
// So r is always positive or null now
float r = mRadius - sphere.mRadius;
return mCenter.SquareDistance(sphere.mCenter) <= r*r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a box is contained within the sphere.
* \param aabb [in] the box to test
* \return true if inside the sphere
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Contains(const AABB& aabb) const
{
// I assume if all 8 box vertices are inside the sphere, so does the whole box.
// Sounds ok but maybe there's a better way?
float R2 = mRadius * mRadius;
#ifdef USE_MIN_MAX
const Point& Max = ((ShadowAABB&)&aabb).mMax;
const Point& Min = ((ShadowAABB&)&aabb).mMin;
#else
Point Max; aabb.GetMax(Max);
Point Min; aabb.GetMin(Min);
#endif
Point p;
p.x=Max.x; p.y=Max.y; p.z=Max.z; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Max.y; p.z=Min.z; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE;
p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if the sphere intersects another sphere
* \param sphere [in] the other sphere
* \return true if spheres overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Intersect(const Sphere& sphere) const
{
float r = mRadius + sphere.mRadius;
return mCenter.SquareDistance(sphere.mCenter) <= r*r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the sphere is valid.
* \return true if the box is valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsValid() const
{
// Consistency condition for spheres: Radius >= 0.0f
if(mRadius < 0.0f) return FALSE;
return TRUE;
}
public:
Point mCenter; //!< Sphere center
float mRadius; //!< Sphere radius
};
#endif // __ICEBOUNDINGSPHERE_H__

View File

@@ -1,423 +1,423 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a list of 32-bits values.
* Use this class when you need to store an unknown number of values. The list is automatically
* resized and can contains 32-bits entities (dwords or floats)
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "StdAfx.h"
using namespace Opcode;
// Static members
#ifdef CONTAINER_STATS
udword Container::mNbContainers = 0;
udword Container::mUsedRam = 0;
LinkedList Container::mContainers;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. No entries allocated there.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. Also allocates a given number of entries.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null)
{
SetGrowthFactor(growth_factor);
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
SetSize(size);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Copy constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
*this = object;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor. Frees everything and leaves.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::~Container()
{
Empty();
#ifdef CONTAINER_STATS
mNbContainers--;
mUsedRam-=GetUsedRam();
mContainers.RemElem(this);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
* \param max_entries [in] max number of entries in the container
* \param entries [in] external memory buffer
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Container::InitSharedBuffers(udword max_entries, udword* entries)
{
Empty(); // Make sure everything has been released
mMaxNbEntries = max_entries;
mEntries = entries;
mGrowthFactor = -1.0f; // Negative growth ==> resize is disabled
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::Empty()
{
#ifdef CONTAINER_STATS
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
if(mGrowthFactor>=0.0f) ICE_FREE(mEntries); // Release memory if we own it
mCurNbEntries = mMaxNbEntries = 0;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resizes the container.
* \param needed [in] assume the container can be added at least "needed" values
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Resize(udword needed)
{
// Check growth is allowed
if(mGrowthFactor<=0.0f)
{
ASSERT(!"Invalid operation - trying to resize a static buffer!");
return false;
}
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get more entries
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
// Get some bytes for new entries
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data if needed
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
ICE_FREE(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::SetSize(udword nb)
{
// Make sure it's empty
Empty();
// Checkings
if(!nb) return false;
// Initialize for nb entries
mMaxNbEntries = nb;
// Get some bytes for new entries
mEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(mEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Refit()
{
// Check refit is allowed
if(mGrowthFactor<=0.0f)
{
ASSERT(!"Invalid operation - trying to refit a static buffer!");
return false;
}
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
if(!mMaxNbEntries) return false;
// Get just enough bytes
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
ICE_FREE(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
// Same as Refit but more efficient
bool Container::Shrink()
{
if(!mEntries) return false;
if(!mCurNbEntries)
{
Empty();
return true;
}
// Try to shrink the pointer
if(!GetAllocator()->shrink(mEntries, sizeof(udword)*mCurNbEntries))
return false;
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the container already contains a given value.
* \param entry [in] the value to look for in the container
* \param location [out] a possible pointer to store the entry location
* \see Add(udword entry)
* \see Add(float entry)
* \see Empty()
* \return true if the value has been found in the container, else false.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Contains(udword entry, udword* location) const
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
if(location) *location = i;
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Delete(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
DeleteIndex(i);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::DeleteKeepingOrder(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i.
// Shift entries to preserve order. You really should use a linked list instead.
mCurNbEntries--;
for(udword j=i;j<mCurNbEntries;j++)
{
mEntries[j] = mEntries[j+1];
}
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the next entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the next entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindNext(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location++;
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the previous entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindPrev(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location--;
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the ram used by the container.
* \return the ram used in bytes.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Container::GetUsedRam() const
{
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
}
float Container::GetGrowthFactor() const
{
return mGrowthFactor;
}
void Container::SetGrowthFactor(float growth)
{
// Negative growths are reserved for internal usages
if(growth<0.0f) growth = 0.0f;
mGrowthFactor = growth;
}
//! Operator for "Container A = Container B"
void Container::operator=(const Container& object)
{
SetSize(object.GetNbEntries());
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
mCurNbEntries = mMaxNbEntries;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a list of 32-bits values.
* Use this class when you need to store an unknown number of values. The list is automatically
* resized and can contains 32-bits entities (dwords or floats)
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "StdAfx.h"
using namespace Opcode;
// Static members
#ifdef CONTAINER_STATS
udword Container::mNbContainers = 0;
udword Container::mUsedRam = 0;
LinkedList Container::mContainers;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. No entries allocated there.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. Also allocates a given number of entries.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null)
{
SetGrowthFactor(growth_factor);
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
SetSize(size);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Copy constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
mContainers.AddElem(this);
#endif
*this = object;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor. Frees everything and leaves.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::~Container()
{
Empty();
#ifdef CONTAINER_STATS
mNbContainers--;
mUsedRam-=GetUsedRam();
mContainers.RemElem(this);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
* \param max_entries [in] max number of entries in the container
* \param entries [in] external memory buffer
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Container::InitSharedBuffers(udword max_entries, udword* entries)
{
Empty(); // Make sure everything has been released
mMaxNbEntries = max_entries;
mEntries = entries;
mGrowthFactor = -1.0f; // Negative growth ==> resize is disabled
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::Empty()
{
#ifdef CONTAINER_STATS
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
if(mGrowthFactor>=0.0f) ICE_FREE(mEntries); // Release memory if we own it
mCurNbEntries = mMaxNbEntries = 0;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resizes the container.
* \param needed [in] assume the container can be added at least "needed" values
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Resize(udword needed)
{
// Check growth is allowed
if(mGrowthFactor<=0.0f)
{
ASSERT(!"Invalid operation - trying to resize a static buffer!");
return false;
}
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get more entries
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
// Get some bytes for new entries
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data if needed
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
ICE_FREE(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::SetSize(udword nb)
{
// Make sure it's empty
Empty();
// Checkings
if(!nb) return false;
// Initialize for nb entries
mMaxNbEntries = nb;
// Get some bytes for new entries
mEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(mEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Refit()
{
// Check refit is allowed
if(mGrowthFactor<=0.0f)
{
ASSERT(!"Invalid operation - trying to refit a static buffer!");
return false;
}
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
if(!mMaxNbEntries) return false;
// Get just enough bytes
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
ICE_FREE(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
// Same as Refit but more efficient
bool Container::Shrink()
{
if(!mEntries) return false;
if(!mCurNbEntries)
{
Empty();
return true;
}
// Try to shrink the pointer
if(!GetAllocator()->shrink(mEntries, sizeof(udword)*mCurNbEntries))
return false;
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the container already contains a given value.
* \param entry [in] the value to look for in the container
* \param location [out] a possible pointer to store the entry location
* \see Add(udword entry)
* \see Add(float entry)
* \see Empty()
* \return true if the value has been found in the container, else false.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Contains(udword entry, udword* location) const
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
if(location) *location = i;
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Delete(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
DeleteIndex(i);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::DeleteKeepingOrder(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i.
// Shift entries to preserve order. You really should use a linked list instead.
mCurNbEntries--;
for(udword j=i;j<mCurNbEntries;j++)
{
mEntries[j] = mEntries[j+1];
}
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the next entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the next entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindNext(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location++;
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the previous entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindPrev(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location--;
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the ram used by the container.
* \return the ram used in bytes.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Container::GetUsedRam() const
{
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
}
float Container::GetGrowthFactor() const
{
return mGrowthFactor;
}
void Container::SetGrowthFactor(float growth)
{
// Negative growths are reserved for internal usages
if(growth<0.0f) growth = 0.0f;
mGrowthFactor = growth;
}
//! Operator for "Container A = Container B"
void Container::operator=(const Container& object)
{
SetSize(object.GetNbEntries());
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
mCurNbEntries = mMaxNbEntries;
}

View File

@@ -1,254 +1,254 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICECONTAINER_H
#define ICECONTAINER_H
// #define CONTAINER_STATS // #### doesn't work with micro-threads!
class LinkedList;
enum FindMode
{
FIND_CLAMP,
FIND_WRAP,
FIND_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API Container : public Allocateable
#ifdef CONTAINER_STATS
, public ListElem
#endif
{
public:
// Constructor / Destructor
Container();
Container(const Container& object);
Container(udword size, float growth_factor);
~Container();
// Management
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
* \param max_entries [in] max number of entries in the container
* \param entries [in] external memory buffer
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void InitSharedBuffers(udword max_entries, udword* entries);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a udword to store in the container
* \see Add(float entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(udword entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = entry;
return *this;
}
inline_ Container& Add(const udword* entries, udword nb)
{
if(entries && nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
mCurNbEntries += nb;
}
return *this;
}
inline_ Container& Add(const Container& container)
{
return Add(container.GetEntries(), container.GetNbEntries());
}
inline_ udword* Reserve(udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// We expect the user to fill reserved memory with 'nb' udwords
udword* Reserved = &mEntries[mCurNbEntries];
// Meanwhile, we do as if it had been filled
mCurNbEntries += nb;
// This is mainly used to avoid the copy when possible
return Reserved;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a float to store in the container
* \see Add(udword entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(float entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = IR(entry);
return *this;
}
inline_ Container& Add(const float* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float));
mCurNbEntries+=nb;
return *this;
}
//! Add unique [slow]
inline_ Container& AddUnique(udword entry)
{
if(!Contains(entry)) Add(entry);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Empty();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again.
* That's a kind of temporal coherence.
* \see Empty()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Reset()
{
// Avoid the write if possible
// ### CMOV
if(mCurNbEntries) mCurNbEntries = 0;
}
// HANDLE WITH CARE - I hope you know what you're doing
inline_ void ForceSize(udword size)
{
mCurNbEntries = size;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetSize(udword nb);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Refit();
bool Shrink();
// Checks whether the container already contains a given value.
bool Contains(udword entry, udword* location=null) const;
// Deletes an entry - doesn't preserve insertion order.
bool Delete(udword entry);
// Deletes an entry - does preserve insertion order.
bool DeleteKeepingOrder(udword entry);
//! Deletes the very last entry.
inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; }
//! Deletes the entry whose index is given
inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; }
// Helpers
Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP);
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
// Data access.
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
inline_ udword GetMaxNbEntries() const { return mMaxNbEntries; } //!< Returns max number of entries before resizing.
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry.
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
inline_ udword GetFirst() const { return mEntries[0]; }
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
// Growth control
float GetGrowthFactor() const; //!< Returns the growth factor
void SetGrowthFactor(float growth); //!< Sets the growth factor
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
//! Read-access as an array
inline_ udword operator[](udword i) const { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
//! Write-access as an array
inline_ udword& operator[](udword i) { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
// Stats
udword GetUsedRam() const;
//! Operator for "Container A = Container B"
void operator = (const Container& object);
#ifdef CONTAINER_STATS
static udword GetNbContainers() { return mNbContainers; }
static udword GetTotalBytes() { return mUsedRam; }
static LinkedList& GetContainers() { return mContainers; }
private:
static udword mNbContainers; //!< Number of containers around
static udword mUsedRam; //!< Amount of bytes used by containers in the system
static LinkedList mContainers;
#endif
private:
// Resizing
bool Resize(udword needed=1);
// Data
udword mMaxNbEntries; //!< Maximum possible number of entries
udword mCurNbEntries; //!< Current number of entries
udword* mEntries; //!< List of entries
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
};
#endif // ICECONTAINER_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICECONTAINER_H
#define ICECONTAINER_H
// #define CONTAINER_STATS // #### doesn't work with micro-threads!
class LinkedList;
enum FindMode
{
FIND_CLAMP,
FIND_WRAP,
FIND_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API Container : public Allocateable
#ifdef CONTAINER_STATS
, public ListElem
#endif
{
public:
// Constructor / Destructor
Container();
Container(const Container& object);
Container(udword size, float growth_factor);
~Container();
// Management
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
* \param max_entries [in] max number of entries in the container
* \param entries [in] external memory buffer
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void InitSharedBuffers(udword max_entries, udword* entries);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a udword to store in the container
* \see Add(float entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(udword entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = entry;
return *this;
}
inline_ Container& Add(const udword* entries, udword nb)
{
if(entries && nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
mCurNbEntries += nb;
}
return *this;
}
inline_ Container& Add(const Container& container)
{
return Add(container.GetEntries(), container.GetNbEntries());
}
inline_ udword* Reserve(udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// We expect the user to fill reserved memory with 'nb' udwords
udword* Reserved = &mEntries[mCurNbEntries];
// Meanwhile, we do as if it had been filled
mCurNbEntries += nb;
// This is mainly used to avoid the copy when possible
return Reserved;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a float to store in the container
* \see Add(udword entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(float entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = IR(entry);
return *this;
}
inline_ Container& Add(const float* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float));
mCurNbEntries+=nb;
return *this;
}
//! Add unique [slow]
inline_ Container& AddUnique(udword entry)
{
if(!Contains(entry)) Add(entry);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Empty();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again.
* That's a kind of temporal coherence.
* \see Empty()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Reset()
{
// Avoid the write if possible
// ### CMOV
if(mCurNbEntries) mCurNbEntries = 0;
}
// HANDLE WITH CARE - I hope you know what you're doing
inline_ void ForceSize(udword size)
{
mCurNbEntries = size;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetSize(udword nb);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Refit();
bool Shrink();
// Checks whether the container already contains a given value.
bool Contains(udword entry, udword* location=null) const;
// Deletes an entry - doesn't preserve insertion order.
bool Delete(udword entry);
// Deletes an entry - does preserve insertion order.
bool DeleteKeepingOrder(udword entry);
//! Deletes the very last entry.
inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; }
//! Deletes the entry whose index is given
inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; }
// Helpers
Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP);
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
// Data access.
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
inline_ udword GetMaxNbEntries() const { return mMaxNbEntries; } //!< Returns max number of entries before resizing.
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry.
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
inline_ udword GetFirst() const { return mEntries[0]; }
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
// Growth control
float GetGrowthFactor() const; //!< Returns the growth factor
void SetGrowthFactor(float growth); //!< Sets the growth factor
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
//! Read-access as an array
inline_ udword operator[](udword i) const { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
//! Write-access as an array
inline_ udword& operator[](udword i) { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
// Stats
udword GetUsedRam() const;
//! Operator for "Container A = Container B"
void operator = (const Container& object);
#ifdef CONTAINER_STATS
static udword GetNbContainers() { return mNbContainers; }
static udword GetTotalBytes() { return mUsedRam; }
static LinkedList& GetContainers() { return mContainers; }
private:
static udword mNbContainers; //!< Number of containers around
static udword mUsedRam; //!< Amount of bytes used by containers in the system
static LinkedList mContainers;
#endif
private:
// Resizing
bool Resize(udword needed=1);
// Data
udword mMaxNbEntries; //!< Maximum possible number of entries
udword mCurNbEntries; //!< Current number of entries
udword* mEntries; //!< List of entries
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
};
#endif // ICECONTAINER_H

View File

@@ -1,403 +1,403 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains FPU related code.
* \file IceFPU.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEFPU_H
#define ICEFPU_H
#define SIGN_BITMASK 0x80000000
//! Integer representation of a floating-point value.
#define IR(x) ((udword&)(x))
//! Signed integer representation of a floating-point value.
#define SIR(x) ((sdword&)(x))
//! Absolute integer representation of a floating-point value
#define AIR(x) (IR(x)&0x7fffffff)
//! Floating-point representation of an integer value.
#define FR(x) ((float&)(x))
//! Integer-based comparison of a floating point value.
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
//! Checks 2 values have different signs
inline_ BOOL DifferentSign(float f0, float f1)
{
return (IR(f0)^IR(f1))&SIGN_BITMASK;
}
//! Fast fabs for floating-point values. It just clears the sign bit.
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
inline_ float FastFabs(float x)
{
udword FloatBits = IR(x)&0x7fffffff;
return FR(FloatBits);
}
//! Fast square root for floating-point values.
inline_ float FastSqrt(float square)
{
float retval;
__asm {
mov eax, square
sub eax, 0x3F800000
sar eax, 1
add eax, 0x3F800000
mov [retval], eax
}
return retval;
}
//! Saturates positive to zero.
inline_ float fsat(float f)
{
udword y = (udword&)f & ~((sdword&)f >>31);
return (float&)y;
}
//! Computes 1.0f / sqrtf(x).
inline_ float frsqrt(float f)
{
float x = f * 0.5f;
udword y = 0x5f3759df - ((udword&)f >> 1);
// Iteration...
(float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) );
// Result
return (float&)y;
}
//! Computes 1.0f / sqrtf(x). Comes from NVIDIA.
inline_ float InvSqrt(const float& x)
{
udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1;
float y = *(float*)&tmp;
return y * (1.47f - 0.47f * x * y * y);
}
//! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above.
//! See http://www.magic-software.com/3DGEDInvSqrt.html
inline_ float RSqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = * (long *) &y;
i = 0x5f3759df - (i >> 1);
y = * (float *) &i;
y = y * (threehalfs - (x2 * y * y));
return y;
}
//! TO BE DOCUMENTED
inline_ float fsqrt(float f)
{
udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000;
// Iteration...?
// (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f;
// Result
return (float&)y;
}
//! Returns the float ranged espilon value.
inline_ float fepsilon(float f)
{
udword b = (udword&)f & 0xff800000;
udword a = b | 0x00000001;
(float&)a -= (float&)b;
// Result
return (float&)a;
}
//! Is the float valid ?
inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; }
inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; }
inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; }
inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; }
inline_ bool IsValidFloat(float value)
{
if(IsNAN(value)) return false;
if(IsIndeterminate(value)) return false;
if(IsPlusInf(value)) return false;
if(IsMinusInf(value)) return false;
return true;
}
#define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x));
/*
//! FPU precision setting function.
inline_ void SetFPU()
{
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.
{
uword wTemp, wSave;
__asm fstcw wSave
if (wSave & 0x300 || // Not single mode
0x3f != (wSave & 0x3f) || // Exceptions enabled
wSave & 0xC00) // Not round to nearest mode
{
__asm
{
mov ax, wSave
and ax, not 300h ;; single mode
or ax, 3fh ;; disable all exceptions
and ax, not 0xC00 ;; round to nearest mode
mov wTemp, ax
fldcw wTemp
}
}
}
}
*/
//! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON)
inline_ float ComputeFloatEpsilon()
{
float f = 1.0f;
((udword&)f)^=1;
return f - 1.0f; // You can check it's the same as FLT_EPSILON
}
inline_ bool IsFloatZero(float x, float epsilon=1e-6f)
{
return x*x < epsilon;
}
#define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0
#define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0
#define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0
#define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0
#define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1
#define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1
#define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1
#define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1
#define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2
#define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2
#define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2
#define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2
#define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3
#define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3
#define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3
#define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3
#define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4
#define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4
#define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4
#define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4
#define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5
#define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5
#define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5
#define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5
#define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6
#define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6
#define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6
#define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6
#define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7
#define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7
#define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7
#define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7
//! A global function to find MAX(a,b) using FCOMI/FCMOV
inline_ float FCMax2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b) using FCOMI/FCMOV
inline_ float FCMin2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVNB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MAX(a,b,c) using FCOMI/FCMOV
inline_ float FCMax3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MIN(a,b,c) using FCOMI/FCMOV
inline_ float FCMin3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MAX(a,b,c,d) using FCOMI/FCMOV
inline_ float FCMax4(float a, float b, float c, float d)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
_asm fld [d]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
FCOMI_ST3
FCMOVB_ST3
_asm fstp [Res]
_asm fcompp
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b,c,d) using FCOMI/FCMOV
inline_ float FCMin4(float a, float b, float c, float d)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
_asm fld [d]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
FCOMI_ST3
FCMOVNB_ST3
_asm fstp [Res]
_asm fcompp
_asm fcomp
return Res;
}
inline_ int ConvertToSortable(float f)
{
int& Fi = (int&)f;
int Fmask = (Fi>>31);
Fi ^= Fmask;
Fmask &= ~(1<<31);
Fi -= Fmask;
return Fi;
}
inline_ udword EncodeFloat(const float val)
{
// We may need to check on -0 and 0
// But it should make no practical difference.
udword ir = IR(val);
if(ir & 0x80000000) //negative?
ir = ~ir;//reverse sequence of negative numbers
else
ir |= 0x80000000; // flip sign
return ir;
}
inline_ float DecodeFloat(udword ir)
{
udword rv;
if(ir & 0x80000000) //positive?
rv = ir & ~0x80000000; //flip sign
else
rv = ~ir; //undo reversal
return FR(rv);
}
enum FPUMode
{
FPU_FLOOR = 0,
FPU_CEIL = 1,
FPU_BEST = 2,
FPU_FORCE_DWORD = 0x7fffffff
};
FUNCTION ICECORE_API FPUMode GetFPUMode();
FUNCTION ICECORE_API void SaveFPU();
FUNCTION ICECORE_API void RestoreFPU();
FUNCTION ICECORE_API void SetFPUFloorMode();
FUNCTION ICECORE_API void SetFPUCeilMode();
FUNCTION ICECORE_API void SetFPUBestMode();
FUNCTION ICECORE_API void SetFPUPrecision24();
FUNCTION ICECORE_API void SetFPUPrecision53();
FUNCTION ICECORE_API void SetFPUPrecision64();
FUNCTION ICECORE_API void SetFPURoundingChop();
FUNCTION ICECORE_API void SetFPURoundingUp();
FUNCTION ICECORE_API void SetFPURoundingDown();
FUNCTION ICECORE_API void SetFPURoundingNear();
FUNCTION ICECORE_API int intChop(const float& f);
FUNCTION ICECORE_API int intFloor(const float& f);
FUNCTION ICECORE_API int intCeil(const float& f);
inline_ sdword MyFloor(float f)
{
return (sdword)f - (IR(f)>>31);
}
class ICECORE_API FPUGuard
{
public:
FPUGuard();
~FPUGuard();
private:
uword mControlWord;
};
#endif // ICEFPU_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains FPU related code.
* \file IceFPU.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEFPU_H
#define ICEFPU_H
#define SIGN_BITMASK 0x80000000
//! Integer representation of a floating-point value.
#define IR(x) ((udword&)(x))
//! Signed integer representation of a floating-point value.
#define SIR(x) ((sdword&)(x))
//! Absolute integer representation of a floating-point value
#define AIR(x) (IR(x)&0x7fffffff)
//! Floating-point representation of an integer value.
#define FR(x) ((float&)(x))
//! Integer-based comparison of a floating point value.
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
//! Checks 2 values have different signs
inline_ BOOL DifferentSign(float f0, float f1)
{
return (IR(f0)^IR(f1))&SIGN_BITMASK;
}
//! Fast fabs for floating-point values. It just clears the sign bit.
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
inline_ float FastFabs(float x)
{
udword FloatBits = IR(x)&0x7fffffff;
return FR(FloatBits);
}
//! Fast square root for floating-point values.
inline_ float FastSqrt(float square)
{
float retval;
__asm {
mov eax, square
sub eax, 0x3F800000
sar eax, 1
add eax, 0x3F800000
mov [retval], eax
}
return retval;
}
//! Saturates positive to zero.
inline_ float fsat(float f)
{
udword y = (udword&)f & ~((sdword&)f >>31);
return (float&)y;
}
//! Computes 1.0f / sqrtf(x).
inline_ float frsqrt(float f)
{
float x = f * 0.5f;
udword y = 0x5f3759df - ((udword&)f >> 1);
// Iteration...
(float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) );
// Result
return (float&)y;
}
//! Computes 1.0f / sqrtf(x). Comes from NVIDIA.
inline_ float InvSqrt(const float& x)
{
udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1;
float y = *(float*)&tmp;
return y * (1.47f - 0.47f * x * y * y);
}
//! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above.
//! See http://www.magic-software.com/3DGEDInvSqrt.html
inline_ float RSqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = * (long *) &y;
i = 0x5f3759df - (i >> 1);
y = * (float *) &i;
y = y * (threehalfs - (x2 * y * y));
return y;
}
//! TO BE DOCUMENTED
inline_ float fsqrt(float f)
{
udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000;
// Iteration...?
// (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f;
// Result
return (float&)y;
}
//! Returns the float ranged espilon value.
inline_ float fepsilon(float f)
{
udword b = (udword&)f & 0xff800000;
udword a = b | 0x00000001;
(float&)a -= (float&)b;
// Result
return (float&)a;
}
//! Is the float valid ?
inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; }
inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; }
inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; }
inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; }
inline_ bool IsValidFloat(float value)
{
if(IsNAN(value)) return false;
if(IsIndeterminate(value)) return false;
if(IsPlusInf(value)) return false;
if(IsMinusInf(value)) return false;
return true;
}
#define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x));
/*
//! FPU precision setting function.
inline_ void SetFPU()
{
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.
{
uword wTemp, wSave;
__asm fstcw wSave
if (wSave & 0x300 || // Not single mode
0x3f != (wSave & 0x3f) || // Exceptions enabled
wSave & 0xC00) // Not round to nearest mode
{
__asm
{
mov ax, wSave
and ax, not 300h ;; single mode
or ax, 3fh ;; disable all exceptions
and ax, not 0xC00 ;; round to nearest mode
mov wTemp, ax
fldcw wTemp
}
}
}
}
*/
//! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON)
inline_ float ComputeFloatEpsilon()
{
float f = 1.0f;
((udword&)f)^=1;
return f - 1.0f; // You can check it's the same as FLT_EPSILON
}
inline_ bool IsFloatZero(float x, float epsilon=1e-6f)
{
return x*x < epsilon;
}
#define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0
#define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0
#define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0
#define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0
#define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1
#define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1
#define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1
#define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1
#define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2
#define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2
#define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2
#define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2
#define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3
#define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3
#define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3
#define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3
#define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4
#define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4
#define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4
#define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4
#define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5
#define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5
#define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5
#define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5
#define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6
#define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6
#define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6
#define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6
#define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7
#define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7
#define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7
#define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7
//! A global function to find MAX(a,b) using FCOMI/FCMOV
inline_ float FCMax2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b) using FCOMI/FCMOV
inline_ float FCMin2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVNB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MAX(a,b,c) using FCOMI/FCMOV
inline_ float FCMax3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MIN(a,b,c) using FCOMI/FCMOV
inline_ float FCMin3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MAX(a,b,c,d) using FCOMI/FCMOV
inline_ float FCMax4(float a, float b, float c, float d)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
_asm fld [d]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
FCOMI_ST3
FCMOVB_ST3
_asm fstp [Res]
_asm fcompp
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b,c,d) using FCOMI/FCMOV
inline_ float FCMin4(float a, float b, float c, float d)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
_asm fld [d]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
FCOMI_ST3
FCMOVNB_ST3
_asm fstp [Res]
_asm fcompp
_asm fcomp
return Res;
}
inline_ int ConvertToSortable(float f)
{
int& Fi = (int&)f;
int Fmask = (Fi>>31);
Fi ^= Fmask;
Fmask &= ~(1<<31);
Fi -= Fmask;
return Fi;
}
inline_ udword EncodeFloat(const float val)
{
// We may need to check on -0 and 0
// But it should make no practical difference.
udword ir = IR(val);
if(ir & 0x80000000) //negative?
ir = ~ir;//reverse sequence of negative numbers
else
ir |= 0x80000000; // flip sign
return ir;
}
inline_ float DecodeFloat(udword ir)
{
udword rv;
if(ir & 0x80000000) //positive?
rv = ir & ~0x80000000; //flip sign
else
rv = ~ir; //undo reversal
return FR(rv);
}
enum FPUMode
{
FPU_FLOOR = 0,
FPU_CEIL = 1,
FPU_BEST = 2,
FPU_FORCE_DWORD = 0x7fffffff
};
FUNCTION ICECORE_API FPUMode GetFPUMode();
FUNCTION ICECORE_API void SaveFPU();
FUNCTION ICECORE_API void RestoreFPU();
FUNCTION ICECORE_API void SetFPUFloorMode();
FUNCTION ICECORE_API void SetFPUCeilMode();
FUNCTION ICECORE_API void SetFPUBestMode();
FUNCTION ICECORE_API void SetFPUPrecision24();
FUNCTION ICECORE_API void SetFPUPrecision53();
FUNCTION ICECORE_API void SetFPUPrecision64();
FUNCTION ICECORE_API void SetFPURoundingChop();
FUNCTION ICECORE_API void SetFPURoundingUp();
FUNCTION ICECORE_API void SetFPURoundingDown();
FUNCTION ICECORE_API void SetFPURoundingNear();
FUNCTION ICECORE_API int intChop(const float& f);
FUNCTION ICECORE_API int intFloor(const float& f);
FUNCTION ICECORE_API int intCeil(const float& f);
inline_ sdword MyFloor(float f)
{
return (sdword)f - (IR(f)>>31);
}
class ICECORE_API FPUGuard
{
public:
FPUGuard();
~FPUGuard();
private:
uword mControlWord;
};
#endif // ICEFPU_H

View File

@@ -1,87 +1,87 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for homogeneous points.
* \file IceHPoint.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Homogeneous point.
*
* Use it:
* - for clipping in homogeneous space (standard way)
* - to differentiate between points (w=1) and vectors (w=0).
* - in some cases you can also use it instead of Point for padding reasons.
*
* \class HPoint
* \author Pierre Terdiman
* \version 1.0
* \warning No cross-product in 4D.
* \warning HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Point Mul = HPoint * Matrix3x3;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point HPoint::operator*(const Matrix3x3& mat) const
{
return Point(
x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0],
x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1],
x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HPoint Mul = HPoint * Matrix4x4;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HPoint HPoint::operator*(const Matrix4x4& mat) const
{
return HPoint(
x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0],
x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1],
x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2],
x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HPoint *= Matrix4x4
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HPoint& HPoint::operator*=(const Matrix4x4& mat)
{
float xp = x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0];
float yp = x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1];
float zp = x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2];
float wp = x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3];
x = xp; y = yp; z = zp; w = wp;
return *this;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for homogeneous points.
* \file IceHPoint.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Homogeneous point.
*
* Use it:
* - for clipping in homogeneous space (standard way)
* - to differentiate between points (w=1) and vectors (w=0).
* - in some cases you can also use it instead of Point for padding reasons.
*
* \class HPoint
* \author Pierre Terdiman
* \version 1.0
* \warning No cross-product in 4D.
* \warning HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Point Mul = HPoint * Matrix3x3;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point HPoint::operator*(const Matrix3x3& mat) const
{
return Point(
x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0],
x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1],
x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HPoint Mul = HPoint * Matrix4x4;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HPoint HPoint::operator*(const Matrix4x4& mat) const
{
return HPoint(
x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0],
x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1],
x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2],
x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HPoint *= Matrix4x4
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HPoint& HPoint::operator*=(const Matrix4x4& mat)
{
float xp = x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0];
float yp = x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1];
float zp = x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2];
float wp = x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3];
x = xp; y = yp; z = zp; w = wp;
return *this;
}

View File

@@ -1,173 +1,173 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for homogeneous points.
* \file IceHPoint.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEHPOINT_H__
#define __ICEHPOINT_H__
class ICEMATHS_API HPoint : public Point
{
public:
//! Empty constructor
inline_ HPoint() {}
//! Constructor from floats
inline_ HPoint(float _x, float _y, float _z, float _w=0.0f) : Point(_x, _y, _z), w(_w) {}
//! Constructor from array
inline_ HPoint(const float f[4]) : Point(f), w(f[3]) {}
//! Constructor from a Point
inline_ HPoint(const Point& p, float _w=0.0f) : Point(p), w(_w) {}
//! Destructor
inline_ ~HPoint() {}
//! Clear the point
inline_ HPoint& Zero() { x = y = z = w = 0.0f; return *this; }
//! Assignment from values
inline_ HPoint& Set(float _x, float _y, float _z, float _w ) { x = _x; y = _y; z = _z; w = _w; return *this; }
//! Assignment from array
inline_ HPoint& Set(const float f[4]) { x = f[_X]; y = f[_Y]; z = f[_Z]; w = f[_W]; return *this; }
//! Assignment from another h-point
inline_ HPoint& Set(const HPoint& src) { x = src.x; y = src.y; z = src.z; w = src.w; return *this; }
//! Add a vector
inline_ HPoint& Add(float _x, float _y, float _z, float _w ) { x += _x; y += _y; z += _z; w += _w; return *this; }
//! Add a vector
inline_ HPoint& Add(const float f[4]) { x += f[_X]; y += f[_Y]; z += f[_Z]; w += f[_W]; return *this; }
//! Subtract a vector
inline_ HPoint& Sub(float _x, float _y, float _z, float _w ) { x -= _x; y -= _y; z -= _z; w -= _w; return *this; }
//! Subtract a vector
inline_ HPoint& Sub(const float f[4]) { x -= f[_X]; y -= f[_Y]; z -= f[_Z]; w -= f[_W]; return *this; }
//! Multiplies by a scalar
inline_ HPoint& Mul(float s) { x *= s; y *= s; z *= s; w *= s; return *this; }
//! Returns MIN(x, y, z, w);
float Min() const { return MIN(x, MIN(y, MIN(z, w))); }
//! Returns MAX(x, y, z, w);
float Max() const { return MAX(x, MAX(y, MAX(z, w))); }
//! Sets each element to be componentwise minimum
HPoint& Min(const HPoint& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); w = MIN(w, p.w); return *this; }
//! Sets each element to be componentwise maximum
HPoint& Max(const HPoint& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); w = MAX(w, p.w); return *this; }
//! Computes square magnitude
inline_ float SquareMagnitude() const { return x*x + y*y + z*z + w*w; }
//! Computes magnitude
inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z + w*w); }
//! Normalize the vector
inline_ HPoint& Normalize()
{
float M = Magnitude();
if(M)
{
M = 1.0f / M;
x *= M;
y *= M;
z *= M;
w *= M;
}
return *this;
}
// Arithmetic operators
//! Operator for HPoint Negate = - HPoint;
inline_ HPoint operator-() const { return HPoint(-x, -y, -z, -w); }
//! Operator for HPoint Plus = HPoint + HPoint;
inline_ HPoint operator+(const HPoint& p) const { return HPoint(x + p.x, y + p.y, z + p.z, w + p.w); }
//! Operator for HPoint Minus = HPoint - HPoint;
inline_ HPoint operator-(const HPoint& p) const { return HPoint(x - p.x, y - p.y, z - p.z, w - p.w); }
//! Operator for HPoint Mul = HPoint * HPoint;
inline_ HPoint operator*(const HPoint& p) const { return HPoint(x * p.x, y * p.y, z * p.z, w * p.w); }
//! Operator for HPoint Scale = HPoint * float;
inline_ HPoint operator*(float s) const { return HPoint(x * s, y * s, z * s, w * s); }
//! Operator for HPoint Scale = float * HPoint;
inline_ friend HPoint operator*(float s, const HPoint& p) { return HPoint(s * p.x, s * p.y, s * p.z, s * p.w); }
//! Operator for HPoint Div = HPoint / HPoint;
inline_ HPoint operator/(const HPoint& p) const { return HPoint(x / p.x, y / p.y, z / p.z, w / p.w); }
//! Operator for HPoint Scale = HPoint / float;
inline_ HPoint operator/(float s) const { s = 1.0f / s; return HPoint(x * s, y * s, z * s, w * s); }
//! Operator for HPoint Scale = float / HPoint;
inline_ friend HPoint operator/(float s, const HPoint& p) { return HPoint(s / p.x, s / p.y, s / p.z, s / p.w); }
//! Operator for float DotProd = HPoint | HPoint;
inline_ float operator|(const HPoint& p) const { return x*p.x + y*p.y + z*p.z + w*p.w; }
// No cross-product in 4D
//! Operator for HPoint += HPoint;
inline_ HPoint& operator+=(const HPoint& p) { x += p.x; y += p.y; z += p.z; w += p.w; return *this; }
//! Operator for HPoint += float;
inline_ HPoint& operator+=(float s) { x += s; y += s; z += s; w += s; return *this; }
//! Operator for HPoint -= HPoint;
inline_ HPoint& operator-=(const HPoint& p) { x -= p.x; y -= p.y; z -= p.z; w -= p.w; return *this; }
//! Operator for HPoint -= float;
inline_ HPoint& operator-=(float s) { x -= s; y -= s; z -= s; w -= s; return *this; }
//! Operator for HPoint *= HPoint;
inline_ HPoint& operator*=(const HPoint& p) { x *= p.x; y *= p.y; z *= p.z; w *= p.w; return *this; }
//! Operator for HPoint *= float;
inline_ HPoint& operator*=(float s) { x*=s; y*=s; z*=s; w*=s; return *this; }
//! Operator for HPoint /= HPoint;
inline_ HPoint& operator/=(const HPoint& p) { x /= p.x; y /= p.y; z /= p.z; w /= p.w; return *this; }
//! Operator for HPoint /= float;
inline_ HPoint& operator/=(float s) { s = 1.0f / s; x*=s; y*=s; z*=s; w*=s; return *this; }
// Arithmetic operators
//! Operator for Point Mul = HPoint * Matrix3x3;
Point operator*(const Matrix3x3& mat) const;
//! Operator for HPoint Mul = HPoint * Matrix4x4;
HPoint operator*(const Matrix4x4& mat) const;
// HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4
//! Operator for HPoint *= Matrix4x4
HPoint& operator*=(const Matrix4x4& mat);
// Logical operators
//! Operator for "if(HPoint==HPoint)"
inline_ bool operator==(const HPoint& p) const { return ( (x==p.x)&&(y==p.y)&&(z==p.z)&&(w==p.w)); }
//! Operator for "if(HPoint!=HPoint)"
inline_ bool operator!=(const HPoint& p) const { return ( (x!=p.x)||(y!=p.y)||(z!=p.z)||(w!=p.w)); }
// Cast operators
//! Cast a HPoint to a Point. w is discarded.
inline_ operator Point() const { return Point(x, y, z); }
public:
float w;
};
#endif // __ICEHPOINT_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for homogeneous points.
* \file IceHPoint.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEHPOINT_H__
#define __ICEHPOINT_H__
class ICEMATHS_API HPoint : public Point
{
public:
//! Empty constructor
inline_ HPoint() {}
//! Constructor from floats
inline_ HPoint(float _x, float _y, float _z, float _w=0.0f) : Point(_x, _y, _z), w(_w) {}
//! Constructor from array
inline_ HPoint(const float f[4]) : Point(f), w(f[3]) {}
//! Constructor from a Point
inline_ HPoint(const Point& p, float _w=0.0f) : Point(p), w(_w) {}
//! Destructor
inline_ ~HPoint() {}
//! Clear the point
inline_ HPoint& Zero() { x = y = z = w = 0.0f; return *this; }
//! Assignment from values
inline_ HPoint& Set(float _x, float _y, float _z, float _w ) { x = _x; y = _y; z = _z; w = _w; return *this; }
//! Assignment from array
inline_ HPoint& Set(const float f[4]) { x = f[_X]; y = f[_Y]; z = f[_Z]; w = f[_W]; return *this; }
//! Assignment from another h-point
inline_ HPoint& Set(const HPoint& src) { x = src.x; y = src.y; z = src.z; w = src.w; return *this; }
//! Add a vector
inline_ HPoint& Add(float _x, float _y, float _z, float _w ) { x += _x; y += _y; z += _z; w += _w; return *this; }
//! Add a vector
inline_ HPoint& Add(const float f[4]) { x += f[_X]; y += f[_Y]; z += f[_Z]; w += f[_W]; return *this; }
//! Subtract a vector
inline_ HPoint& Sub(float _x, float _y, float _z, float _w ) { x -= _x; y -= _y; z -= _z; w -= _w; return *this; }
//! Subtract a vector
inline_ HPoint& Sub(const float f[4]) { x -= f[_X]; y -= f[_Y]; z -= f[_Z]; w -= f[_W]; return *this; }
//! Multiplies by a scalar
inline_ HPoint& Mul(float s) { x *= s; y *= s; z *= s; w *= s; return *this; }
//! Returns MIN(x, y, z, w);
float Min() const { return MIN(x, MIN(y, MIN(z, w))); }
//! Returns MAX(x, y, z, w);
float Max() const { return MAX(x, MAX(y, MAX(z, w))); }
//! Sets each element to be componentwise minimum
HPoint& Min(const HPoint& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); w = MIN(w, p.w); return *this; }
//! Sets each element to be componentwise maximum
HPoint& Max(const HPoint& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); w = MAX(w, p.w); return *this; }
//! Computes square magnitude
inline_ float SquareMagnitude() const { return x*x + y*y + z*z + w*w; }
//! Computes magnitude
inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z + w*w); }
//! Normalize the vector
inline_ HPoint& Normalize()
{
float M = Magnitude();
if(M)
{
M = 1.0f / M;
x *= M;
y *= M;
z *= M;
w *= M;
}
return *this;
}
// Arithmetic operators
//! Operator for HPoint Negate = - HPoint;
inline_ HPoint operator-() const { return HPoint(-x, -y, -z, -w); }
//! Operator for HPoint Plus = HPoint + HPoint;
inline_ HPoint operator+(const HPoint& p) const { return HPoint(x + p.x, y + p.y, z + p.z, w + p.w); }
//! Operator for HPoint Minus = HPoint - HPoint;
inline_ HPoint operator-(const HPoint& p) const { return HPoint(x - p.x, y - p.y, z - p.z, w - p.w); }
//! Operator for HPoint Mul = HPoint * HPoint;
inline_ HPoint operator*(const HPoint& p) const { return HPoint(x * p.x, y * p.y, z * p.z, w * p.w); }
//! Operator for HPoint Scale = HPoint * float;
inline_ HPoint operator*(float s) const { return HPoint(x * s, y * s, z * s, w * s); }
//! Operator for HPoint Scale = float * HPoint;
inline_ friend HPoint operator*(float s, const HPoint& p) { return HPoint(s * p.x, s * p.y, s * p.z, s * p.w); }
//! Operator for HPoint Div = HPoint / HPoint;
inline_ HPoint operator/(const HPoint& p) const { return HPoint(x / p.x, y / p.y, z / p.z, w / p.w); }
//! Operator for HPoint Scale = HPoint / float;
inline_ HPoint operator/(float s) const { s = 1.0f / s; return HPoint(x * s, y * s, z * s, w * s); }
//! Operator for HPoint Scale = float / HPoint;
inline_ friend HPoint operator/(float s, const HPoint& p) { return HPoint(s / p.x, s / p.y, s / p.z, s / p.w); }
//! Operator for float DotProd = HPoint | HPoint;
inline_ float operator|(const HPoint& p) const { return x*p.x + y*p.y + z*p.z + w*p.w; }
// No cross-product in 4D
//! Operator for HPoint += HPoint;
inline_ HPoint& operator+=(const HPoint& p) { x += p.x; y += p.y; z += p.z; w += p.w; return *this; }
//! Operator for HPoint += float;
inline_ HPoint& operator+=(float s) { x += s; y += s; z += s; w += s; return *this; }
//! Operator for HPoint -= HPoint;
inline_ HPoint& operator-=(const HPoint& p) { x -= p.x; y -= p.y; z -= p.z; w -= p.w; return *this; }
//! Operator for HPoint -= float;
inline_ HPoint& operator-=(float s) { x -= s; y -= s; z -= s; w -= s; return *this; }
//! Operator for HPoint *= HPoint;
inline_ HPoint& operator*=(const HPoint& p) { x *= p.x; y *= p.y; z *= p.z; w *= p.w; return *this; }
//! Operator for HPoint *= float;
inline_ HPoint& operator*=(float s) { x*=s; y*=s; z*=s; w*=s; return *this; }
//! Operator for HPoint /= HPoint;
inline_ HPoint& operator/=(const HPoint& p) { x /= p.x; y /= p.y; z /= p.z; w /= p.w; return *this; }
//! Operator for HPoint /= float;
inline_ HPoint& operator/=(float s) { s = 1.0f / s; x*=s; y*=s; z*=s; w*=s; return *this; }
// Arithmetic operators
//! Operator for Point Mul = HPoint * Matrix3x3;
Point operator*(const Matrix3x3& mat) const;
//! Operator for HPoint Mul = HPoint * Matrix4x4;
HPoint operator*(const Matrix4x4& mat) const;
// HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4
//! Operator for HPoint *= Matrix4x4
HPoint& operator*=(const Matrix4x4& mat);
// Logical operators
//! Operator for "if(HPoint==HPoint)"
inline_ bool operator==(const HPoint& p) const { return ( (x==p.x)&&(y==p.y)&&(z==p.z)&&(w==p.w)); }
//! Operator for "if(HPoint!=HPoint)"
inline_ bool operator!=(const HPoint& p) const { return ( (x!=p.x)||(y!=p.y)||(z!=p.z)||(w!=p.w)); }
// Cast operators
//! Cast a HPoint to a Point. w is discarded.
inline_ operator Point() const { return Point(x, y, z); }
public:
float w;
};
#endif // __ICEHPOINT_H__

View File

@@ -1,78 +1,78 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains hashing code.
* \file IceHashing.h
* \author Pierre Terdiman
* \date May, 08, 1999
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEHASHING_H
#define ICEHASHING_H
#define HashSize(n) ((udword)1<<(n))
#define HashMask(n) (HashSize(n)-1)
ICECORE_API udword Hash(const char* str);
ICECORE_API udword Hash(ubyte* k, udword length, udword initval);
// Bob Jenkin's hash
inline_ unsigned int Hash32Bits_0(unsigned int key)
{
key += (key << 12);
key ^= (key >> 22);
key += (key << 4);
key ^= (key >> 9);
key += (key << 10);
key ^= (key >> 2);
key += (key << 7);
key ^= (key >> 12);
return key;
}
// Thomas Wang's hash
inline_ int Hash32Bits_1(int key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
// Thomas Wang's hash
inline_ __int64 Hash64Bits_0(__int64 key)
{
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return key;
}
inline_ __int64 Hash64Bits_1(__int64 key)
{
__int64 c1 = 0x6e5ea73858134343L;
__int64 c2 = 0xb34e8f99a2ec9ef5L;
key ^= ((c1 ^ key) >> 32);
key *= c1;
key ^= ((c2 ^ key) >> 31);
key *= c2;
key ^= ((c1 ^ key) >> 32);
return key;
}
inline_ udword Hash(udword id0, udword id1)
{
return Hash32Bits_1( (id0&0xffff)|(id1<<16) );
}
#endif // ICEHASHING_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains hashing code.
* \file IceHashing.h
* \author Pierre Terdiman
* \date May, 08, 1999
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEHASHING_H
#define ICEHASHING_H
#define HashSize(n) ((udword)1<<(n))
#define HashMask(n) (HashSize(n)-1)
ICECORE_API udword Hash(const char* str);
ICECORE_API udword Hash(ubyte* k, udword length, udword initval);
// Bob Jenkin's hash
inline_ unsigned int Hash32Bits_0(unsigned int key)
{
key += (key << 12);
key ^= (key >> 22);
key += (key << 4);
key ^= (key >> 9);
key += (key << 10);
key ^= (key >> 2);
key += (key << 7);
key ^= (key >> 12);
return key;
}
// Thomas Wang's hash
inline_ int Hash32Bits_1(int key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
// Thomas Wang's hash
inline_ __int64 Hash64Bits_0(__int64 key)
{
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return key;
}
inline_ __int64 Hash64Bits_1(__int64 key)
{
__int64 c1 = 0x6e5ea73858134343L;
__int64 c2 = 0xb34e8f99a2ec9ef5L;
key ^= ((c1 ^ key) >> 32);
key *= c1;
key ^= ((c2 ^ key) >> 31);
key *= c2;
key ^= ((c1 ^ key) >> 32);
return key;
}
inline_ udword Hash(udword id0, udword id1)
{
return Hash32Bits_1( (id0&0xffff)|(id1<<16) );
}
#endif // ICEHASHING_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,84 +1,84 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy indexed triangle class.
* \file IceIndexedTriangle.h
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEINDEXEDTRIANGLE_H__
#define __ICEINDEXEDTRIANGLE_H__
// Forward declarations
enum CubeIndex;
// An indexed triangle class.
class ICEMATHS_API IndexedTriangle
{
public:
//! Constructor
inline_ IndexedTriangle() {}
//! Constructor
inline_ IndexedTriangle(udword r0, udword r1, udword r2) { mVRef[0]=r0; mVRef[1]=r1; mVRef[2]=r2; }
//! Copy constructor
inline_ IndexedTriangle(const IndexedTriangle& triangle)
{
mVRef[0] = triangle.mVRef[0];
mVRef[1] = triangle.mVRef[1];
mVRef[2] = triangle.mVRef[2];
}
//! Destructor
inline_ ~IndexedTriangle() {}
//! Vertex-references
udword mVRef[3];
// Methods
void Flip();
float Area(const Point* verts) const;
float Perimeter(const Point* verts) const;
float Compacity(const Point* verts) const;
void Normal(const Point* verts, Point& normal) const;
void DenormalizedNormal(const Point* verts, Point& normal) const;
void Center(const Point* verts, Point& center) const;
void CenteredNormal(const Point* verts, Point& normal) const;
void RandomPoint(const Point* verts, Point& random) const;
bool IsVisible(const Point* verts, const Point& source) const;
bool BackfaceCulling(const Point* verts, const Point& source) const;
float ComputeOcclusionPotential(const Point* verts, const Point& view) const;
bool ReplaceVertex(udword oldref, udword newref);
bool IsDegenerate() const;
bool HasVertex(udword ref) const;
bool HasVertex(udword ref, udword* index) const;
ubyte FindEdge(udword vref0, udword vref1) const;
udword OppositeVertex(udword vref0, udword vref1) const;
inline_ udword OppositeVertex(ubyte edgenb) const { return mVRef[2-edgenb]; }
void GetVRefs(ubyte edgenb, udword& vref0, udword& vref1, udword& vref2) const;
float MinEdgeLength(const Point* verts) const;
float MaxEdgeLength(const Point* verts) const;
void ComputePoint(const Point* verts, float u, float v, Point& pt, udword* nearvtx=null) const;
float Angle(const IndexedTriangle& tri, const Point* verts) const;
inline_ Plane PlaneEquation(const Point* verts) const { return Plane(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); }
bool Equal(const IndexedTriangle& tri) const;
CubeIndex ComputeCubeIndex(const Point* verts) const;
};
#endif // __ICEINDEXEDTRIANGLE_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy indexed triangle class.
* \file IceIndexedTriangle.h
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEINDEXEDTRIANGLE_H__
#define __ICEINDEXEDTRIANGLE_H__
// Forward declarations
enum CubeIndex;
// An indexed triangle class.
class ICEMATHS_API IndexedTriangle
{
public:
//! Constructor
inline_ IndexedTriangle() {}
//! Constructor
inline_ IndexedTriangle(udword r0, udword r1, udword r2) { mVRef[0]=r0; mVRef[1]=r1; mVRef[2]=r2; }
//! Copy constructor
inline_ IndexedTriangle(const IndexedTriangle& triangle)
{
mVRef[0] = triangle.mVRef[0];
mVRef[1] = triangle.mVRef[1];
mVRef[2] = triangle.mVRef[2];
}
//! Destructor
inline_ ~IndexedTriangle() {}
//! Vertex-references
udword mVRef[3];
// Methods
void Flip();
float Area(const Point* verts) const;
float Perimeter(const Point* verts) const;
float Compacity(const Point* verts) const;
void Normal(const Point* verts, Point& normal) const;
void DenormalizedNormal(const Point* verts, Point& normal) const;
void Center(const Point* verts, Point& center) const;
void CenteredNormal(const Point* verts, Point& normal) const;
void RandomPoint(const Point* verts, Point& random) const;
bool IsVisible(const Point* verts, const Point& source) const;
bool BackfaceCulling(const Point* verts, const Point& source) const;
float ComputeOcclusionPotential(const Point* verts, const Point& view) const;
bool ReplaceVertex(udword oldref, udword newref);
bool IsDegenerate() const;
bool HasVertex(udword ref) const;
bool HasVertex(udword ref, udword* index) const;
ubyte FindEdge(udword vref0, udword vref1) const;
udword OppositeVertex(udword vref0, udword vref1) const;
inline_ udword OppositeVertex(ubyte edgenb) const { return mVRef[2-edgenb]; }
void GetVRefs(ubyte edgenb, udword& vref0, udword& vref1, udword& vref2) const;
float MinEdgeLength(const Point* verts) const;
float MaxEdgeLength(const Point* verts) const;
void ComputePoint(const Point* verts, float u, float v, Point& pt, udword* nearvtx=null) const;
float Angle(const IndexedTriangle& tri, const Point* verts) const;
inline_ Plane PlaneEquation(const Point* verts) const { return Plane(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); }
bool Equal(const IndexedTriangle& tri) const;
CubeIndex ComputeCubeIndex(const Point* verts) const;
};
#endif // __ICEINDEXEDTRIANGLE_H__

View File

@@ -1,91 +1,91 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for line-swept spheres.
* \file IceLSS.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICELSS_H__
#define __ICELSS_H__
class ICEMATHS_API LSS : public Segment
{
public:
//! Constructor
inline_ LSS() {}
//! Constructor
inline_ LSS(const Segment& seg, float radius) : Segment(seg), mRadius(radius) {}
//! Destructor
inline_ ~LSS() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an OBB surrounding the LSS.
* \param box [out] the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeOBB(OBB& box);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the LSS.
* \param pt [in] the point to test
* \return true if inside the LSS
* \warning point and LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Point& pt) const { return SquareDistance(pt) <= mRadius*mRadius; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a sphere is contained within the LSS.
* \param sphere [in] the sphere to test
* \return true if inside the LSS
* \warning sphere and LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Sphere& sphere)
{
float d = mRadius - sphere.mRadius;
if(d>=0.0f) return SquareDistance(sphere.mCenter) <= d*d;
else return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if an LSS is contained within the LSS.
* \param lss [in] the LSS to test
* \return true if inside the LSS
* \warning both LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const LSS& lss)
{
// We check the LSS contains the two spheres at the start and end of the sweep
return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius));
}
float mRadius; //!< Sphere radius
};
#endif // __ICELSS_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for line-swept spheres.
* \file IceLSS.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICELSS_H__
#define __ICELSS_H__
class ICEMATHS_API LSS : public Segment
{
public:
//! Constructor
inline_ LSS() {}
//! Constructor
inline_ LSS(const Segment& seg, float radius) : Segment(seg), mRadius(radius) {}
//! Destructor
inline_ ~LSS() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an OBB surrounding the LSS.
* \param box [out] the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeOBB(OBB& box);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the LSS.
* \param pt [in] the point to test
* \return true if inside the LSS
* \warning point and LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Point& pt) const { return SquareDistance(pt) <= mRadius*mRadius; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a sphere is contained within the LSS.
* \param sphere [in] the sphere to test
* \return true if inside the LSS
* \warning sphere and LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const Sphere& sphere)
{
float d = mRadius - sphere.mRadius;
if(d>=0.0f) return SquareDistance(sphere.mCenter) <= d*d;
else return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if an LSS is contained within the LSS.
* \param lss [in] the LSS to test
* \return true if inside the LSS
* \warning both LSS must be in same space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool Contains(const LSS& lss)
{
// We check the LSS contains the two spheres at the start and end of the sweep
return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius));
}
float mRadius; //!< Sphere radius
};
#endif // __ICELSS_H__

View File

@@ -1,64 +1,64 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 3x3 matrices.
* \file IceMatrix3x3.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 3x3 matrix.
* DirectX-compliant, ie row-column order, ie m[Row][Col].
* Same as:
* m11 m12 m13 first row.
* m21 m22 m23 second row.
* m31 m32 m33 third row.
* Stored in memory as m11 m12 m13 m21...
*
* Multiplication rules:
*
* [x'y'z'] = [xyz][M]
*
* x' = x*m11 + y*m21 + z*m31
* y' = x*m12 + y*m22 + z*m32
* z' = x*m13 + y*m23 + z*m33
*
* \class Matrix3x3
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
// Cast operator
Matrix3x3::operator Matrix4x4() const
{
return Matrix4x4(
m[0][0], m[0][1], m[0][2], 0.0f,
m[1][0], m[1][1], m[1][2], 0.0f,
m[2][0], m[2][1], m[2][2], 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 3x3 matrices.
* \file IceMatrix3x3.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 3x3 matrix.
* DirectX-compliant, ie row-column order, ie m[Row][Col].
* Same as:
* m11 m12 m13 first row.
* m21 m22 m23 second row.
* m31 m32 m33 third row.
* Stored in memory as m11 m12 m13 m21...
*
* Multiplication rules:
*
* [x'y'z'] = [xyz][M]
*
* x' = x*m11 + y*m21 + z*m31
* y' = x*m12 + y*m22 + z*m32
* z' = x*m13 + y*m23 + z*m33
*
* \class Matrix3x3
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
// Cast operator
Matrix3x3::operator Matrix4x4() const
{
return Matrix4x4(
m[0][0], m[0][1], m[0][2], 0.0f,
m[1][0], m[1][1], m[1][2], 0.0f,
m[2][0], m[2][1], m[2][2], 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,152 +1,152 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 4x4 matrices.
* \file IceMatrix4x4.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 4x4 matrix.
* DirectX-compliant, ie row-column order, ie m[Row][Col].
* Same as:
* m11 m12 m13 m14 first row.
* m21 m22 m23 m24 second row.
* m31 m32 m33 m34 third row.
* m41 m42 m43 m44 fourth row.
* Translation is (m41, m42, m43), (m14, m24, m34, m44) = (0, 0, 0, 1).
* Stored in memory as m11 m12 m13 m14 m21...
*
* Multiplication rules:
*
* [x'y'z'1] = [xyz1][M]
*
* x' = x*m11 + y*m21 + z*m31 + m41
* y' = x*m12 + y*m22 + z*m32 + m42
* z' = x*m13 + y*m23 + z*m33 + m43
* 1' = 0 + 0 + 0 + m44
*
* \class Matrix4x4
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Inverts a PR matrix. (which only contains a rotation and a translation)
* This is faster and less subject to FPU errors than the generic inversion code.
*
* \relates Matrix4x4
* \fn InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src)
* \param dest [out] destination matrix
* \param src [in] source matrix
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ICEMATHS_API void IceMaths::InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src)
{
dest.m[0][0] = src.m[0][0];
dest.m[1][0] = src.m[0][1];
dest.m[2][0] = src.m[0][2];
dest.m[3][0] = -(src.m[3][0]*src.m[0][0] + src.m[3][1]*src.m[0][1] + src.m[3][2]*src.m[0][2]);
dest.m[0][1] = src.m[1][0];
dest.m[1][1] = src.m[1][1];
dest.m[2][1] = src.m[1][2];
dest.m[3][1] = -(src.m[3][0]*src.m[1][0] + src.m[3][1]*src.m[1][1] + src.m[3][2]*src.m[1][2]);
dest.m[0][2] = src.m[2][0];
dest.m[1][2] = src.m[2][1];
dest.m[2][2] = src.m[2][2];
dest.m[3][2] = -(src.m[3][0]*src.m[2][0] + src.m[3][1]*src.m[2][1] + src.m[3][2]*src.m[2][2]);
dest.m[0][3] = 0.0f;
dest.m[1][3] = 0.0f;
dest.m[2][3] = 0.0f;
dest.m[3][3] = 1.0f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the cofactor of the Matrix at a specified location
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Matrix4x4::CoFactor(udword row, udword col) const
{
return (( m[(row+1)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+3)&3][(col+3)&3] +
m[(row+1)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+3)&3][(col+1)&3] +
m[(row+1)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+3)&3][(col+2)&3])
- (m[(row+3)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+1)&3][(col+3)&3] +
m[(row+3)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+1)&3][(col+1)&3] +
m[(row+3)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+1)&3][(col+2)&3])) * ((row + col) & 1 ? -1.0f : +1.0f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the determinant of the Matrix
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Matrix4x4::Determinant() const
{
return m[0][0] * CoFactor(0, 0) +
m[0][1] * CoFactor(0, 1) +
m[0][2] * CoFactor(0, 2) +
m[0][3] * CoFactor(0, 3);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the inverse of the matrix
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Matrix4x4& Matrix4x4::Invert()
{
float Det = Determinant();
Matrix4x4 Temp;
if(fabsf(Det) < MATRIX4X4_EPSILON)
return *this; // The matrix is not invertible! Singular case!
float IDet = 1.0f / Det;
Temp.m[0][0] = CoFactor(0,0) * IDet;
Temp.m[1][0] = CoFactor(0,1) * IDet;
Temp.m[2][0] = CoFactor(0,2) * IDet;
Temp.m[3][0] = CoFactor(0,3) * IDet;
Temp.m[0][1] = CoFactor(1,0) * IDet;
Temp.m[1][1] = CoFactor(1,1) * IDet;
Temp.m[2][1] = CoFactor(1,2) * IDet;
Temp.m[3][1] = CoFactor(1,3) * IDet;
Temp.m[0][2] = CoFactor(2,0) * IDet;
Temp.m[1][2] = CoFactor(2,1) * IDet;
Temp.m[2][2] = CoFactor(2,2) * IDet;
Temp.m[3][2] = CoFactor(2,3) * IDet;
Temp.m[0][3] = CoFactor(3,0) * IDet;
Temp.m[1][3] = CoFactor(3,1) * IDet;
Temp.m[2][3] = CoFactor(3,2) * IDet;
Temp.m[3][3] = CoFactor(3,3) * IDet;
*this = Temp;
return *this;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 4x4 matrices.
* \file IceMatrix4x4.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 4x4 matrix.
* DirectX-compliant, ie row-column order, ie m[Row][Col].
* Same as:
* m11 m12 m13 m14 first row.
* m21 m22 m23 m24 second row.
* m31 m32 m33 m34 third row.
* m41 m42 m43 m44 fourth row.
* Translation is (m41, m42, m43), (m14, m24, m34, m44) = (0, 0, 0, 1).
* Stored in memory as m11 m12 m13 m14 m21...
*
* Multiplication rules:
*
* [x'y'z'1] = [xyz1][M]
*
* x' = x*m11 + y*m21 + z*m31 + m41
* y' = x*m12 + y*m22 + z*m32 + m42
* z' = x*m13 + y*m23 + z*m33 + m43
* 1' = 0 + 0 + 0 + m44
*
* \class Matrix4x4
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Inverts a PR matrix. (which only contains a rotation and a translation)
* This is faster and less subject to FPU errors than the generic inversion code.
*
* \relates Matrix4x4
* \fn InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src)
* \param dest [out] destination matrix
* \param src [in] source matrix
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ICEMATHS_API void IceMaths::InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src)
{
dest.m[0][0] = src.m[0][0];
dest.m[1][0] = src.m[0][1];
dest.m[2][0] = src.m[0][2];
dest.m[3][0] = -(src.m[3][0]*src.m[0][0] + src.m[3][1]*src.m[0][1] + src.m[3][2]*src.m[0][2]);
dest.m[0][1] = src.m[1][0];
dest.m[1][1] = src.m[1][1];
dest.m[2][1] = src.m[1][2];
dest.m[3][1] = -(src.m[3][0]*src.m[1][0] + src.m[3][1]*src.m[1][1] + src.m[3][2]*src.m[1][2]);
dest.m[0][2] = src.m[2][0];
dest.m[1][2] = src.m[2][1];
dest.m[2][2] = src.m[2][2];
dest.m[3][2] = -(src.m[3][0]*src.m[2][0] + src.m[3][1]*src.m[2][1] + src.m[3][2]*src.m[2][2]);
dest.m[0][3] = 0.0f;
dest.m[1][3] = 0.0f;
dest.m[2][3] = 0.0f;
dest.m[3][3] = 1.0f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the cofactor of the Matrix at a specified location
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Matrix4x4::CoFactor(udword row, udword col) const
{
return (( m[(row+1)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+3)&3][(col+3)&3] +
m[(row+1)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+3)&3][(col+1)&3] +
m[(row+1)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+3)&3][(col+2)&3])
- (m[(row+3)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+1)&3][(col+3)&3] +
m[(row+3)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+1)&3][(col+1)&3] +
m[(row+3)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+1)&3][(col+2)&3])) * ((row + col) & 1 ? -1.0f : +1.0f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the determinant of the Matrix
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Matrix4x4::Determinant() const
{
return m[0][0] * CoFactor(0, 0) +
m[0][1] * CoFactor(0, 1) +
m[0][2] * CoFactor(0, 2) +
m[0][3] * CoFactor(0, 3);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the inverse of the matrix
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Matrix4x4& Matrix4x4::Invert()
{
float Det = Determinant();
Matrix4x4 Temp;
if(fabsf(Det) < MATRIX4X4_EPSILON)
return *this; // The matrix is not invertible! Singular case!
float IDet = 1.0f / Det;
Temp.m[0][0] = CoFactor(0,0) * IDet;
Temp.m[1][0] = CoFactor(0,1) * IDet;
Temp.m[2][0] = CoFactor(0,2) * IDet;
Temp.m[3][0] = CoFactor(0,3) * IDet;
Temp.m[0][1] = CoFactor(1,0) * IDet;
Temp.m[1][1] = CoFactor(1,1) * IDet;
Temp.m[2][1] = CoFactor(1,2) * IDet;
Temp.m[3][1] = CoFactor(1,3) * IDet;
Temp.m[0][2] = CoFactor(2,0) * IDet;
Temp.m[1][2] = CoFactor(2,1) * IDet;
Temp.m[2][2] = CoFactor(2,2) * IDet;
Temp.m[3][2] = CoFactor(2,3) * IDet;
Temp.m[0][3] = CoFactor(3,0) * IDet;
Temp.m[1][3] = CoFactor(3,1) * IDet;
Temp.m[2][3] = CoFactor(3,2) * IDet;
Temp.m[3][3] = CoFactor(3,3) * IDet;
*this = Temp;
return *this;
}

View File

@@ -1,471 +1,471 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 4x4 matrices.
* \file IceMatrix4x4.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEMATRIX4X4_H__
#define __ICEMATRIX4X4_H__
// Forward declarations
class PRS;
class PR;
#define MATRIX4X4_EPSILON (1.0e-7f)
class ICEMATHS_API Matrix4x4
{
// void LUBackwardSubstitution( sdword *indx, float* b );
// void LUDecomposition( sdword* indx, float* d );
public:
//! Empty constructor.
inline_ Matrix4x4() {}
//! Constructor from 16 values
inline_ Matrix4x4( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
}
//! Copy constructor
inline_ Matrix4x4(const Matrix4x4& mat) { CopyMemory(m, &mat.m, 16*sizeof(float)); }
//! Destructor.
inline_ ~Matrix4x4() {}
//! Assign values (rotation only)
inline_ Matrix4x4& Set( float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22;
return *this;
}
//! Assign values
inline_ Matrix4x4& Set( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
return *this;
}
//! Copy from a Matrix4x4
inline_ void Copy(const Matrix4x4& source) { CopyMemory(m, source.m, 16*sizeof(float)); }
// Row-column access
//! Returns a row.
inline_ void GetRow(const udword r, HPoint& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; p.w=m[r][3]; }
//! Returns a row.
inline_ void GetRow(const udword r, Point& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; }
//! Returns a row.
inline_ const HPoint& GetRow(const udword r) const { return *(const HPoint*)&m[r][0]; }
//! Returns a row.
inline_ HPoint& GetRow(const udword r) { return *(HPoint*)&m[r][0]; }
//! Sets a row.
inline_ void SetRow(const udword r, const HPoint& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]=p.w; }
//! Sets a row.
inline_ void SetRow(const udword r, const Point& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]= (r!=3) ? 0.0f : 1.0f; }
//! Returns a column.
inline_ void GetCol(const udword c, HPoint& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; p.w=m[3][c]; }
//! Returns a column.
inline_ void GetCol(const udword c, Point& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; }
//! Sets a column.
inline_ void SetCol(const udword c, const HPoint& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]=p.w; }
//! Sets a column.
inline_ void SetCol(const udword c, const Point& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]= (c!=3) ? 0.0f : 1.0f; }
// Translation
//! Returns the translation part of the matrix.
inline_ const HPoint& GetTrans() const { return GetRow(3); }
//! Gets the translation part of the matrix
inline_ void GetTrans(Point& p) const { p.x=m[3][0]; p.y=m[3][1]; p.z=m[3][2]; }
//! Sets the translation part of the matrix, from a Point.
inline_ void SetTrans(const Point& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; }
//! Sets the translation part of the matrix, from a HPoint.
inline_ void SetTrans(const HPoint& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; m[3][3]=p.w; }
//! Sets the translation part of the matrix, from floats.
inline_ void SetTrans(float tx, float ty, float tz) { m[3][0]=tx; m[3][1]=ty; m[3][2]=tz; }
// Scale
//! Sets the scale from a Point. The point is put on the diagonal.
inline_ void SetScale(const Point& p) { m[0][0]=p.x; m[1][1]=p.y; m[2][2]=p.z; }
//! Sets the scale from floats. Values are put on the diagonal.
inline_ void SetScale(float sx, float sy, float sz) { m[0][0]=sx; m[1][1]=sy; m[2][2]=sz; }
//! Scales from a Point. Each row is multiplied by a component.
void Scale(const Point& p)
{
m[0][0] *= p.x; m[1][0] *= p.y; m[2][0] *= p.z;
m[0][1] *= p.x; m[1][1] *= p.y; m[2][1] *= p.z;
m[0][2] *= p.x; m[1][2] *= p.y; m[2][2] *= p.z;
}
//! Scales from floats. Each row is multiplied by a value.
void Scale(float sx, float sy, float sz)
{
m[0][0] *= sx; m[1][0] *= sy; m[2][0] *= sz;
m[0][1] *= sx; m[1][1] *= sy; m[2][1] *= sz;
m[0][2] *= sx; m[1][2] *= sy; m[2][2] *= sz;
}
/*
//! Returns a row.
inline_ HPoint GetRow(const udword row) const { return mRow[row]; }
//! Sets a row.
inline_ Matrix4x4& SetRow(const udword row, const HPoint& p) { mRow[row] = p; return *this; }
//! Sets a row.
Matrix4x4& SetRow(const udword row, const Point& p)
{
m[row][0] = p.x;
m[row][1] = p.y;
m[row][2] = p.z;
m[row][3] = (row != 3) ? 0.0f : 1.0f;
return *this;
}
//! Returns a column.
HPoint GetCol(const udword col) const
{
HPoint Res;
Res.x = m[0][col];
Res.y = m[1][col];
Res.z = m[2][col];
Res.w = m[3][col];
return Res;
}
//! Sets a column.
Matrix4x4& SetCol(const udword col, const HPoint& p)
{
m[0][col] = p.x;
m[1][col] = p.y;
m[2][col] = p.z;
m[3][col] = p.w;
return *this;
}
//! Sets a column.
Matrix4x4& SetCol(const udword col, const Point& p)
{
m[0][col] = p.x;
m[1][col] = p.y;
m[2][col] = p.z;
m[3][col] = (col != 3) ? 0.0f : 1.0f;
return *this;
}
*/
//! Computes the trace. The trace is the sum of the 4 diagonal components.
inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; }
//! Computes the trace of the upper 3x3 matrix.
inline_ float Trace3x3() const { return m[0][0] + m[1][1] + m[2][2]; }
//! Clears the matrix.
inline_ void Zero() { ZeroMemory(&m, sizeof(m)); }
//! Sets the identity matrix.
inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; }
//! Checks for identity
inline_ bool IsIdentity() const
{
if(IR(m[0][0])!=IEEE_1_0) return false;
if(IR(m[0][1])!=0) return false;
if(IR(m[0][2])!=0) return false;
if(IR(m[0][3])!=0) return false;
if(IR(m[1][0])!=0) return false;
if(IR(m[1][1])!=IEEE_1_0) return false;
if(IR(m[1][2])!=0) return false;
if(IR(m[1][3])!=0) return false;
if(IR(m[2][0])!=0) return false;
if(IR(m[2][1])!=0) return false;
if(IR(m[2][2])!=IEEE_1_0) return false;
if(IR(m[2][3])!=0) return false;
if(IR(m[3][0])!=0) return false;
if(IR(m[3][1])!=0) return false;
if(IR(m[3][2])!=0) return false;
if(IR(m[3][3])!=IEEE_1_0) return false;
return true;
}
//! Checks matrix validity
inline_ BOOL IsValid() const
{
for(udword j=0;j<4;j++)
{
for(udword i=0;i<4;i++)
{
if(!IsValidFloat(m[j][i])) return FALSE;
}
}
return TRUE;
}
//! Sets a rotation matrix around the X axis.
void RotX(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[1][1] = m[2][2] = Cos; m[2][1] = -Sin; m[1][2] = Sin; }
//! Sets a rotation matrix around the Y axis.
void RotY(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[2][2] = Cos; m[2][0] = Sin; m[0][2] = -Sin; }
//! Sets a rotation matrix around the Z axis.
void RotZ(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[1][1] = Cos; m[1][0] = -Sin; m[0][1] = Sin; }
//! Makes a rotation matrix about an arbitrary axis
Matrix4x4& Rot(float angle, Point& p1, Point& p2);
//! Transposes the matrix.
void Transpose()
{
IR(m[1][0]) ^= IR(m[0][1]); IR(m[0][1]) ^= IR(m[1][0]); IR(m[1][0]) ^= IR(m[0][1]);
IR(m[2][0]) ^= IR(m[0][2]); IR(m[0][2]) ^= IR(m[2][0]); IR(m[2][0]) ^= IR(m[0][2]);
IR(m[3][0]) ^= IR(m[0][3]); IR(m[0][3]) ^= IR(m[3][0]); IR(m[3][0]) ^= IR(m[0][3]);
IR(m[1][2]) ^= IR(m[2][1]); IR(m[2][1]) ^= IR(m[1][2]); IR(m[1][2]) ^= IR(m[2][1]);
IR(m[1][3]) ^= IR(m[3][1]); IR(m[3][1]) ^= IR(m[1][3]); IR(m[1][3]) ^= IR(m[3][1]);
IR(m[2][3]) ^= IR(m[3][2]); IR(m[3][2]) ^= IR(m[2][3]); IR(m[2][3]) ^= IR(m[3][2]);
}
//! Computes a cofactor. Used for matrix inversion.
float CoFactor(udword row, udword col) const;
//! Computes the determinant of the matrix.
float Determinant() const;
//! Inverts the matrix. Determinant must be different from zero, else matrix can't be inverted.
Matrix4x4& Invert();
// Matrix& ComputeAxisMatrix(Point& axis, float angle);
// Cast operators
//! Casts a Matrix4x4 to a Matrix3x3.
inline_ operator Matrix3x3() const
{
return Matrix3x3(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
}
//! Casts a Matrix4x4 to a Quat.
operator Quat() const;
//! Casts a Matrix4x4 to a PR.
operator PR() const;
// Arithmetic operators
//! Operator for Matrix4x4 Plus = Matrix4x4 + Matrix4x4;
inline_ Matrix4x4 operator+(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]+mat.m[0][0], m[0][1]+mat.m[0][1], m[0][2]+mat.m[0][2], m[0][3]+mat.m[0][3],
m[1][0]+mat.m[1][0], m[1][1]+mat.m[1][1], m[1][2]+mat.m[1][2], m[1][3]+mat.m[1][3],
m[2][0]+mat.m[2][0], m[2][1]+mat.m[2][1], m[2][2]+mat.m[2][2], m[2][3]+mat.m[2][3],
m[3][0]+mat.m[3][0], m[3][1]+mat.m[3][1], m[3][2]+mat.m[3][2], m[3][3]+mat.m[3][3]);
}
//! Operator for Matrix4x4 Minus = Matrix4x4 - Matrix4x4;
inline_ Matrix4x4 operator-(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]-mat.m[0][0], m[0][1]-mat.m[0][1], m[0][2]-mat.m[0][2], m[0][3]-mat.m[0][3],
m[1][0]-mat.m[1][0], m[1][1]-mat.m[1][1], m[1][2]-mat.m[1][2], m[1][3]-mat.m[1][3],
m[2][0]-mat.m[2][0], m[2][1]-mat.m[2][1], m[2][2]-mat.m[2][2], m[2][3]-mat.m[2][3],
m[3][0]-mat.m[3][0], m[3][1]-mat.m[3][1], m[3][2]-mat.m[3][2], m[3][3]-mat.m[3][3]);
}
//! Operator for Matrix4x4 Mul = Matrix4x4 * Matrix4x4;
inline_ Matrix4x4 operator*(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0] + m[0][3]*mat.m[3][0],
m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1] + m[0][3]*mat.m[3][1],
m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2] + m[0][3]*mat.m[3][2],
m[0][0]*mat.m[0][3] + m[0][1]*mat.m[1][3] + m[0][2]*mat.m[2][3] + m[0][3]*mat.m[3][3],
m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0] + m[1][3]*mat.m[3][0],
m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1] + m[1][3]*mat.m[3][1],
m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2] + m[1][3]*mat.m[3][2],
m[1][0]*mat.m[0][3] + m[1][1]*mat.m[1][3] + m[1][2]*mat.m[2][3] + m[1][3]*mat.m[3][3],
m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0] + m[2][3]*mat.m[3][0],
m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1] + m[2][3]*mat.m[3][1],
m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2] + m[2][3]*mat.m[3][2],
m[2][0]*mat.m[0][3] + m[2][1]*mat.m[1][3] + m[2][2]*mat.m[2][3] + m[2][3]*mat.m[3][3],
m[3][0]*mat.m[0][0] + m[3][1]*mat.m[1][0] + m[3][2]*mat.m[2][0] + m[3][3]*mat.m[3][0],
m[3][0]*mat.m[0][1] + m[3][1]*mat.m[1][1] + m[3][2]*mat.m[2][1] + m[3][3]*mat.m[3][1],
m[3][0]*mat.m[0][2] + m[3][1]*mat.m[1][2] + m[3][2]*mat.m[2][2] + m[3][3]*mat.m[3][2],
m[3][0]*mat.m[0][3] + m[3][1]*mat.m[1][3] + m[3][2]*mat.m[2][3] + m[3][3]*mat.m[3][3]);
}
//! Operator for HPoint Mul = Matrix4x4 * HPoint;
inline_ HPoint operator*(const HPoint& v) const { return HPoint(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v, GetRow(3)|v); }
//! Operator for Point Mul = Matrix4x4 * Point;
inline_ Point operator*(const Point& v) const
{
return Point( m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3],
m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3],
m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3] );
}
//! Operator for Matrix4x4 Scale = Matrix4x4 * float;
inline_ Matrix4x4 operator*(float s) const
{
return Matrix4x4(
m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s,
m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s,
m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s,
m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s);
}
//! Operator for Matrix4x4 Scale = float * Matrix4x4;
inline_ friend Matrix4x4 operator*(float s, const Matrix4x4& mat)
{
return Matrix4x4(
s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], s*mat.m[0][3],
s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], s*mat.m[1][3],
s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2], s*mat.m[2][3],
s*mat.m[3][0], s*mat.m[3][1], s*mat.m[3][2], s*mat.m[3][3]);
}
//! Operator for Matrix4x4 Div = Matrix4x4 / float;
inline_ Matrix4x4 operator/(float s) const
{
if(s) s = 1.0f / s;
return Matrix4x4(
m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s,
m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s,
m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s,
m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s);
}
//! Operator for Matrix4x4 Div = float / Matrix4x4;
inline_ friend Matrix4x4 operator/(float s, const Matrix4x4& mat)
{
return Matrix4x4(
s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], s/mat.m[0][3],
s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], s/mat.m[1][3],
s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2], s/mat.m[2][3],
s/mat.m[3][0], s/mat.m[3][1], s/mat.m[3][2], s/mat.m[3][3]);
}
//! Operator for Matrix4x4 += Matrix4x4;
inline_ Matrix4x4& operator+=(const Matrix4x4& mat)
{
m[0][0]+=mat.m[0][0]; m[0][1]+=mat.m[0][1]; m[0][2]+=mat.m[0][2]; m[0][3]+=mat.m[0][3];
m[1][0]+=mat.m[1][0]; m[1][1]+=mat.m[1][1]; m[1][2]+=mat.m[1][2]; m[1][3]+=mat.m[1][3];
m[2][0]+=mat.m[2][0]; m[2][1]+=mat.m[2][1]; m[2][2]+=mat.m[2][2]; m[2][3]+=mat.m[2][3];
m[3][0]+=mat.m[3][0]; m[3][1]+=mat.m[3][1]; m[3][2]+=mat.m[3][2]; m[3][3]+=mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 -= Matrix4x4;
inline_ Matrix4x4& operator-=(const Matrix4x4& mat)
{
m[0][0]-=mat.m[0][0]; m[0][1]-=mat.m[0][1]; m[0][2]-=mat.m[0][2]; m[0][3]-=mat.m[0][3];
m[1][0]-=mat.m[1][0]; m[1][1]-=mat.m[1][1]; m[1][2]-=mat.m[1][2]; m[1][3]-=mat.m[1][3];
m[2][0]-=mat.m[2][0]; m[2][1]-=mat.m[2][1]; m[2][2]-=mat.m[2][2]; m[2][3]-=mat.m[2][3];
m[3][0]-=mat.m[3][0]; m[3][1]-=mat.m[3][1]; m[3][2]-=mat.m[3][2]; m[3][3]-=mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 *= Matrix4x4;
Matrix4x4& operator*=(const Matrix4x4& mat)
{
HPoint TempRow;
GetRow(0, TempRow);
m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[0][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(1, TempRow);
m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[1][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(2, TempRow);
m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[2][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(3, TempRow);
m[3][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[3][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[3][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[3][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 *= float;
inline_ Matrix4x4& operator*=(float s)
{
m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s;
m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s;
m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s;
m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s;
return *this;
}
//! Operator for Matrix4x4 /= float;
inline_ Matrix4x4& operator/=(float s)
{
if(s) s = 1.0f / s;
m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s;
m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s;
m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s;
m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s;
return *this;
}
inline_ const HPoint& operator[](int row) const { return *(const HPoint*)&m[row][0]; }
inline_ HPoint& operator[](int row) { return *(HPoint*)&m[row][0]; }
public:
float m[4][4];
};
//! Quickly rotates & translates a vector, using the 4x3 part of a 4x4 matrix
inline_ void TransformPoint4x3(Point& dest, const Point& source, const Matrix4x4& rot)
{
dest.x = rot.m[3][0] + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = rot.m[3][1] + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = rot.m[3][2] + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
//! Quickly rotates a vector, using the 3x3 part of a 4x4 matrix
inline_ void TransformPoint3x3(Point& dest, const Point& source, const Matrix4x4& rot)
{
dest.x = source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
ICEMATHS_API void InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src);
#endif // __ICEMATRIX4X4_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 4x4 matrices.
* \file IceMatrix4x4.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEMATRIX4X4_H__
#define __ICEMATRIX4X4_H__
// Forward declarations
class PRS;
class PR;
#define MATRIX4X4_EPSILON (1.0e-7f)
class ICEMATHS_API Matrix4x4
{
// void LUBackwardSubstitution( sdword *indx, float* b );
// void LUDecomposition( sdword* indx, float* d );
public:
//! Empty constructor.
inline_ Matrix4x4() {}
//! Constructor from 16 values
inline_ Matrix4x4( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
}
//! Copy constructor
inline_ Matrix4x4(const Matrix4x4& mat) { CopyMemory(m, &mat.m, 16*sizeof(float)); }
//! Destructor.
inline_ ~Matrix4x4() {}
//! Assign values (rotation only)
inline_ Matrix4x4& Set( float m00, float m01, float m02,
float m10, float m11, float m12,
float m20, float m21, float m22)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22;
return *this;
}
//! Assign values
inline_ Matrix4x4& Set( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
return *this;
}
//! Copy from a Matrix4x4
inline_ void Copy(const Matrix4x4& source) { CopyMemory(m, source.m, 16*sizeof(float)); }
// Row-column access
//! Returns a row.
inline_ void GetRow(const udword r, HPoint& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; p.w=m[r][3]; }
//! Returns a row.
inline_ void GetRow(const udword r, Point& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; }
//! Returns a row.
inline_ const HPoint& GetRow(const udword r) const { return *(const HPoint*)&m[r][0]; }
//! Returns a row.
inline_ HPoint& GetRow(const udword r) { return *(HPoint*)&m[r][0]; }
//! Sets a row.
inline_ void SetRow(const udword r, const HPoint& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]=p.w; }
//! Sets a row.
inline_ void SetRow(const udword r, const Point& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]= (r!=3) ? 0.0f : 1.0f; }
//! Returns a column.
inline_ void GetCol(const udword c, HPoint& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; p.w=m[3][c]; }
//! Returns a column.
inline_ void GetCol(const udword c, Point& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; }
//! Sets a column.
inline_ void SetCol(const udword c, const HPoint& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]=p.w; }
//! Sets a column.
inline_ void SetCol(const udword c, const Point& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]= (c!=3) ? 0.0f : 1.0f; }
// Translation
//! Returns the translation part of the matrix.
inline_ const HPoint& GetTrans() const { return GetRow(3); }
//! Gets the translation part of the matrix
inline_ void GetTrans(Point& p) const { p.x=m[3][0]; p.y=m[3][1]; p.z=m[3][2]; }
//! Sets the translation part of the matrix, from a Point.
inline_ void SetTrans(const Point& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; }
//! Sets the translation part of the matrix, from a HPoint.
inline_ void SetTrans(const HPoint& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; m[3][3]=p.w; }
//! Sets the translation part of the matrix, from floats.
inline_ void SetTrans(float tx, float ty, float tz) { m[3][0]=tx; m[3][1]=ty; m[3][2]=tz; }
// Scale
//! Sets the scale from a Point. The point is put on the diagonal.
inline_ void SetScale(const Point& p) { m[0][0]=p.x; m[1][1]=p.y; m[2][2]=p.z; }
//! Sets the scale from floats. Values are put on the diagonal.
inline_ void SetScale(float sx, float sy, float sz) { m[0][0]=sx; m[1][1]=sy; m[2][2]=sz; }
//! Scales from a Point. Each row is multiplied by a component.
void Scale(const Point& p)
{
m[0][0] *= p.x; m[1][0] *= p.y; m[2][0] *= p.z;
m[0][1] *= p.x; m[1][1] *= p.y; m[2][1] *= p.z;
m[0][2] *= p.x; m[1][2] *= p.y; m[2][2] *= p.z;
}
//! Scales from floats. Each row is multiplied by a value.
void Scale(float sx, float sy, float sz)
{
m[0][0] *= sx; m[1][0] *= sy; m[2][0] *= sz;
m[0][1] *= sx; m[1][1] *= sy; m[2][1] *= sz;
m[0][2] *= sx; m[1][2] *= sy; m[2][2] *= sz;
}
/*
//! Returns a row.
inline_ HPoint GetRow(const udword row) const { return mRow[row]; }
//! Sets a row.
inline_ Matrix4x4& SetRow(const udword row, const HPoint& p) { mRow[row] = p; return *this; }
//! Sets a row.
Matrix4x4& SetRow(const udword row, const Point& p)
{
m[row][0] = p.x;
m[row][1] = p.y;
m[row][2] = p.z;
m[row][3] = (row != 3) ? 0.0f : 1.0f;
return *this;
}
//! Returns a column.
HPoint GetCol(const udword col) const
{
HPoint Res;
Res.x = m[0][col];
Res.y = m[1][col];
Res.z = m[2][col];
Res.w = m[3][col];
return Res;
}
//! Sets a column.
Matrix4x4& SetCol(const udword col, const HPoint& p)
{
m[0][col] = p.x;
m[1][col] = p.y;
m[2][col] = p.z;
m[3][col] = p.w;
return *this;
}
//! Sets a column.
Matrix4x4& SetCol(const udword col, const Point& p)
{
m[0][col] = p.x;
m[1][col] = p.y;
m[2][col] = p.z;
m[3][col] = (col != 3) ? 0.0f : 1.0f;
return *this;
}
*/
//! Computes the trace. The trace is the sum of the 4 diagonal components.
inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; }
//! Computes the trace of the upper 3x3 matrix.
inline_ float Trace3x3() const { return m[0][0] + m[1][1] + m[2][2]; }
//! Clears the matrix.
inline_ void Zero() { ZeroMemory(&m, sizeof(m)); }
//! Sets the identity matrix.
inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; }
//! Checks for identity
inline_ bool IsIdentity() const
{
if(IR(m[0][0])!=IEEE_1_0) return false;
if(IR(m[0][1])!=0) return false;
if(IR(m[0][2])!=0) return false;
if(IR(m[0][3])!=0) return false;
if(IR(m[1][0])!=0) return false;
if(IR(m[1][1])!=IEEE_1_0) return false;
if(IR(m[1][2])!=0) return false;
if(IR(m[1][3])!=0) return false;
if(IR(m[2][0])!=0) return false;
if(IR(m[2][1])!=0) return false;
if(IR(m[2][2])!=IEEE_1_0) return false;
if(IR(m[2][3])!=0) return false;
if(IR(m[3][0])!=0) return false;
if(IR(m[3][1])!=0) return false;
if(IR(m[3][2])!=0) return false;
if(IR(m[3][3])!=IEEE_1_0) return false;
return true;
}
//! Checks matrix validity
inline_ BOOL IsValid() const
{
for(udword j=0;j<4;j++)
{
for(udword i=0;i<4;i++)
{
if(!IsValidFloat(m[j][i])) return FALSE;
}
}
return TRUE;
}
//! Sets a rotation matrix around the X axis.
void RotX(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[1][1] = m[2][2] = Cos; m[2][1] = -Sin; m[1][2] = Sin; }
//! Sets a rotation matrix around the Y axis.
void RotY(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[2][2] = Cos; m[2][0] = Sin; m[0][2] = -Sin; }
//! Sets a rotation matrix around the Z axis.
void RotZ(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[1][1] = Cos; m[1][0] = -Sin; m[0][1] = Sin; }
//! Makes a rotation matrix about an arbitrary axis
Matrix4x4& Rot(float angle, Point& p1, Point& p2);
//! Transposes the matrix.
void Transpose()
{
IR(m[1][0]) ^= IR(m[0][1]); IR(m[0][1]) ^= IR(m[1][0]); IR(m[1][0]) ^= IR(m[0][1]);
IR(m[2][0]) ^= IR(m[0][2]); IR(m[0][2]) ^= IR(m[2][0]); IR(m[2][0]) ^= IR(m[0][2]);
IR(m[3][0]) ^= IR(m[0][3]); IR(m[0][3]) ^= IR(m[3][0]); IR(m[3][0]) ^= IR(m[0][3]);
IR(m[1][2]) ^= IR(m[2][1]); IR(m[2][1]) ^= IR(m[1][2]); IR(m[1][2]) ^= IR(m[2][1]);
IR(m[1][3]) ^= IR(m[3][1]); IR(m[3][1]) ^= IR(m[1][3]); IR(m[1][3]) ^= IR(m[3][1]);
IR(m[2][3]) ^= IR(m[3][2]); IR(m[3][2]) ^= IR(m[2][3]); IR(m[2][3]) ^= IR(m[3][2]);
}
//! Computes a cofactor. Used for matrix inversion.
float CoFactor(udword row, udword col) const;
//! Computes the determinant of the matrix.
float Determinant() const;
//! Inverts the matrix. Determinant must be different from zero, else matrix can't be inverted.
Matrix4x4& Invert();
// Matrix& ComputeAxisMatrix(Point& axis, float angle);
// Cast operators
//! Casts a Matrix4x4 to a Matrix3x3.
inline_ operator Matrix3x3() const
{
return Matrix3x3(
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
}
//! Casts a Matrix4x4 to a Quat.
operator Quat() const;
//! Casts a Matrix4x4 to a PR.
operator PR() const;
// Arithmetic operators
//! Operator for Matrix4x4 Plus = Matrix4x4 + Matrix4x4;
inline_ Matrix4x4 operator+(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]+mat.m[0][0], m[0][1]+mat.m[0][1], m[0][2]+mat.m[0][2], m[0][3]+mat.m[0][3],
m[1][0]+mat.m[1][0], m[1][1]+mat.m[1][1], m[1][2]+mat.m[1][2], m[1][3]+mat.m[1][3],
m[2][0]+mat.m[2][0], m[2][1]+mat.m[2][1], m[2][2]+mat.m[2][2], m[2][3]+mat.m[2][3],
m[3][0]+mat.m[3][0], m[3][1]+mat.m[3][1], m[3][2]+mat.m[3][2], m[3][3]+mat.m[3][3]);
}
//! Operator for Matrix4x4 Minus = Matrix4x4 - Matrix4x4;
inline_ Matrix4x4 operator-(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]-mat.m[0][0], m[0][1]-mat.m[0][1], m[0][2]-mat.m[0][2], m[0][3]-mat.m[0][3],
m[1][0]-mat.m[1][0], m[1][1]-mat.m[1][1], m[1][2]-mat.m[1][2], m[1][3]-mat.m[1][3],
m[2][0]-mat.m[2][0], m[2][1]-mat.m[2][1], m[2][2]-mat.m[2][2], m[2][3]-mat.m[2][3],
m[3][0]-mat.m[3][0], m[3][1]-mat.m[3][1], m[3][2]-mat.m[3][2], m[3][3]-mat.m[3][3]);
}
//! Operator for Matrix4x4 Mul = Matrix4x4 * Matrix4x4;
inline_ Matrix4x4 operator*(const Matrix4x4& mat) const
{
return Matrix4x4(
m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0] + m[0][3]*mat.m[3][0],
m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1] + m[0][3]*mat.m[3][1],
m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2] + m[0][3]*mat.m[3][2],
m[0][0]*mat.m[0][3] + m[0][1]*mat.m[1][3] + m[0][2]*mat.m[2][3] + m[0][3]*mat.m[3][3],
m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0] + m[1][3]*mat.m[3][0],
m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1] + m[1][3]*mat.m[3][1],
m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2] + m[1][3]*mat.m[3][2],
m[1][0]*mat.m[0][3] + m[1][1]*mat.m[1][3] + m[1][2]*mat.m[2][3] + m[1][3]*mat.m[3][3],
m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0] + m[2][3]*mat.m[3][0],
m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1] + m[2][3]*mat.m[3][1],
m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2] + m[2][3]*mat.m[3][2],
m[2][0]*mat.m[0][3] + m[2][1]*mat.m[1][3] + m[2][2]*mat.m[2][3] + m[2][3]*mat.m[3][3],
m[3][0]*mat.m[0][0] + m[3][1]*mat.m[1][0] + m[3][2]*mat.m[2][0] + m[3][3]*mat.m[3][0],
m[3][0]*mat.m[0][1] + m[3][1]*mat.m[1][1] + m[3][2]*mat.m[2][1] + m[3][3]*mat.m[3][1],
m[3][0]*mat.m[0][2] + m[3][1]*mat.m[1][2] + m[3][2]*mat.m[2][2] + m[3][3]*mat.m[3][2],
m[3][0]*mat.m[0][3] + m[3][1]*mat.m[1][3] + m[3][2]*mat.m[2][3] + m[3][3]*mat.m[3][3]);
}
//! Operator for HPoint Mul = Matrix4x4 * HPoint;
inline_ HPoint operator*(const HPoint& v) const { return HPoint(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v, GetRow(3)|v); }
//! Operator for Point Mul = Matrix4x4 * Point;
inline_ Point operator*(const Point& v) const
{
return Point( m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3],
m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3],
m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3] );
}
//! Operator for Matrix4x4 Scale = Matrix4x4 * float;
inline_ Matrix4x4 operator*(float s) const
{
return Matrix4x4(
m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s,
m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s,
m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s,
m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s);
}
//! Operator for Matrix4x4 Scale = float * Matrix4x4;
inline_ friend Matrix4x4 operator*(float s, const Matrix4x4& mat)
{
return Matrix4x4(
s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], s*mat.m[0][3],
s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], s*mat.m[1][3],
s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2], s*mat.m[2][3],
s*mat.m[3][0], s*mat.m[3][1], s*mat.m[3][2], s*mat.m[3][3]);
}
//! Operator for Matrix4x4 Div = Matrix4x4 / float;
inline_ Matrix4x4 operator/(float s) const
{
if(s) s = 1.0f / s;
return Matrix4x4(
m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s,
m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s,
m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s,
m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s);
}
//! Operator for Matrix4x4 Div = float / Matrix4x4;
inline_ friend Matrix4x4 operator/(float s, const Matrix4x4& mat)
{
return Matrix4x4(
s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], s/mat.m[0][3],
s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], s/mat.m[1][3],
s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2], s/mat.m[2][3],
s/mat.m[3][0], s/mat.m[3][1], s/mat.m[3][2], s/mat.m[3][3]);
}
//! Operator for Matrix4x4 += Matrix4x4;
inline_ Matrix4x4& operator+=(const Matrix4x4& mat)
{
m[0][0]+=mat.m[0][0]; m[0][1]+=mat.m[0][1]; m[0][2]+=mat.m[0][2]; m[0][3]+=mat.m[0][3];
m[1][0]+=mat.m[1][0]; m[1][1]+=mat.m[1][1]; m[1][2]+=mat.m[1][2]; m[1][3]+=mat.m[1][3];
m[2][0]+=mat.m[2][0]; m[2][1]+=mat.m[2][1]; m[2][2]+=mat.m[2][2]; m[2][3]+=mat.m[2][3];
m[3][0]+=mat.m[3][0]; m[3][1]+=mat.m[3][1]; m[3][2]+=mat.m[3][2]; m[3][3]+=mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 -= Matrix4x4;
inline_ Matrix4x4& operator-=(const Matrix4x4& mat)
{
m[0][0]-=mat.m[0][0]; m[0][1]-=mat.m[0][1]; m[0][2]-=mat.m[0][2]; m[0][3]-=mat.m[0][3];
m[1][0]-=mat.m[1][0]; m[1][1]-=mat.m[1][1]; m[1][2]-=mat.m[1][2]; m[1][3]-=mat.m[1][3];
m[2][0]-=mat.m[2][0]; m[2][1]-=mat.m[2][1]; m[2][2]-=mat.m[2][2]; m[2][3]-=mat.m[2][3];
m[3][0]-=mat.m[3][0]; m[3][1]-=mat.m[3][1]; m[3][2]-=mat.m[3][2]; m[3][3]-=mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 *= Matrix4x4;
Matrix4x4& operator*=(const Matrix4x4& mat)
{
HPoint TempRow;
GetRow(0, TempRow);
m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[0][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(1, TempRow);
m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[1][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(2, TempRow);
m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[2][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
GetRow(3, TempRow);
m[3][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0];
m[3][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1];
m[3][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2];
m[3][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3];
return *this;
}
//! Operator for Matrix4x4 *= float;
inline_ Matrix4x4& operator*=(float s)
{
m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s;
m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s;
m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s;
m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s;
return *this;
}
//! Operator for Matrix4x4 /= float;
inline_ Matrix4x4& operator/=(float s)
{
if(s) s = 1.0f / s;
m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s;
m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s;
m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s;
m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s;
return *this;
}
inline_ const HPoint& operator[](int row) const { return *(const HPoint*)&m[row][0]; }
inline_ HPoint& operator[](int row) { return *(HPoint*)&m[row][0]; }
public:
float m[4][4];
};
//! Quickly rotates & translates a vector, using the 4x3 part of a 4x4 matrix
inline_ void TransformPoint4x3(Point& dest, const Point& source, const Matrix4x4& rot)
{
dest.x = rot.m[3][0] + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = rot.m[3][1] + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = rot.m[3][2] + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
//! Quickly rotates a vector, using the 3x3 part of a 4x4 matrix
inline_ void TransformPoint3x3(Point& dest, const Point& source, const Matrix4x4& rot)
{
dest.x = source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
ICEMATHS_API void InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src);
#endif // __ICEMATRIX4X4_H__

View File

@@ -1,180 +1,180 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains all memory macros.
* \file IceMemoryMacros.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEMEMORYMACROS_H
#define ICEMEMORYMACROS_H
#undef ZeroMemory
#undef CopyMemory
#undef MoveMemory
#undef FillMemory
//! Clears a buffer.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
//! \see MoveMemory
inline_ void ZeroMemory(void* addr, regsize size) { memset(addr, 0, size); }
//! Fills a buffer with a given byte.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \param val [in] the byte value
//! \see StoreDwords
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
inline_ void FillMemory(void* dest, regsize size, ubyte val) { memset(dest, val, size); }
//! Fills a buffer with a given dword.
//! \param addr [in] buffer address
//! \param nb [in] number of dwords to write
//! \param value [in] the dword value
//! \see FillMemory
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
//! \warning writes nb*4 bytes !
inline_ void StoreDwords(udword* dest, udword nb, udword value)
{
// The asm code below **SHOULD** be equivalent to one of those C versions
// or the other if your compiled is good: (checked on VC++ 6.0)
//
// 1) while(nb--) *dest++ = value;
//
// 2) for(udword i=0;i<nb;i++) dest[i] = value;
//
_asm push eax
_asm push ecx
_asm push edi
_asm mov edi, dest
_asm mov ecx, nb
_asm mov eax, value
_asm rep stosd
_asm pop edi
_asm pop ecx
_asm pop eax
}
//! Copies a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see MoveMemory
inline_ void CopyMemory(void* dest, const void* src, regsize size) { memcpy(dest, src, size); }
//! Moves a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
inline_ void MoveMemory(void* dest, const void* src, regsize size) { memmove(dest, src, size); }
//! Flexible buffer copy
//! \param src [in] source buffer address
//! \param dst [in] destination buffer address
//! \param nb_elem [in] number of elements to copy
//! \param elem_size [in] size of an element
//! \param stride [in] stride in bytes, including size of element
inline_ void FlexiCopy(const void* src, void* dst, udword nb_elem, regsize elem_size, udword stride)
{
ubyte* d = (ubyte*)dst;
const ubyte* s = (const ubyte*)src;
const ubyte* Last = s + stride*nb_elem;
while(s!=Last)
{
CopyMemory(d, s, elem_size);
d += elem_size;
s += stride;
}
}
//! Gives the size of current object. This avoids some mistakes (e.g. "sizeof(this)").
#define SIZEOFOBJECT sizeof(*this)
//! Clears current object. Laziness is my business! HANDLE WITH CARE. ### Removed, too dangerous, cleared too many v-tables
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); }
// The two macros below are here for several reasons:
// - sometimes we write "delete x" instead of "delete []x" just because we don't pay attention. Using the macro forces you
// to think about what you're deleting, just because you have to write the macro's name (SINGLE or ARRAY).
// - always clearing the pointer afterwards prevents some double-deletion in various situations.
// - deleting null is a valid operation according to the standard, yet some lame memory managers don't like it. In sake of
// robustness, we avoid trying.
//! Deletes an instance of a class.
#define DELETESINGLE(x) if (x) { delete x; x = null; }
//! Deletes an array.
#define DELETEARRAY(x) if (x) { delete []x; x = null; }
//! Safe D3D-style release
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; }
//! Safe ICE-style release
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; }
#ifdef ICEERROR_H
//! Standard alloc checking. HANDLE WITH CARE. Relies on strict coding rules. Probably shouldn't be used outside of ICE.
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY);
#else
#define CHECKALLOC(x) if(!x) return false;
#endif
//! Standard allocation cycle
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
#define SAFE_ICE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = ICE_NEW(type)[count]; CHECKALLOC(ptr);
//! Don't use inline for alloca !!!
#ifdef WIN32
#define StackAlloc(x) _alloca(x)
#elif LINUX
#define StackAlloc(x) alloca(x)
#elif defined(__APPLE__)
#define StackAlloc(x) alloca(x)
#elif defined(_XBOX)
#define StackAlloc(x) _alloca(x)
#endif
#ifdef _DEBUG
// #define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_TEMP)
// #define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_PERSISTENT)
#define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_TEMP)
#define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_PERSISTENT)
#define ICE_ALLOC_TMP2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_TEMP)
#define ICE_ALLOC2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_PERSISTENT)
#else
#define ICE_ALLOC_TMP(x) GetAllocator()->malloc(x, MEMORY_TEMP)
#define ICE_ALLOC(x) GetAllocator()->malloc(x, MEMORY_PERSISTENT)
#endif
#define ICE_FREE(x) if(x) { GetAllocator()->free(x); x = null; }
#ifdef DONT_TRACK_MEMORY_LEAKS
#ifdef _DEBUG
#define ICE_NEW_TMP(x) new(__FILE__, __LINE__, #x, MEMORY_TEMP) x
#define ICE_NEW(x) new(__FILE__, __LINE__, #x, MEMORY_PERSISTENT) x
#else
#define ICE_NEW_TMP(x) new(MEMORY_TEMP) x
#define ICE_NEW(x) new(MEMORY_PERSISTENT) x
#endif
#else
#define ICE_NEW_TMP(x) new x
#define ICE_NEW(x) new x
#endif
#endif // ICEMEMORYMACROS_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains all memory macros.
* \file IceMemoryMacros.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEMEMORYMACROS_H
#define ICEMEMORYMACROS_H
#undef ZeroMemory
#undef CopyMemory
#undef MoveMemory
#undef FillMemory
//! Clears a buffer.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
//! \see MoveMemory
inline_ void ZeroMemory(void* addr, regsize size) { memset(addr, 0, size); }
//! Fills a buffer with a given byte.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \param val [in] the byte value
//! \see StoreDwords
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
inline_ void FillMemory(void* dest, regsize size, ubyte val) { memset(dest, val, size); }
//! Fills a buffer with a given dword.
//! \param addr [in] buffer address
//! \param nb [in] number of dwords to write
//! \param value [in] the dword value
//! \see FillMemory
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
//! \warning writes nb*4 bytes !
inline_ void StoreDwords(udword* dest, udword nb, udword value)
{
// The asm code below **SHOULD** be equivalent to one of those C versions
// or the other if your compiled is good: (checked on VC++ 6.0)
//
// 1) while(nb--) *dest++ = value;
//
// 2) for(udword i=0;i<nb;i++) dest[i] = value;
//
_asm push eax
_asm push ecx
_asm push edi
_asm mov edi, dest
_asm mov ecx, nb
_asm mov eax, value
_asm rep stosd
_asm pop edi
_asm pop ecx
_asm pop eax
}
//! Copies a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see MoveMemory
inline_ void CopyMemory(void* dest, const void* src, regsize size) { memcpy(dest, src, size); }
//! Moves a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
inline_ void MoveMemory(void* dest, const void* src, regsize size) { memmove(dest, src, size); }
//! Flexible buffer copy
//! \param src [in] source buffer address
//! \param dst [in] destination buffer address
//! \param nb_elem [in] number of elements to copy
//! \param elem_size [in] size of an element
//! \param stride [in] stride in bytes, including size of element
inline_ void FlexiCopy(const void* src, void* dst, udword nb_elem, regsize elem_size, udword stride)
{
ubyte* d = (ubyte*)dst;
const ubyte* s = (const ubyte*)src;
const ubyte* Last = s + stride*nb_elem;
while(s!=Last)
{
CopyMemory(d, s, elem_size);
d += elem_size;
s += stride;
}
}
//! Gives the size of current object. This avoids some mistakes (e.g. "sizeof(this)").
#define SIZEOFOBJECT sizeof(*this)
//! Clears current object. Laziness is my business! HANDLE WITH CARE. ### Removed, too dangerous, cleared too many v-tables
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); }
// The two macros below are here for several reasons:
// - sometimes we write "delete x" instead of "delete []x" just because we don't pay attention. Using the macro forces you
// to think about what you're deleting, just because you have to write the macro's name (SINGLE or ARRAY).
// - always clearing the pointer afterwards prevents some double-deletion in various situations.
// - deleting null is a valid operation according to the standard, yet some lame memory managers don't like it. In sake of
// robustness, we avoid trying.
//! Deletes an instance of a class.
#define DELETESINGLE(x) if (x) { delete x; x = null; }
//! Deletes an array.
#define DELETEARRAY(x) if (x) { delete []x; x = null; }
//! Safe D3D-style release
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; }
//! Safe ICE-style release
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; }
#ifdef ICEERROR_H
//! Standard alloc checking. HANDLE WITH CARE. Relies on strict coding rules. Probably shouldn't be used outside of ICE.
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY);
#else
#define CHECKALLOC(x) if(!x) return false;
#endif
//! Standard allocation cycle
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
#define SAFE_ICE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = ICE_NEW(type)[count]; CHECKALLOC(ptr);
//! Don't use inline for alloca !!!
#ifdef WIN32
#define StackAlloc(x) _alloca(x)
#elif LINUX
#define StackAlloc(x) alloca(x)
#elif defined(__APPLE__)
#define StackAlloc(x) alloca(x)
#elif defined(_XBOX)
#define StackAlloc(x) _alloca(x)
#endif
#ifdef _DEBUG
// #define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_TEMP)
// #define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_PERSISTENT)
#define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_TEMP)
#define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_PERSISTENT)
#define ICE_ALLOC_TMP2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_TEMP)
#define ICE_ALLOC2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_PERSISTENT)
#else
#define ICE_ALLOC_TMP(x) GetAllocator()->malloc(x, MEMORY_TEMP)
#define ICE_ALLOC(x) GetAllocator()->malloc(x, MEMORY_PERSISTENT)
#endif
#define ICE_FREE(x) if(x) { GetAllocator()->free(x); x = null; }
#ifdef DONT_TRACK_MEMORY_LEAKS
#ifdef _DEBUG
#define ICE_NEW_TMP(x) new(__FILE__, __LINE__, #x, MEMORY_TEMP) x
#define ICE_NEW(x) new(__FILE__, __LINE__, #x, MEMORY_PERSISTENT) x
#else
#define ICE_NEW_TMP(x) new(MEMORY_TEMP) x
#define ICE_NEW(x) new(MEMORY_PERSISTENT) x
#endif
#else
#define ICE_NEW_TMP(x) new x
#define ICE_NEW(x) new x
#endif
#endif // ICEMEMORYMACROS_H

View File

@@ -1,339 +1,339 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains OBB-related code.
* \file IceOBB.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An Oriented Bounding Box (OBB).
* \class OBB
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the OBB.
* \param p [in] the world point to test
* \return true if inside the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ContainsPoint(const Point& p) const
{
// Point in OBB test using lazy evaluation and early exits
// Translate to box space
Point RelPoint = p - mCenter;
// Point * mRot maps from box space to world space
// mRot * Point maps from world space to box space (what we need here)
float f = mRot.m[0][0] * RelPoint.x + mRot.m[0][1] * RelPoint.y + mRot.m[0][2] * RelPoint.z;
if(f >= mExtents.x || f <= -mExtents.x) return false;
f = mRot.m[1][0] * RelPoint.x + mRot.m[1][1] * RelPoint.y + mRot.m[1][2] * RelPoint.z;
if(f >= mExtents.y || f <= -mExtents.y) return false;
f = mRot.m[2][0] * RelPoint.x + mRot.m[2][1] * RelPoint.y + mRot.m[2][2] * RelPoint.z;
if(f >= mExtents.z || f <= -mExtents.z) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds an OBB from an AABB and a world transform.
* \param aabb [in] the aabb
* \param mat [in] the world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::Create(const AABB& aabb, const Matrix4x4& mat)
{
// Note: must be coherent with Rotate()
aabb.GetCenter(mCenter);
aabb.GetExtents(mExtents);
// Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity).
// So following what's done in Rotate:
// - x-form the center
mCenter *= mat;
// - combine rotation with identity, i.e. just use given matrix
mRot = mat;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb planes.
* \param planes [out] 6 box planes
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputePlanes(Plane* planes) const
{
// Checkings
if(!planes) return false;
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
// Writes normals
planes[0].n = Axis0;
planes[1].n = -Axis0;
planes[2].n = Axis1;
planes[3].n = -Axis1;
planes[4].n = Axis2;
planes[5].n = -Axis2;
// Compute a point on each plane
Point p0 = mCenter + Axis0 * mExtents.x;
Point p1 = mCenter - Axis0 * mExtents.x;
Point p2 = mCenter + Axis1 * mExtents.y;
Point p3 = mCenter - Axis1 * mExtents.y;
Point p4 = mCenter + Axis2 * mExtents.z;
Point p5 = mCenter - Axis2 * mExtents.z;
// Compute d
planes[0].d = -(planes[0].n|p0);
planes[1].d = -(planes[1].n|p1);
planes[2].d = -(planes[2].n|p2);
planes[3].d = -(planes[3].n|p3);
planes[4].d = -(planes[4].n|p4);
planes[5].d = -(planes[5].n|p5);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputePoints(Point* pts) const
{
// Checkings
if(!pts) return false;
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
Axis0 *= mExtents.x;
Axis1 *= mExtents.y;
Axis2 *= mExtents.z;
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
pts[0] = mCenter - Axis0 - Axis1 - Axis2;
pts[1] = mCenter + Axis0 - Axis1 - Axis2;
pts[2] = mCenter + Axis0 + Axis1 - Axis2;
pts[3] = mCenter - Axis0 + Axis1 - Axis2;
pts[4] = mCenter - Axis0 - Axis1 + Axis2;
pts[5] = mCenter + Axis0 - Axis1 + Axis2;
pts[6] = mCenter + Axis0 + Axis1 + Axis2;
pts[7] = mCenter - Axis0 + Axis1 + Axis2;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputeVertexNormals(Point* pts) const
{
static float VertexNormals[] =
{
-INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, INVSQRT3, INVSQRT3,
-INVSQRT3, INVSQRT3, INVSQRT3
};
if(!pts) return false;
const Point* VN = (const Point*)VertexNormals;
for(udword i=0;i<8;i++)
{
pts[i] = VN[i] * mRot;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* OBB::GetEdges() const
{
static udword Indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
7, 6, 6, 5, 5, 4, 4, 7,
1, 5, 6, 2,
3, 7, 4, 0
};
return Indices;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns local edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* OBB::GetLocalEdgeNormals() const
{
static float EdgeNormals[] =
{
0, -INVSQRT2, -INVSQRT2, // 0-1
INVSQRT2, 0, -INVSQRT2, // 1-2
0, INVSQRT2, -INVSQRT2, // 2-3
-INVSQRT2, 0, -INVSQRT2, // 3-0
0, INVSQRT2, INVSQRT2, // 7-6
INVSQRT2, 0, INVSQRT2, // 6-5
0, -INVSQRT2, INVSQRT2, // 5-4
-INVSQRT2, 0, INVSQRT2, // 4-7
INVSQRT2, -INVSQRT2, 0, // 1-5
INVSQRT2, INVSQRT2, 0, // 6-2
-INVSQRT2, INVSQRT2, 0, // 3-7
-INVSQRT2, -INVSQRT2, 0 // 4-0
};
return (const Point*)EdgeNormals;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns world edge normal
* \param edge_index [in] 0 <= edge index < 12
* \param world_normal [out] edge normal in world space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const
{
ASSERT(edge_index<12);
world_normal = GetLocalEdgeNormals()[edge_index] * mRot;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an LSS surrounding the OBB.
* \param lss [out] the LSS
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::ComputeLSS(LSS& lss) const
{
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
switch(mExtents.LargestAxis())
{
case 0:
lss.mRadius = (mExtents.y + mExtents.z)*0.5f;
lss.mP0 = mCenter + Axis0 * (mExtents.x - lss.mRadius);
lss.mP1 = mCenter - Axis0 * (mExtents.x - lss.mRadius);
break;
case 1:
lss.mRadius = (mExtents.x + mExtents.z)*0.5f;
lss.mP0 = mCenter + Axis1 * (mExtents.y - lss.mRadius);
lss.mP1 = mCenter - Axis1 * (mExtents.y - lss.mRadius);
break;
case 2:
lss.mRadius = (mExtents.x + mExtents.y)*0.5f;
lss.mP0 = mCenter + Axis2 * (mExtents.z - lss.mRadius);
lss.mP1 = mCenter - Axis2 * (mExtents.z - lss.mRadius);
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is inside another OBB.
* \param box [in] the other OBB
* \return TRUE if we're inside the other box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL OBB::IsInside(const OBB& box) const
{
// Make a 4x4 from the box & inverse it
Matrix4x4 M0Inv;
{
Matrix4x4 M0 = box.mRot;
M0.SetTrans(box.mCenter);
InvertPRMatrix(M0Inv, M0);
}
// With our inversed 4x4, create box1 in space of box0
OBB _1in0;
Rotate(M0Inv, _1in0);
// This should cancel out box0's rotation, i.e. it's now an AABB.
// => Center(0,0,0), Rot(identity)
// The two boxes are in the same space so now we can compare them.
// Create the AABB of (box1 in space of box0)
const Matrix3x3& mtx = _1in0.mRot;
float f = fabsf(mtx.m[0][0] * mExtents.x) + fabsf(mtx.m[1][0] * mExtents.y) + fabsf(mtx.m[2][0] * mExtents.z) - box.mExtents.x;
if(f > _1in0.mCenter.x) return FALSE;
if(-f < _1in0.mCenter.x) return FALSE;
f = fabsf(mtx.m[0][1] * mExtents.x) + fabsf(mtx.m[1][1] * mExtents.y) + fabsf(mtx.m[2][1] * mExtents.z) - box.mExtents.y;
if(f > _1in0.mCenter.y) return FALSE;
if(-f < _1in0.mCenter.y) return FALSE;
f = fabsf(mtx.m[0][2] * mExtents.x) + fabsf(mtx.m[1][2] * mExtents.y) + fabsf(mtx.m[2][2] * mExtents.z) - box.mExtents.z;
if(f > _1in0.mCenter.z) return FALSE;
if(-f < _1in0.mCenter.z) return FALSE;
return TRUE;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains OBB-related code.
* \file IceOBB.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An Oriented Bounding Box (OBB).
* \class OBB
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the OBB.
* \param p [in] the world point to test
* \return true if inside the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ContainsPoint(const Point& p) const
{
// Point in OBB test using lazy evaluation and early exits
// Translate to box space
Point RelPoint = p - mCenter;
// Point * mRot maps from box space to world space
// mRot * Point maps from world space to box space (what we need here)
float f = mRot.m[0][0] * RelPoint.x + mRot.m[0][1] * RelPoint.y + mRot.m[0][2] * RelPoint.z;
if(f >= mExtents.x || f <= -mExtents.x) return false;
f = mRot.m[1][0] * RelPoint.x + mRot.m[1][1] * RelPoint.y + mRot.m[1][2] * RelPoint.z;
if(f >= mExtents.y || f <= -mExtents.y) return false;
f = mRot.m[2][0] * RelPoint.x + mRot.m[2][1] * RelPoint.y + mRot.m[2][2] * RelPoint.z;
if(f >= mExtents.z || f <= -mExtents.z) return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds an OBB from an AABB and a world transform.
* \param aabb [in] the aabb
* \param mat [in] the world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::Create(const AABB& aabb, const Matrix4x4& mat)
{
// Note: must be coherent with Rotate()
aabb.GetCenter(mCenter);
aabb.GetExtents(mExtents);
// Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity).
// So following what's done in Rotate:
// - x-form the center
mCenter *= mat;
// - combine rotation with identity, i.e. just use given matrix
mRot = mat;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb planes.
* \param planes [out] 6 box planes
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputePlanes(Plane* planes) const
{
// Checkings
if(!planes) return false;
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
// Writes normals
planes[0].n = Axis0;
planes[1].n = -Axis0;
planes[2].n = Axis1;
planes[3].n = -Axis1;
planes[4].n = Axis2;
planes[5].n = -Axis2;
// Compute a point on each plane
Point p0 = mCenter + Axis0 * mExtents.x;
Point p1 = mCenter - Axis0 * mExtents.x;
Point p2 = mCenter + Axis1 * mExtents.y;
Point p3 = mCenter - Axis1 * mExtents.y;
Point p4 = mCenter + Axis2 * mExtents.z;
Point p5 = mCenter - Axis2 * mExtents.z;
// Compute d
planes[0].d = -(planes[0].n|p0);
planes[1].d = -(planes[1].n|p1);
planes[2].d = -(planes[2].n|p2);
planes[3].d = -(planes[3].n|p3);
planes[4].d = -(planes[4].n|p4);
planes[5].d = -(planes[5].n|p5);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputePoints(Point* pts) const
{
// Checkings
if(!pts) return false;
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
Axis0 *= mExtents.x;
Axis1 *= mExtents.y;
Axis2 *= mExtents.z;
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
pts[0] = mCenter - Axis0 - Axis1 - Axis2;
pts[1] = mCenter + Axis0 - Axis1 - Axis2;
pts[2] = mCenter + Axis0 + Axis1 - Axis2;
pts[3] = mCenter - Axis0 + Axis1 - Axis2;
pts[4] = mCenter - Axis0 - Axis1 + Axis2;
pts[5] = mCenter + Axis0 - Axis1 + Axis2;
pts[6] = mCenter + Axis0 + Axis1 + Axis2;
pts[7] = mCenter - Axis0 + Axis1 + Axis2;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool OBB::ComputeVertexNormals(Point* pts) const
{
static float VertexNormals[] =
{
-INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, -INVSQRT3, -INVSQRT3,
INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, INVSQRT3, -INVSQRT3,
-INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, -INVSQRT3, INVSQRT3,
INVSQRT3, INVSQRT3, INVSQRT3,
-INVSQRT3, INVSQRT3, INVSQRT3
};
if(!pts) return false;
const Point* VN = (const Point*)VertexNormals;
for(udword i=0;i<8;i++)
{
pts[i] = VN[i] * mRot;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* OBB::GetEdges() const
{
static udword Indices[] = {
0, 1, 1, 2, 2, 3, 3, 0,
7, 6, 6, 5, 5, 4, 4, 7,
1, 5, 6, 2,
3, 7, 4, 0
};
return Indices;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns local edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* OBB::GetLocalEdgeNormals() const
{
static float EdgeNormals[] =
{
0, -INVSQRT2, -INVSQRT2, // 0-1
INVSQRT2, 0, -INVSQRT2, // 1-2
0, INVSQRT2, -INVSQRT2, // 2-3
-INVSQRT2, 0, -INVSQRT2, // 3-0
0, INVSQRT2, INVSQRT2, // 7-6
INVSQRT2, 0, INVSQRT2, // 6-5
0, -INVSQRT2, INVSQRT2, // 5-4
-INVSQRT2, 0, INVSQRT2, // 4-7
INVSQRT2, -INVSQRT2, 0, // 1-5
INVSQRT2, INVSQRT2, 0, // 6-2
-INVSQRT2, INVSQRT2, 0, // 3-7
-INVSQRT2, -INVSQRT2, 0 // 4-0
};
return (const Point*)EdgeNormals;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns world edge normal
* \param edge_index [in] 0 <= edge index < 12
* \param world_normal [out] edge normal in world space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const
{
ASSERT(edge_index<12);
world_normal = GetLocalEdgeNormals()[edge_index] * mRot;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an LSS surrounding the OBB.
* \param lss [out] the LSS
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void OBB::ComputeLSS(LSS& lss) const
{
Point Axis0 = mRot[0];
Point Axis1 = mRot[1];
Point Axis2 = mRot[2];
switch(mExtents.LargestAxis())
{
case 0:
lss.mRadius = (mExtents.y + mExtents.z)*0.5f;
lss.mP0 = mCenter + Axis0 * (mExtents.x - lss.mRadius);
lss.mP1 = mCenter - Axis0 * (mExtents.x - lss.mRadius);
break;
case 1:
lss.mRadius = (mExtents.x + mExtents.z)*0.5f;
lss.mP0 = mCenter + Axis1 * (mExtents.y - lss.mRadius);
lss.mP1 = mCenter - Axis1 * (mExtents.y - lss.mRadius);
break;
case 2:
lss.mRadius = (mExtents.x + mExtents.y)*0.5f;
lss.mP0 = mCenter + Axis2 * (mExtents.z - lss.mRadius);
lss.mP1 = mCenter - Axis2 * (mExtents.z - lss.mRadius);
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is inside another OBB.
* \param box [in] the other OBB
* \return TRUE if we're inside the other box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL OBB::IsInside(const OBB& box) const
{
// Make a 4x4 from the box & inverse it
Matrix4x4 M0Inv;
{
Matrix4x4 M0 = box.mRot;
M0.SetTrans(box.mCenter);
InvertPRMatrix(M0Inv, M0);
}
// With our inversed 4x4, create box1 in space of box0
OBB _1in0;
Rotate(M0Inv, _1in0);
// This should cancel out box0's rotation, i.e. it's now an AABB.
// => Center(0,0,0), Rot(identity)
// The two boxes are in the same space so now we can compare them.
// Create the AABB of (box1 in space of box0)
const Matrix3x3& mtx = _1in0.mRot;
float f = fabsf(mtx.m[0][0] * mExtents.x) + fabsf(mtx.m[1][0] * mExtents.y) + fabsf(mtx.m[2][0] * mExtents.z) - box.mExtents.x;
if(f > _1in0.mCenter.x) return FALSE;
if(-f < _1in0.mCenter.x) return FALSE;
f = fabsf(mtx.m[0][1] * mExtents.x) + fabsf(mtx.m[1][1] * mExtents.y) + fabsf(mtx.m[2][1] * mExtents.z) - box.mExtents.y;
if(f > _1in0.mCenter.y) return FALSE;
if(-f < _1in0.mCenter.y) return FALSE;
f = fabsf(mtx.m[0][2] * mExtents.x) + fabsf(mtx.m[1][2] * mExtents.y) + fabsf(mtx.m[2][2] * mExtents.z) - box.mExtents.z;
if(f > _1in0.mCenter.z) return FALSE;
if(-f < _1in0.mCenter.z) return FALSE;
return TRUE;
}

View File

@@ -1,193 +1,193 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains OBB-related code. (oriented bounding box)
* \file IceOBB.h
* \author Pierre Terdiman
* \date January, 13, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEOBB_H__
#define __ICEOBB_H__
// Forward declarations
class LSS;
class ICEMATHS_API OBB
{
public:
//! Constructor
inline_ OBB() {}
//! Constructor
inline_ OBB(const Point& center, const Point& extents, const Matrix3x3& rot) : mCenter(center), mExtents(extents), mRot(rot) {}
//! Destructor
inline_ ~OBB() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an empty OBB.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SetEmpty()
{
mCenter.Zero();
mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
mRot.Identity();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the OBB.
* \param p [in] the world point to test
* \return true if inside the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ContainsPoint(const Point& p) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds an OBB from an AABB and a world transform.
* \param aabb [in] the aabb
* \param mat [in] the world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Create(const AABB& aabb, const Matrix4x4& mat);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recomputes the OBB after an arbitrary transform by a 4x4 matrix.
* \param mtx [in] the transform matrix
* \param obb [out] the transformed OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Rotate(const Matrix4x4& mtx, OBB& obb) const
{
// The extents remain constant
obb.mExtents = mExtents;
// The center gets x-formed
obb.mCenter = mCenter * mtx;
// Combine rotations
obb.mRot = mRot * Matrix3x3(mtx);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is valid.
* \return true if the box is valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsValid() const
{
// Consistency condition for (Center, Extents) boxes: Extents >= 0.0f
if(mExtents.x < 0.0f) return FALSE;
if(mExtents.y < 0.0f) return FALSE;
if(mExtents.z < 0.0f) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb planes.
* \param planes [out] 6 box planes
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputePlanes(Plane* planes) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputePoints(Point* pts) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputeVertexNormals(Point* pts) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* GetEdges() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns local edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* GetLocalEdgeNormals() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns world edge normal
* \param edge_index [in] 0 <= edge index < 12
* \param world_normal [out] edge normal in world space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an LSS surrounding the OBB.
* \param lss [out] the LSS
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeLSS(LSS& lss) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is inside another OBB.
* \param box [in] the other OBB
* \return TRUE if we're inside the other box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsInside(const OBB& box) const;
inline_ const Point& GetCenter() const { return mCenter; }
inline_ const Point& GetExtents() const { return mExtents; }
inline_ const Matrix3x3& GetRot() const { return mRot; }
inline_ void GetRotatedExtents(Matrix3x3& extents) const
{
extents = mRot;
extents.Scale(mExtents);
}
Point mCenter; //!< B for Box
Point mExtents; //!< B for Bounding
Matrix3x3 mRot; //!< O for Oriented
// Orientation is stored in row-major format,
// i.e. rows = eigen vectors of the covariance matrix
};
#endif // __ICEOBB_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains OBB-related code. (oriented bounding box)
* \file IceOBB.h
* \author Pierre Terdiman
* \date January, 13, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEOBB_H__
#define __ICEOBB_H__
// Forward declarations
class LSS;
class ICEMATHS_API OBB
{
public:
//! Constructor
inline_ OBB() {}
//! Constructor
inline_ OBB(const Point& center, const Point& extents, const Matrix3x3& rot) : mCenter(center), mExtents(extents), mRot(rot) {}
//! Destructor
inline_ ~OBB() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an empty OBB.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SetEmpty()
{
mCenter.Zero();
mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
mRot.Identity();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Tests if a point is contained within the OBB.
* \param p [in] the world point to test
* \return true if inside the OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ContainsPoint(const Point& p) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds an OBB from an AABB and a world transform.
* \param aabb [in] the aabb
* \param mat [in] the world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Create(const AABB& aabb, const Matrix4x4& mat);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recomputes the OBB after an arbitrary transform by a 4x4 matrix.
* \param mtx [in] the transform matrix
* \param obb [out] the transformed OBB
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Rotate(const Matrix4x4& mtx, OBB& obb) const
{
// The extents remain constant
obb.mExtents = mExtents;
// The center gets x-formed
obb.mCenter = mCenter * mtx;
// Combine rotations
obb.mRot = mRot * Matrix3x3(mtx);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is valid.
* \return true if the box is valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsValid() const
{
// Consistency condition for (Center, Extents) boxes: Extents >= 0.0f
if(mExtents.x < 0.0f) return FALSE;
if(mExtents.y < 0.0f) return FALSE;
if(mExtents.z < 0.0f) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb planes.
* \param planes [out] 6 box planes
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputePlanes(Plane* planes) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the obb points.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputePoints(Point* pts) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes vertex normals.
* \param pts [out] 8 box points
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ComputeVertexNormals(Point* pts) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns edges.
* \return 24 indices (12 edges) indexing the list returned by ComputePoints()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const udword* GetEdges() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns local edge normals.
* \return edge normals in local space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const Point* GetLocalEdgeNormals() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns world edge normal
* \param edge_index [in] 0 <= edge index < 12
* \param world_normal [out] edge normal in world space
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes an LSS surrounding the OBB.
* \param lss [out] the LSS
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ComputeLSS(LSS& lss) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the OBB is inside another OBB.
* \param box [in] the other OBB
* \return TRUE if we're inside the other box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsInside(const OBB& box) const;
inline_ const Point& GetCenter() const { return mCenter; }
inline_ const Point& GetExtents() const { return mExtents; }
inline_ const Matrix3x3& GetRot() const { return mRot; }
inline_ void GetRotatedExtents(Matrix3x3& extents) const
{
extents = mRot;
extents.Scale(mExtents);
}
Point mCenter; //!< B for Box
Point mExtents; //!< B for Bounding
Matrix3x3 mRot; //!< O for Oriented
// Orientation is stored in row-major format,
// i.e. rows = eigen vectors of the covariance matrix
};
#endif // __ICEOBB_H__

View File

@@ -1,61 +1,61 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple pair class.
* \file IcePairs.h
* \author Pierre Terdiman
* \date January, 13, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPAIRS_H__
#define __ICEPAIRS_H__
//! A generic couple structure
struct ICECORE_API Pair
{
inline_ Pair() {}
inline_ Pair(udword i0, udword i1) : id0(i0), id1(i1) {}
udword id0; //!< First index of the pair
udword id1; //!< Second index of the pair
};
class ICECORE_API Pairs : private Container
{
public:
// Constructor / Destructor
Pairs() {}
~Pairs() {}
inline_ udword GetNbPairs() const { return GetNbEntries()>>1; }
inline_ const Pair* GetPairs() const { return (const Pair*)GetEntries(); }
inline_ const Pair* GetPair(udword i) const { return (const Pair*)&GetEntries()[i+i]; }
inline_ BOOL HasPairs() const { return IsNotEmpty(); }
inline_ void ResetPairs() { Reset(); }
inline_ void DeleteLastPair() { DeleteLastEntry(); DeleteLastEntry(); }
inline_ void AddPair(const Pair& p) { Add(p.id0).Add(p.id1); }
inline_ void AddPair(udword id0, udword id1) { Add(id0).Add(id1); }
};
#endif // __ICEPAIRS_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple pair class.
* \file IcePairs.h
* \author Pierre Terdiman
* \date January, 13, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPAIRS_H__
#define __ICEPAIRS_H__
//! A generic couple structure
struct ICECORE_API Pair
{
inline_ Pair() {}
inline_ Pair(udword i0, udword i1) : id0(i0), id1(i1) {}
udword id0; //!< First index of the pair
udword id1; //!< Second index of the pair
};
class ICECORE_API Pairs : private Container
{
public:
// Constructor / Destructor
Pairs() {}
~Pairs() {}
inline_ udword GetNbPairs() const { return GetNbEntries()>>1; }
inline_ const Pair* GetPairs() const { return (const Pair*)GetEntries(); }
inline_ const Pair* GetPair(udword i) const { return (const Pair*)&GetEntries()[i+i]; }
inline_ BOOL HasPairs() const { return IsNotEmpty(); }
inline_ void ResetPairs() { Reset(); }
inline_ void DeleteLastPair() { DeleteLastEntry(); DeleteLastEntry(); }
inline_ void AddPair(const Pair& p) { Add(p.id0).Add(p.id1); }
inline_ void AddPair(udword id0, udword id1) { Add(id0).Add(id1); }
};
#endif // __ICEPAIRS_H__

View File

@@ -1,61 +1,61 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for planes.
* \file IcePlane.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Plane class.
* \class Plane
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the plane equation from 3 points.
* \param p0 [in] first point
* \param p1 [in] second point
* \param p2 [in] third point
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Plane& Plane::Set(const Point& p0, const Point& p1, const Point& p2)
{
Point Edge0 = p1 - p0;
Point Edge1 = p2 - p0;
n = Edge0 ^ Edge1;
n.Normalize();
d = -(p0 | n);
return *this;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for planes.
* \file IcePlane.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Plane class.
* \class Plane
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the plane equation from 3 points.
* \param p0 [in] first point
* \param p1 [in] second point
* \param p2 [in] third point
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Plane& Plane::Set(const Point& p0, const Point& p1, const Point& p2)
{
Point Edge0 = p1 - p0;
Point Edge1 = p2 - p0;
n = Edge0 ^ Edge1;
n.Normalize();
d = -(p0 | n);
return *this;
}

View File

@@ -1,129 +1,129 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for planes.
* \file IcePlane.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPLANE_H__
#define __ICEPLANE_H__
#define PLANE_EPSILON (1.0e-7f)
class ICEMATHS_API Plane
{
public:
//! Constructor
inline_ Plane() { }
//! Constructor from a normal and a distance
inline_ Plane(float nx, float ny, float nz, float d) { Set(nx, ny, nz, d); }
//! Constructor from a point on the plane and a normal
inline_ Plane(const Point& p, const Point& n) { Set(p, n); }
//! Constructor from three points
inline_ Plane(const Point& p0, const Point& p1, const Point& p2) { Set(p0, p1, p2); }
//! Constructor from a normal and a distance
inline_ Plane(const Point& _n, float _d) { n = _n; d = _d; }
//! Copy constructor
inline_ Plane(const Plane& plane) : n(plane.n), d(plane.d) { }
//! Destructor
inline_ ~Plane() { }
inline_ Plane& Zero() { n.Zero(); d = 0.0f; return *this; }
inline_ Plane& Set(float nx, float ny, float nz, float _d) { n.Set(nx, ny, nz); d = _d; return *this; }
inline_ Plane& Set(const Point& p, const Point& _n) { n = _n; d = - p | _n; return *this; }
Plane& Set(const Point& p0, const Point& p1, const Point& p2);
inline_ float Distance(const Point& p) const { return (p | n) + d; }
inline_ bool Belongs(const Point& p) const { return fabsf(Distance(p)) < PLANE_EPSILON; }
inline_ void Normalize()
{
float Denom = 1.0f / n.Magnitude();
n.x *= Denom;
n.y *= Denom;
n.z *= Denom;
d *= Denom;
}
public:
// Members
Point n; //!< The normal to the plane
float d; //!< The distance from the origin
// Cast operators
inline_ operator Point() const { return n; }
inline_ operator HPoint() const { return HPoint(n, d); }
// Arithmetic operators
inline_ Plane operator*(const Matrix4x4& m) const
{
// Old code from Irion. Kept for reference.
Plane Ret(*this);
return Ret *= m;
}
inline_ Plane& operator*=(const Matrix4x4& m)
{
// Old code from Irion. Kept for reference.
Point n2 = HPoint(n, 0.0f) * m;
d = -((Point) (HPoint( -d*n, 1.0f ) * m) | n2);
n = n2;
return *this;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster.
* \param transformed [out] transformed plane
* \param plane [in] source plane
* \param transform [in] transform matrix
* \warning the plane normal must be unit-length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void TransformPlane(Plane& transformed, const Plane& plane, const Matrix4x4& transform)
{
// Rotate the normal using the rotation part of the 4x4 matrix
transformed.n = plane.n * Matrix3x3(transform);
// Compute new d
transformed.d = plane.d - (Point(transform.GetTrans())|transformed.n);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster.
* \param plane [in/out] source plane (transformed on return)
* \param transform [in] transform matrix
* \warning the plane normal must be unit-length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void TransformPlane(Plane& plane, const Matrix4x4& transform)
{
// Rotate the normal using the rotation part of the 4x4 matrix
plane.n *= Matrix3x3(transform);
// Compute new d
plane.d -= Point(transform.GetTrans())|plane.n;
}
#endif // __ICEPLANE_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for planes.
* \file IcePlane.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPLANE_H__
#define __ICEPLANE_H__
#define PLANE_EPSILON (1.0e-7f)
class ICEMATHS_API Plane
{
public:
//! Constructor
inline_ Plane() { }
//! Constructor from a normal and a distance
inline_ Plane(float nx, float ny, float nz, float d) { Set(nx, ny, nz, d); }
//! Constructor from a point on the plane and a normal
inline_ Plane(const Point& p, const Point& n) { Set(p, n); }
//! Constructor from three points
inline_ Plane(const Point& p0, const Point& p1, const Point& p2) { Set(p0, p1, p2); }
//! Constructor from a normal and a distance
inline_ Plane(const Point& _n, float _d) { n = _n; d = _d; }
//! Copy constructor
inline_ Plane(const Plane& plane) : n(plane.n), d(plane.d) { }
//! Destructor
inline_ ~Plane() { }
inline_ Plane& Zero() { n.Zero(); d = 0.0f; return *this; }
inline_ Plane& Set(float nx, float ny, float nz, float _d) { n.Set(nx, ny, nz); d = _d; return *this; }
inline_ Plane& Set(const Point& p, const Point& _n) { n = _n; d = - p | _n; return *this; }
Plane& Set(const Point& p0, const Point& p1, const Point& p2);
inline_ float Distance(const Point& p) const { return (p | n) + d; }
inline_ bool Belongs(const Point& p) const { return fabsf(Distance(p)) < PLANE_EPSILON; }
inline_ void Normalize()
{
float Denom = 1.0f / n.Magnitude();
n.x *= Denom;
n.y *= Denom;
n.z *= Denom;
d *= Denom;
}
public:
// Members
Point n; //!< The normal to the plane
float d; //!< The distance from the origin
// Cast operators
inline_ operator Point() const { return n; }
inline_ operator HPoint() const { return HPoint(n, d); }
// Arithmetic operators
inline_ Plane operator*(const Matrix4x4& m) const
{
// Old code from Irion. Kept for reference.
Plane Ret(*this);
return Ret *= m;
}
inline_ Plane& operator*=(const Matrix4x4& m)
{
// Old code from Irion. Kept for reference.
Point n2 = HPoint(n, 0.0f) * m;
d = -((Point) (HPoint( -d*n, 1.0f ) * m) | n2);
n = n2;
return *this;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster.
* \param transformed [out] transformed plane
* \param plane [in] source plane
* \param transform [in] transform matrix
* \warning the plane normal must be unit-length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void TransformPlane(Plane& transformed, const Plane& plane, const Matrix4x4& transform)
{
// Rotate the normal using the rotation part of the 4x4 matrix
transformed.n = plane.n * Matrix3x3(transform);
// Compute new d
transformed.d = plane.d - (Point(transform.GetTrans())|transformed.n);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster.
* \param plane [in/out] source plane (transformed on return)
* \param transform [in] transform matrix
* \warning the plane normal must be unit-length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void TransformPlane(Plane& plane, const Matrix4x4& transform)
{
// Rotate the normal using the rotation part of the 4x4 matrix
plane.n *= Matrix3x3(transform);
// Compute new d
plane.d -= Point(transform.GetTrans())|plane.n;
}
#endif // __ICEPLANE_H__

View File

@@ -1,209 +1,209 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 3D vectors.
* \file IcePoint.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 3D point.
*
* The name is "Point" instead of "Vector" since a vector is N-dimensional, whereas a point is an implicit "vector of dimension 3".
* So the choice was between "Point" and "Vector3", the first one looked better (IMHO).
*
* Some people, then, use a typedef to handle both points & vectors using the same class: typedef Point Vector3;
* This is bad since it opens the door to a lot of confusion while reading the code. I know it may sounds weird but check this out:
*
* \code
* Point P0,P1 = some 3D points;
* Point Delta = P1 - P0;
* \endcode
*
* This compiles fine, although you should have written:
*
* \code
* Point P0,P1 = some 3D points;
* Vector3 Delta = P1 - P0;
* \endcode
*
* Subtle things like this are not caught at compile-time, and when you find one in the code, you never know whether it's a mistake
* from the author or something you don't get.
*
* One way to handle it at compile-time would be to use different classes for Point & Vector3, only overloading operator "-" for vectors.
* But then, you get a lot of redundant code in thoses classes, and basically it's really a lot of useless work.
*
* Another way would be to use homogeneous points: w=1 for points, w=0 for vectors. That's why the HPoint class exists. Now, to store
* your model's vertices and in most cases, you really want to use Points to save ram.
*
* \class Point
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates a positive unit random vector.
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point& Point::PositiveUnitRandomVector()
{
x = UnitRandomFloat();
y = UnitRandomFloat();
z = UnitRandomFloat();
Normalize();
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates a unit random vector.
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point& Point::UnitRandomVector()
{
x = UnitRandomFloat() - 0.5f;
y = UnitRandomFloat() - 0.5f;
z = UnitRandomFloat() - 0.5f;
Normalize();
return *this;
}
// Cast operator
// WARNING: not inlined
Point::operator HPoint() const { return HPoint(x, y, z, 0.0f); }
Point& Point::Refract(const Point& eye, const Point& n, float refractindex, Point& refracted)
{
// Point EyePt = eye position
// Point p = current vertex
// Point n = vertex normal
// Point rv = refracted vector
// Eye vector - doesn't need to be normalized
Point Env;
Env.x = eye.x - x;
Env.y = eye.y - y;
Env.z = eye.z - z;
float NDotE = n|Env;
float NDotN = n|n;
NDotE /= refractindex;
// Refracted vector
refracted = n*NDotE - Env*NDotN;
return *this;
}
Point& Point::ProjectToPlane(const Plane& p)
{
*this-= (p.d + (*this|p.n))*p.n;
return *this;
}
void Point::ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const
{
projected = HPoint(x, y, z, 1.0f) * mat;
projected.w = 1.0f / projected.w;
projected.x*=projected.w;
projected.y*=projected.w;
projected.z*=projected.w;
projected.x *= halfrenderwidth; projected.x += halfrenderwidth;
projected.y *= -halfrenderheight; projected.y += halfrenderheight;
}
void Point::SetNotUsed()
{
// We use a particular integer pattern : 0xffffffff everywhere. This is a NAN.
IR(x) = 0xffffffff;
IR(y) = 0xffffffff;
IR(z) = 0xffffffff;
}
BOOL Point::IsNotUsed() const
{
if(IR(x)!=0xffffffff) return FALSE;
if(IR(y)!=0xffffffff) return FALSE;
if(IR(z)!=0xffffffff) return FALSE;
return TRUE;
}
Point& Point::Mult(const Matrix3x3& mat, const Point& a)
{
x = a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2];
y = a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2];
z = a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2];
return *this;
}
Point& Point::Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2)
{
x = a1.x * mat1.m[0][0] + a1.y * mat1.m[0][1] + a1.z * mat1.m[0][2] + a2.x * mat2.m[0][0] + a2.y * mat2.m[0][1] + a2.z * mat2.m[0][2];
y = a1.x * mat1.m[1][0] + a1.y * mat1.m[1][1] + a1.z * mat1.m[1][2] + a2.x * mat2.m[1][0] + a2.y * mat2.m[1][1] + a2.z * mat2.m[1][2];
z = a1.x * mat1.m[2][0] + a1.y * mat1.m[2][1] + a1.z * mat1.m[2][2] + a2.x * mat2.m[2][0] + a2.y * mat2.m[2][1] + a2.z * mat2.m[2][2];
return *this;
}
Point& Point::Mac(const Matrix3x3& mat, const Point& a)
{
x += a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2];
y += a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2];
z += a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2];
return *this;
}
Point& Point::TransMult(const Matrix3x3& mat, const Point& a)
{
x = a.x * mat.m[0][0] + a.y * mat.m[1][0] + a.z * mat.m[2][0];
y = a.x * mat.m[0][1] + a.y * mat.m[1][1] + a.z * mat.m[2][1];
z = a.x * mat.m[0][2] + a.y * mat.m[1][2] + a.z * mat.m[2][2];
return *this;
}
Point& Point::Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos)
{
x = r.x * rotpos.m[0][0] + r.y * rotpos.m[0][1] + r.z * rotpos.m[0][2] + linpos.x;
y = r.x * rotpos.m[1][0] + r.y * rotpos.m[1][1] + r.z * rotpos.m[1][2] + linpos.y;
z = r.x * rotpos.m[2][0] + r.y * rotpos.m[2][1] + r.z * rotpos.m[2][2] + linpos.z;
return *this;
}
Point& Point::InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos)
{
float sx = r.x - linpos.x;
float sy = r.y - linpos.y;
float sz = r.z - linpos.z;
x = sx * rotpos.m[0][0] + sy * rotpos.m[1][0] + sz * rotpos.m[2][0];
y = sx * rotpos.m[0][1] + sy * rotpos.m[1][1] + sz * rotpos.m[2][1];
z = sx * rotpos.m[0][2] + sy * rotpos.m[1][2] + sz * rotpos.m[2][2];
return *this;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for 3D vectors.
* \file IcePoint.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 3D point.
*
* The name is "Point" instead of "Vector" since a vector is N-dimensional, whereas a point is an implicit "vector of dimension 3".
* So the choice was between "Point" and "Vector3", the first one looked better (IMHO).
*
* Some people, then, use a typedef to handle both points & vectors using the same class: typedef Point Vector3;
* This is bad since it opens the door to a lot of confusion while reading the code. I know it may sounds weird but check this out:
*
* \code
* Point P0,P1 = some 3D points;
* Point Delta = P1 - P0;
* \endcode
*
* This compiles fine, although you should have written:
*
* \code
* Point P0,P1 = some 3D points;
* Vector3 Delta = P1 - P0;
* \endcode
*
* Subtle things like this are not caught at compile-time, and when you find one in the code, you never know whether it's a mistake
* from the author or something you don't get.
*
* One way to handle it at compile-time would be to use different classes for Point & Vector3, only overloading operator "-" for vectors.
* But then, you get a lot of redundant code in thoses classes, and basically it's really a lot of useless work.
*
* Another way would be to use homogeneous points: w=1 for points, w=0 for vectors. That's why the HPoint class exists. Now, to store
* your model's vertices and in most cases, you really want to use Points to save ram.
*
* \class Point
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates a positive unit random vector.
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point& Point::PositiveUnitRandomVector()
{
x = UnitRandomFloat();
y = UnitRandomFloat();
z = UnitRandomFloat();
Normalize();
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates a unit random vector.
* \return Self-reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Point& Point::UnitRandomVector()
{
x = UnitRandomFloat() - 0.5f;
y = UnitRandomFloat() - 0.5f;
z = UnitRandomFloat() - 0.5f;
Normalize();
return *this;
}
// Cast operator
// WARNING: not inlined
Point::operator HPoint() const { return HPoint(x, y, z, 0.0f); }
Point& Point::Refract(const Point& eye, const Point& n, float refractindex, Point& refracted)
{
// Point EyePt = eye position
// Point p = current vertex
// Point n = vertex normal
// Point rv = refracted vector
// Eye vector - doesn't need to be normalized
Point Env;
Env.x = eye.x - x;
Env.y = eye.y - y;
Env.z = eye.z - z;
float NDotE = n|Env;
float NDotN = n|n;
NDotE /= refractindex;
// Refracted vector
refracted = n*NDotE - Env*NDotN;
return *this;
}
Point& Point::ProjectToPlane(const Plane& p)
{
*this-= (p.d + (*this|p.n))*p.n;
return *this;
}
void Point::ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const
{
projected = HPoint(x, y, z, 1.0f) * mat;
projected.w = 1.0f / projected.w;
projected.x*=projected.w;
projected.y*=projected.w;
projected.z*=projected.w;
projected.x *= halfrenderwidth; projected.x += halfrenderwidth;
projected.y *= -halfrenderheight; projected.y += halfrenderheight;
}
void Point::SetNotUsed()
{
// We use a particular integer pattern : 0xffffffff everywhere. This is a NAN.
IR(x) = 0xffffffff;
IR(y) = 0xffffffff;
IR(z) = 0xffffffff;
}
BOOL Point::IsNotUsed() const
{
if(IR(x)!=0xffffffff) return FALSE;
if(IR(y)!=0xffffffff) return FALSE;
if(IR(z)!=0xffffffff) return FALSE;
return TRUE;
}
Point& Point::Mult(const Matrix3x3& mat, const Point& a)
{
x = a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2];
y = a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2];
z = a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2];
return *this;
}
Point& Point::Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2)
{
x = a1.x * mat1.m[0][0] + a1.y * mat1.m[0][1] + a1.z * mat1.m[0][2] + a2.x * mat2.m[0][0] + a2.y * mat2.m[0][1] + a2.z * mat2.m[0][2];
y = a1.x * mat1.m[1][0] + a1.y * mat1.m[1][1] + a1.z * mat1.m[1][2] + a2.x * mat2.m[1][0] + a2.y * mat2.m[1][1] + a2.z * mat2.m[1][2];
z = a1.x * mat1.m[2][0] + a1.y * mat1.m[2][1] + a1.z * mat1.m[2][2] + a2.x * mat2.m[2][0] + a2.y * mat2.m[2][1] + a2.z * mat2.m[2][2];
return *this;
}
Point& Point::Mac(const Matrix3x3& mat, const Point& a)
{
x += a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2];
y += a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2];
z += a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2];
return *this;
}
Point& Point::TransMult(const Matrix3x3& mat, const Point& a)
{
x = a.x * mat.m[0][0] + a.y * mat.m[1][0] + a.z * mat.m[2][0];
y = a.x * mat.m[0][1] + a.y * mat.m[1][1] + a.z * mat.m[2][1];
z = a.x * mat.m[0][2] + a.y * mat.m[1][2] + a.z * mat.m[2][2];
return *this;
}
Point& Point::Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos)
{
x = r.x * rotpos.m[0][0] + r.y * rotpos.m[0][1] + r.z * rotpos.m[0][2] + linpos.x;
y = r.x * rotpos.m[1][0] + r.y * rotpos.m[1][1] + r.z * rotpos.m[1][2] + linpos.y;
z = r.x * rotpos.m[2][0] + r.y * rotpos.m[2][1] + r.z * rotpos.m[2][2] + linpos.z;
return *this;
}
Point& Point::InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos)
{
float sx = r.x - linpos.x;
float sy = r.y - linpos.y;
float sz = r.z - linpos.z;
x = sx * rotpos.m[0][0] + sy * rotpos.m[1][0] + sz * rotpos.m[2][0];
y = sx * rotpos.m[0][1] + sy * rotpos.m[1][1] + sz * rotpos.m[2][1];
z = sx * rotpos.m[0][2] + sy * rotpos.m[1][2] + sz * rotpos.m[2][2];
return *this;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,158 +1,158 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains preprocessor stuff. This should be the first included header.
* \file IcePreprocessor.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEPREPROCESSOR_H
#define ICEPREPROCESSOR_H
// Check platform
#if defined( _WIN32 ) || defined( WIN32 )
#pragma message("Compiling on Windows...")
#define PLATFORM_WINDOWS
#else
#pragma message("Compiling on unknown platform...")
#endif
// Check compiler
#if defined(_MSC_VER)
#pragma message("Compiling with VC++...")
#define COMPILER_VISUAL_CPP
#if _MSC_VER > 1300
#pragma message("Compiling with VC7")
#define COMPILER_VC7
#else
#pragma message("Compiling with VC6")
#define COMPILER_VC6
#endif
#else
#pragma message("Compiling with unknown compiler...")
#endif
// Check compiler options. If this file is included in user-apps, this
// shouldn't be needed, so that they can use what they like best.
#ifndef ICE_DONT_CHECK_COMPILER_OPTIONS
#ifdef COMPILER_VISUAL_CPP
#if defined(_CHAR_UNSIGNED)
#endif
#if defined(_CPPRTTI)
#error Please disable RTTI...
#endif
#if defined(_CPPUNWIND)
#error Please disable exceptions...
#endif
#if defined(_MT)
// Multithreading
#endif
#endif
#endif
// Check debug mode
#ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it.
#ifndef _DEBUG
#define _DEBUG
#endif
#endif
#ifdef _DEBUG
// Here you may define items for debug builds
#endif
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
#ifndef ICE_NO_DLL
#ifdef ICECORE_EXPORTS
#define ICECORE_API __declspec(dllexport)
#else
#define ICECORE_API __declspec(dllimport)
#endif
#else
#define ICECORE_API
#endif
#define FUNCTION extern "C"
// Cosmetic stuff [mainly useful with multiple inheritance]
#define override(base_class) virtual
// Our own inline keyword, so that:
// - we can switch to __forceinline to check it's really better or not
// - we can remove __forceinline if the compiler doesn't support it
// #define inline_ __forceinline
// #define inline_ inline
// Contributed by Bruce Mitchener
#if defined(COMPILER_VISUAL_CPP)
#define inline_ __forceinline
// #define inline_ inline
#elif defined(__GNUC__) && __GNUC__ < 3
#define inline_ inline
#elif defined(__GNUC__)
#define inline_ inline __attribute__ ((always_inline))
#else
#define inline_ inline
#endif
// Down the hatch
#pragma inline_depth( 255 )
#ifdef COMPILER_VISUAL_CPP
#pragma intrinsic(memcmp)
#pragma intrinsic(memcpy)
#pragma intrinsic(memset)
#pragma intrinsic(strcat)
#pragma intrinsic(strcmp)
#pragma intrinsic(strcpy)
#pragma intrinsic(strlen)
#pragma intrinsic(abs)
#pragma intrinsic(labs)
#endif
// ANSI compliance
#ifdef _DEBUG
// Remove painful warning in debug
inline_ bool ReturnsFalse(){ return false; }
#define for if(ReturnsFalse()){} else for
#else
#define for if(0){} else for
#endif
// Don't override new/delete
#define DEFAULT_NEWDELETE
#define DONT_TRACK_MEMORY_LEAKS
//! Macro used to give me a clue when it crashes in release and only the assembly is available
#define INCLUDE_GUARDIANS
#ifdef INCLUDE_GUARDIANS
#define GUARD(x) \
{ \
static const char guard_text[] = x; \
_asm push eax \
_asm nop \
_asm nop \
_asm nop \
_asm nop \
_asm lea eax, guard_text \
_asm nop \
_asm nop \
_asm nop \
_asm nop \
_asm pop eax \
}
#else
#define GUARD(x)
#endif
#endif // ICEPREPROCESSOR_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains preprocessor stuff. This should be the first included header.
* \file IcePreprocessor.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEPREPROCESSOR_H
#define ICEPREPROCESSOR_H
// Check platform
#if defined( _WIN32 ) || defined( WIN32 )
#pragma message("Compiling on Windows...")
#define PLATFORM_WINDOWS
#else
#pragma message("Compiling on unknown platform...")
#endif
// Check compiler
#if defined(_MSC_VER)
#pragma message("Compiling with VC++...")
#define COMPILER_VISUAL_CPP
#if _MSC_VER > 1300
#pragma message("Compiling with VC7")
#define COMPILER_VC7
#else
#pragma message("Compiling with VC6")
#define COMPILER_VC6
#endif
#else
#pragma message("Compiling with unknown compiler...")
#endif
// Check compiler options. If this file is included in user-apps, this
// shouldn't be needed, so that they can use what they like best.
#ifndef ICE_DONT_CHECK_COMPILER_OPTIONS
#ifdef COMPILER_VISUAL_CPP
#if defined(_CHAR_UNSIGNED)
#endif
#if defined(_CPPRTTI)
#error Please disable RTTI...
#endif
#if defined(_CPPUNWIND)
#error Please disable exceptions...
#endif
#if defined(_MT)
// Multithreading
#endif
#endif
#endif
// Check debug mode
#ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it.
#ifndef _DEBUG
#define _DEBUG
#endif
#endif
#ifdef _DEBUG
// Here you may define items for debug builds
#endif
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
#ifndef ICE_NO_DLL
#ifdef ICECORE_EXPORTS
#define ICECORE_API __declspec(dllexport)
#else
#define ICECORE_API __declspec(dllimport)
#endif
#else
#define ICECORE_API
#endif
#define FUNCTION extern "C"
// Cosmetic stuff [mainly useful with multiple inheritance]
#define override(base_class) virtual
// Our own inline keyword, so that:
// - we can switch to __forceinline to check it's really better or not
// - we can remove __forceinline if the compiler doesn't support it
// #define inline_ __forceinline
// #define inline_ inline
// Contributed by Bruce Mitchener
#if defined(COMPILER_VISUAL_CPP)
#define inline_ __forceinline
// #define inline_ inline
#elif defined(__GNUC__) && __GNUC__ < 3
#define inline_ inline
#elif defined(__GNUC__)
#define inline_ inline __attribute__ ((always_inline))
#else
#define inline_ inline
#endif
// Down the hatch
#pragma inline_depth( 255 )
#ifdef COMPILER_VISUAL_CPP
#pragma intrinsic(memcmp)
#pragma intrinsic(memcpy)
#pragma intrinsic(memset)
#pragma intrinsic(strcat)
#pragma intrinsic(strcmp)
#pragma intrinsic(strcpy)
#pragma intrinsic(strlen)
#pragma intrinsic(abs)
#pragma intrinsic(labs)
#endif
// ANSI compliance
#ifdef _DEBUG
// Remove painful warning in debug
inline_ bool ReturnsFalse(){ return false; }
#define for if(ReturnsFalse()){} else for
#else
#define for if(0){} else for
#endif
// Don't override new/delete
#define DEFAULT_NEWDELETE
#define DONT_TRACK_MEMORY_LEAKS
//! Macro used to give me a clue when it crashes in release and only the assembly is available
#define INCLUDE_GUARDIANS
#ifdef INCLUDE_GUARDIANS
#define GUARD(x) \
{ \
static const char guard_text[] = x; \
_asm push eax \
_asm nop \
_asm nop \
_asm nop \
_asm nop \
_asm lea eax, guard_text \
_asm nop \
_asm nop \
_asm nop \
_asm nop \
_asm pop eax \
}
#else
#define GUARD(x)
#endif
#endif // ICEPREPROCESSOR_H

View File

@@ -1,52 +1,52 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for random generators.
* \file IceRandom.cpp
* \author Pierre Terdiman
* \date August, 9, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
void IceCore:: SRand(udword seed)
{
srand(seed);
}
udword IceCore::Rand()
{
return rand();
}
static BasicRandom gRandomGenerator(42);
udword IceCore::GetRandomIndex(udword max_index)
{
// We don't use rand() since it's limited to RAND_MAX
udword Index = gRandomGenerator.Randomize();
return Index % max_index;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for random generators.
* \file IceRandom.cpp
* \author Pierre Terdiman
* \date August, 9, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
void IceCore:: SRand(udword seed)
{
srand(seed);
}
udword IceCore::Rand()
{
return rand();
}
static BasicRandom gRandomGenerator(42);
udword IceCore::GetRandomIndex(udword max_index)
{
// We don't use rand() since it's limited to RAND_MAX
udword Index = gRandomGenerator.Randomize();
return Index % max_index;
}

View File

@@ -1,58 +1,58 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for random generators.
* \file IceRandom.h
* \author Pierre Terdiman
* \date August, 9, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERANDOM_H__
#define __ICERANDOM_H__
FUNCTION ICECORE_API void SRand(udword seed);
FUNCTION ICECORE_API udword Rand();
//! Returns a unit random floating-point value
inline_ float UnitRandomFloat() { return float(Rand()) * ONE_OVER_RAND_MAX; }
//! Returns a random index so that 0<= index < max_index
ICECORE_API udword GetRandomIndex(udword max_index);
class ICECORE_API BasicRandom
{
public:
//! Constructor
inline_ BasicRandom(udword seed=0) : mRnd(seed) {}
//! Destructor
inline_ ~BasicRandom() {}
inline_ void SetSeed(udword seed) { mRnd = seed; }
inline_ udword GetCurrentValue() const { return mRnd; }
inline_ udword Randomize() { mRnd = mRnd * 2147001325 + 715136305; return mRnd; }
private:
udword mRnd;
};
#endif // __ICERANDOM_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for random generators.
* \file IceRandom.h
* \author Pierre Terdiman
* \date August, 9, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERANDOM_H__
#define __ICERANDOM_H__
FUNCTION ICECORE_API void SRand(udword seed);
FUNCTION ICECORE_API udword Rand();
//! Returns a unit random floating-point value
inline_ float UnitRandomFloat() { return float(Rand()) * ONE_OVER_RAND_MAX; }
//! Returns a random index so that 0<= index < max_index
ICECORE_API udword GetRandomIndex(udword max_index);
class ICECORE_API BasicRandom
{
public:
//! Constructor
inline_ BasicRandom(udword seed=0) : mRnd(seed) {}
//! Destructor
inline_ ~BasicRandom() {}
inline_ void SetSeed(udword seed) { mRnd = seed; }
inline_ udword GetCurrentValue() const { return mRnd; }
inline_ udword Randomize() { mRnd = mRnd * 2147001325 + 715136305; return mRnd; }
private:
udword mRnd;
};
#endif // __ICERANDOM_H__

View File

@@ -1,100 +1,100 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for rays.
* \file IceRay.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Ray class.
* A ray is a half-line P(t) = mOrig + mDir * t, with 0 <= t <= +infinity
* \class Ray
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
O = Origin = impact point
i = normalized vector along the x axis
j = normalized vector along the y axis = actually the normal vector in O
D = Direction vector, norm |D| = 1
N = Projection of D on y axis, norm |N| = normal reaction
T = Projection of D on x axis, norm |T| = tangential reaction
R = Reflexion vector
^y
|
|
|
_ _ _| _ _ _
* * *|
\ | /
\ |N / |
R\ | /D
\ | / |
\ | /
_________\|/______*_______>x
O T
Let define theta = angle between D and N. Then cos(theta) = |N| / |D| = |N| since D is normalized.
j|D = |j|*|D|*cos(theta) => |N| = j|D
Then we simply have:
D = N + T
To compute tangential reaction :
T = D - N
To compute reflexion vector :
R = N - T = N - (D-N) = 2*N - D
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
float Ray::SquareDistance(const Point& point, float* t) const
{
Point Diff = point - mOrig;
float fT = Diff | mDir;
if(fT<=0.0f)
{
fT = 0.0f;
}
else
{
fT /= mDir.SquareMagnitude();
Diff -= fT*mDir;
}
if(t) *t = fT;
return Diff.SquareMagnitude();
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for rays.
* \file IceRay.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Ray class.
* A ray is a half-line P(t) = mOrig + mDir * t, with 0 <= t <= +infinity
* \class Ray
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
O = Origin = impact point
i = normalized vector along the x axis
j = normalized vector along the y axis = actually the normal vector in O
D = Direction vector, norm |D| = 1
N = Projection of D on y axis, norm |N| = normal reaction
T = Projection of D on x axis, norm |T| = tangential reaction
R = Reflexion vector
^y
|
|
|
_ _ _| _ _ _
* * *|
\ | /
\ |N / |
R\ | /D
\ | / |
\ | /
_________\|/______*_______>x
O T
Let define theta = angle between D and N. Then cos(theta) = |N| / |D| = |N| since D is normalized.
j|D = |j|*|D|*cos(theta) => |N| = j|D
Then we simply have:
D = N + T
To compute tangential reaction :
T = D - N
To compute reflexion vector :
R = N - T = N - (D-N) = 2*N - D
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
float Ray::SquareDistance(const Point& point, float* t) const
{
Point Diff = point - mOrig;
float fT = Diff | mDir;
if(fT<=0.0f)
{
fT = 0.0f;
}
else
{
fT /= mDir.SquareMagnitude();
Diff -= fT*mDir;
}
if(t) *t = fT;
return Diff.SquareMagnitude();
}

View File

@@ -1,114 +1,114 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for rays.
* \file IceRay.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERAY_H__
#define __ICERAY_H__
class ICEMATHS_API Ray
{
public:
//! Constructor
inline_ Ray() {}
//! Constructor
inline_ Ray(const Point& orig, const Point& dir) : mOrig(orig), mDir(dir) {}
//! Copy constructor
inline_ Ray(const Ray& ray) : mOrig(ray.mOrig), mDir(ray.mDir) {}
//! Destructor
inline_ ~Ray() {}
float SquareDistance(const Point& point, float* t=null) const;
inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); }
Point mOrig; //!< Ray origin
Point mDir; //!< Normalized direction
};
inline_ void ComputeReflexionVector(Point& reflected, const Point& incoming_dir, const Point& outward_normal)
{
reflected = incoming_dir - outward_normal * 2.0f * (incoming_dir|outward_normal);
}
inline_ void ComputeReflexionVector(Point& reflected, const Point& source, const Point& impact, const Point& normal)
{
Point V = impact - source;
reflected = V - normal * 2.0f * (V|normal);
}
inline_ void DecomposeVector(Point& normal_compo, Point& tangent_compo, const Point& outward_dir, const Point& outward_normal)
{
normal_compo = outward_normal * (outward_dir|outward_normal);
tangent_compo = outward_dir - normal_compo;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a direction vector from world space to local space
* \param local_dir [out] direction vector in local space
* \param world_dir [in] direction vector in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalDirection(Point& local_dir, const Point& world_dir, const Matrix4x4& world)
{
// Get world direction back in local space
// Matrix3x3 InvWorld = world;
// local_dir = InvWorld * world_dir;
local_dir = Matrix3x3(world) * world_dir;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a position vector from world space to local space
* \param local_pt [out] position vector in local space
* \param world_pt [in] position vector in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalPoint(Point& local_pt, const Point& world_pt, const Matrix4x4& world)
{
// Get world vertex back in local space
Matrix4x4 InvWorld = world;
InvWorld.Invert();
local_pt = world_pt * InvWorld;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a ray from world space to local space
* \param local_ray [out] ray in local space
* \param world_ray [in] ray in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalRay(Ray& local_ray, const Ray& world_ray, const Matrix4x4& world)
{
// Get world ray back in local space
ComputeLocalDirection(local_ray.mDir, world_ray.mDir, world);
ComputeLocalPoint(local_ray.mOrig, world_ray.mOrig, world);
}
#endif // __ICERAY_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for rays.
* \file IceRay.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERAY_H__
#define __ICERAY_H__
class ICEMATHS_API Ray
{
public:
//! Constructor
inline_ Ray() {}
//! Constructor
inline_ Ray(const Point& orig, const Point& dir) : mOrig(orig), mDir(dir) {}
//! Copy constructor
inline_ Ray(const Ray& ray) : mOrig(ray.mOrig), mDir(ray.mDir) {}
//! Destructor
inline_ ~Ray() {}
float SquareDistance(const Point& point, float* t=null) const;
inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); }
Point mOrig; //!< Ray origin
Point mDir; //!< Normalized direction
};
inline_ void ComputeReflexionVector(Point& reflected, const Point& incoming_dir, const Point& outward_normal)
{
reflected = incoming_dir - outward_normal * 2.0f * (incoming_dir|outward_normal);
}
inline_ void ComputeReflexionVector(Point& reflected, const Point& source, const Point& impact, const Point& normal)
{
Point V = impact - source;
reflected = V - normal * 2.0f * (V|normal);
}
inline_ void DecomposeVector(Point& normal_compo, Point& tangent_compo, const Point& outward_dir, const Point& outward_normal)
{
normal_compo = outward_normal * (outward_dir|outward_normal);
tangent_compo = outward_dir - normal_compo;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a direction vector from world space to local space
* \param local_dir [out] direction vector in local space
* \param world_dir [in] direction vector in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalDirection(Point& local_dir, const Point& world_dir, const Matrix4x4& world)
{
// Get world direction back in local space
// Matrix3x3 InvWorld = world;
// local_dir = InvWorld * world_dir;
local_dir = Matrix3x3(world) * world_dir;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a position vector from world space to local space
* \param local_pt [out] position vector in local space
* \param world_pt [in] position vector in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalPoint(Point& local_pt, const Point& world_pt, const Matrix4x4& world)
{
// Get world vertex back in local space
Matrix4x4 InvWorld = world;
InvWorld.Invert();
local_pt = world_pt * InvWorld;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Transforms a ray from world space to local space
* \param local_ray [out] ray in local space
* \param world_ray [in] ray in world space
* \param world [in] world transform
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputeLocalRay(Ray& local_ray, const Ray& world_ray, const Matrix4x4& world)
{
// Get world ray back in local space
ComputeLocalDirection(local_ray.mDir, world_ray.mDir, world);
ComputeLocalPoint(local_ray.mOrig, world_ray.mOrig, world);
}
#endif // __ICERAY_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +1,74 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains source code from the article "Radix Sort Revisited".
* \file IceRevisitedRadix.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICERADIXSORT_H
#define ICERADIXSORT_H
//! Allocate histograms & offsets locally
#define RADIX_LOCAL_RAM
enum RadixHint
{
RADIX_SIGNED, //!< Input values are signed
RADIX_UNSIGNED, //!< Input values are unsigned
RADIX_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API RadixSort : public Allocateable
{
public:
// Constructor/Destructor
RadixSort();
~RadixSort();
// Sorting methods
RadixSort& Sort(const udword* input, udword nb, RadixHint hint=RADIX_SIGNED);
RadixSort& Sort(const float* input, udword nb);
//! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
inline_ const udword* GetRanks() const { return mRanks; }
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
inline_ udword* GetRecyclable() const { return mRanks2; }
// Stats
udword GetUsedRam() const;
//! Returns the total number of calls to the radix sorter.
inline_ udword GetNbTotalCalls() const { return mTotalCalls; }
//! Returns the number of eraly exits due to temporal coherence.
inline_ udword GetNbHits() const { return mNbHits; }
bool SetRankBuffers(udword* ranks0, udword* ranks1);
PREVENT_COPY(RadixSort)
private:
#ifndef RADIX_LOCAL_RAM
udword* mHistogram; //!< Counters for each byte
udword* mOffset; //!< Offsets (nearly a cumulative distribution function)
#endif
udword mCurrentSize; //!< Current size of the indices list
udword* mRanks; //!< Two lists, swapped each pass
udword* mRanks2;
// Stats
udword mTotalCalls; //!< Total number of calls to the sort routine
udword mNbHits; //!< Number of early exits due to coherence
// Stack-radix
bool mDeleteRanks; //!<
// Internal methods
void CheckResize(udword nb);
bool Resize(udword nb);
};
#define StackRadixSort(name, ranks0, ranks1) \
RadixSort name; \
name.SetRankBuffers(ranks0, ranks1);
#endif // ICERADIXSORT_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains source code from the article "Radix Sort Revisited".
* \file IceRevisitedRadix.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICERADIXSORT_H
#define ICERADIXSORT_H
//! Allocate histograms & offsets locally
#define RADIX_LOCAL_RAM
enum RadixHint
{
RADIX_SIGNED, //!< Input values are signed
RADIX_UNSIGNED, //!< Input values are unsigned
RADIX_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API RadixSort : public Allocateable
{
public:
// Constructor/Destructor
RadixSort();
~RadixSort();
// Sorting methods
RadixSort& Sort(const udword* input, udword nb, RadixHint hint=RADIX_SIGNED);
RadixSort& Sort(const float* input, udword nb);
//! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
inline_ const udword* GetRanks() const { return mRanks; }
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
inline_ udword* GetRecyclable() const { return mRanks2; }
// Stats
udword GetUsedRam() const;
//! Returns the total number of calls to the radix sorter.
inline_ udword GetNbTotalCalls() const { return mTotalCalls; }
//! Returns the number of eraly exits due to temporal coherence.
inline_ udword GetNbHits() const { return mNbHits; }
bool SetRankBuffers(udword* ranks0, udword* ranks1);
PREVENT_COPY(RadixSort)
private:
#ifndef RADIX_LOCAL_RAM
udword* mHistogram; //!< Counters for each byte
udword* mOffset; //!< Offsets (nearly a cumulative distribution function)
#endif
udword mCurrentSize; //!< Current size of the indices list
udword* mRanks; //!< Two lists, swapped each pass
udword* mRanks2;
// Stats
udword mTotalCalls; //!< Total number of calls to the sort routine
udword mNbHits; //!< Number of early exits due to coherence
// Stack-radix
bool mDeleteRanks; //!<
// Internal methods
void CheckResize(udword nb);
bool Resize(udword nb);
};
#define StackRadixSort(name, ranks0, ranks1) \
RadixSort name; \
name.SetRankBuffers(ranks0, ranks1);
#endif // ICERADIXSORT_H

View File

@@ -1,73 +1,73 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for segments.
* \file IceSegment.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Segment class.
* A segment is defined by S(t) = mP0 * (1 - t) + mP1 * t, with 0 <= t <= 1
* Alternatively, a segment is S(t) = Origin + t * Direction for 0 <= t <= 1.
* Direction is not necessarily unit length. The end points are Origin = mP0 and Origin + Direction = mP1.
*
* \class Segment
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
float Segment::SquareDistance(const Point& point, float* t) const
{
Point Diff = point - mP0;
Point Dir = mP1 - mP0;
float fT = Diff | Dir;
if(fT<=0.0f)
{
fT = 0.0f;
}
else
{
float SqrLen= Dir.SquareMagnitude();
if(fT>=SqrLen)
{
fT = 1.0f;
Diff -= Dir;
}
else
{
fT /= SqrLen;
Diff -= fT*Dir;
}
}
if(t) *t = fT;
return Diff.SquareMagnitude();
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for segments.
* \file IceSegment.cpp
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Segment class.
* A segment is defined by S(t) = mP0 * (1 - t) + mP1 * t, with 0 <= t <= 1
* Alternatively, a segment is S(t) = Origin + t * Direction for 0 <= t <= 1.
* Direction is not necessarily unit length. The end points are Origin = mP0 and Origin + Direction = mP1.
*
* \class Segment
* \author Pierre Terdiman
* \version 1.0
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
float Segment::SquareDistance(const Point& point, float* t) const
{
Point Diff = point - mP0;
Point Dir = mP1 - mP0;
float fT = Diff | Dir;
if(fT<=0.0f)
{
fT = 0.0f;
}
else
{
float SqrLen= Dir.SquareMagnitude();
if(fT>=SqrLen)
{
fT = 1.0f;
Diff -= Dir;
}
else
{
fT /= SqrLen;
Diff -= fT*Dir;
}
}
if(t) *t = fT;
return Diff.SquareMagnitude();
}

View File

@@ -1,71 +1,71 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for segments.
* \file IceSegment.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICESEGMENT_H__
#define __ICESEGMENT_H__
class ICEMATHS_API Segment
{
public:
//! Constructor
inline_ Segment() {}
//! Constructor
inline_ Segment(const Point& p0, const Point& p1) : mP0(p0), mP1(p1) {}
//! Copy constructor
inline_ Segment(const Segment& seg) : mP0(seg.mP0), mP1(seg.mP1) {}
//! Destructor
inline_ ~Segment() {}
inline_ const Point& GetOrigin() const { return mP0; }
inline_ Point ComputeDirection() const { return mP1 - mP0; }
inline_ void ComputeDirection(Point& dir) const { dir = mP1 - mP0; }
inline_ float ComputeLength() const { return mP1.Distance(mP0); }
inline_ float ComputeSquareLength() const { return mP1.SquareDistance(mP0); }
inline_ void SetOriginDirection(const Point& origin, const Point& direction)
{
mP0 = mP1 = origin;
mP1 += direction;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a point on the segment
* \param pt [out] point on segment
* \param t [in] point's parameter [t=0 => pt = mP0, t=1 => pt = mP1]
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputePoint(Point& pt, float t) const { pt = mP0 + t * (mP1 - mP0); }
float SquareDistance(const Point& point, float* t=null) const;
inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); }
Point mP0; //!< Start of segment
Point mP1; //!< End of segment
};
#endif // __ICESEGMENT_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for segments.
* \file IceSegment.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICESEGMENT_H__
#define __ICESEGMENT_H__
class ICEMATHS_API Segment
{
public:
//! Constructor
inline_ Segment() {}
//! Constructor
inline_ Segment(const Point& p0, const Point& p1) : mP0(p0), mP1(p1) {}
//! Copy constructor
inline_ Segment(const Segment& seg) : mP0(seg.mP0), mP1(seg.mP1) {}
//! Destructor
inline_ ~Segment() {}
inline_ const Point& GetOrigin() const { return mP0; }
inline_ Point ComputeDirection() const { return mP1 - mP0; }
inline_ void ComputeDirection(Point& dir) const { dir = mP1 - mP0; }
inline_ float ComputeLength() const { return mP1.Distance(mP0); }
inline_ float ComputeSquareLength() const { return mP1.SquareDistance(mP0); }
inline_ void SetOriginDirection(const Point& origin, const Point& direction)
{
mP0 = mP1 = origin;
mP1 += direction;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a point on the segment
* \param pt [out] point on segment
* \param t [in] point's parameter [t=0 => pt = mP0, t=1 => pt = mP1]
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void ComputePoint(Point& pt, float t) const { pt = mP0 + t * (mP1 - mP0); }
float SquareDistance(const Point& point, float* t=null) const;
inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); }
Point mP0; //!< Start of segment
Point mP1; //!< End of segment
};
#endif // __ICESEGMENT_H__

View File

@@ -1,302 +1,302 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy triangle class.
* \file IceTriangle.cpp
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a triangle class.
*
* \class Tri
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon)
{
// Compute distance from current vertex to the plane
float Dist = plane.Distance(v);
// Compute side:
// 1 = the vertex is on the positive side of the plane
// -1 = the vertex is on the negative side of the plane
// 0 = the vertex is on the plane (within epsilon)
return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Flips the winding order.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Flip()
{
Point Tmp = mVerts[1];
mVerts[1] = mVerts[2];
mVerts[2] = Tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle area.
* \return the area
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Area() const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle perimeter.
* \return the perimeter
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Perimeter() const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
return p0.Distance(p1)
+ p0.Distance(p2)
+ p1.Distance(p2);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle compacity.
* \return the compacity
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Compacity() const
{
float P = Perimeter();
if(P==0.0f) return 0.0f;
return (4.0f*PI*Area()/(P*P));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle normal.
* \param normal [out] the computed normal
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Normal(Point& normal) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
normal = ((p0 - p1)^(p0 - p2)).Normalize();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle denormalized normal.
* \param normal [out] the computed normal
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::DenormalizedNormal(Point& normal) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
normal = ((p0 - p1)^(p0 - p2));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle center.
* \param center [out] the computed center
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Center(Point& center) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
center = (p0 + p1 + p2)*INV3;
}
PartVal Triangle::TestAgainstPlane(const Plane& plane, float epsilon) const
{
bool Pos = false, Neg = false;
// Loop through all vertices
for(udword i=0;i<3;i++)
{
// Compute side:
sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon);
if (Side < 0) Neg = true;
else if (Side > 0) Pos = true;
}
if (!Pos && !Neg) return TRI_ON_PLANE;
else if (Pos && Neg) return TRI_INTERSECT;
else if (Pos && !Neg) return TRI_PLUS_SPACE;
else if (!Pos && Neg) return TRI_MINUS_SPACE;
// What?!
return TRI_FORCEDWORD;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle moment.
* \param m [out] the moment
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void Triangle::ComputeMoment(Moment& m)
{
// Compute the area of the triangle
m.mArea = Area();
// Compute the centroid
Center(m.mCentroid);
// Second-order components. Handle zero-area faces.
Point& p = mVerts[0];
Point& q = mVerts[1];
Point& r = mVerts[2];
if(m.mArea==0.0f)
{
// This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the
// sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices.
m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x);
m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y);
m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z);
m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y);
m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z);
m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z);
m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
}
else
{
const float OneOverTwelve = 1.0f / 12.0f;
m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve;
m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve;
m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve;
m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve;
m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve;
m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve;
m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
}
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle's smallest edge length.
* \return the smallest edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MinEdgeLength() const
{
float Min = MAX_FLOAT;
float Length01 = mVerts[0].Distance(mVerts[1]);
float Length02 = mVerts[0].Distance(mVerts[2]);
float Length12 = mVerts[1].Distance(mVerts[2]);
if(Length01 < Min) Min = Length01;
if(Length02 < Min) Min = Length02;
if(Length12 < Min) Min = Length12;
return Min;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle's largest edge length.
* \return the largest edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MaxEdgeLength() const
{
float Max = MIN_FLOAT;
float Length01 = mVerts[0].Distance(mVerts[1]);
float Length02 = mVerts[0].Distance(mVerts[2]);
float Length12 = mVerts[1].Distance(mVerts[2]);
if(Length01 > Max) Max = Length01;
if(Length02 > Max) Max = Length02;
if(Length12 > Max) Max = Length12;
return Max;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a point on the triangle according to the stabbing information.
* \param u,v [in] point's barycentric coordinates
* \param pt [out] point on triangle
* \param nearvtx [out] index of nearest vertex
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::ComputePoint(float u, float v, Point& pt, udword* nearvtx) const
{
// Compute point coordinates
pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2];
// Compute nearest vertex if needed
if(nearvtx)
{
// Compute distance vector
Point d(mVerts[0].SquareDistance(pt), // Distance^2 from vertex 0 to point on the face
mVerts[1].SquareDistance(pt), // Distance^2 from vertex 1 to point on the face
mVerts[2].SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face
// Get smallest distance
*nearvtx = d.SmallestAxis();
}
}
void Triangle::Inflate(float fat_coeff, bool constant_border)
{
// Compute triangle center
Point TriangleCenter;
Center(TriangleCenter);
// Don't normalize?
// Normalize => add a constant border, regardless of triangle size
// Don't => add more to big triangles
for(udword i=0;i<3;i++)
{
Point v = mVerts[i] - TriangleCenter;
if(constant_border) v.Normalize();
mVerts[i] += v * fat_coeff;
}
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy triangle class.
* \file IceTriangle.cpp
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a triangle class.
*
* \class Tri
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon)
{
// Compute distance from current vertex to the plane
float Dist = plane.Distance(v);
// Compute side:
// 1 = the vertex is on the positive side of the plane
// -1 = the vertex is on the negative side of the plane
// 0 = the vertex is on the plane (within epsilon)
return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Flips the winding order.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Flip()
{
Point Tmp = mVerts[1];
mVerts[1] = mVerts[2];
mVerts[2] = Tmp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle area.
* \return the area
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Area() const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle perimeter.
* \return the perimeter
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Perimeter() const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
return p0.Distance(p1)
+ p0.Distance(p2)
+ p1.Distance(p2);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle compacity.
* \return the compacity
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::Compacity() const
{
float P = Perimeter();
if(P==0.0f) return 0.0f;
return (4.0f*PI*Area()/(P*P));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle normal.
* \param normal [out] the computed normal
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Normal(Point& normal) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
normal = ((p0 - p1)^(p0 - p2)).Normalize();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle denormalized normal.
* \param normal [out] the computed normal
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::DenormalizedNormal(Point& normal) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
normal = ((p0 - p1)^(p0 - p2));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle center.
* \param center [out] the computed center
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::Center(Point& center) const
{
const Point& p0 = mVerts[0];
const Point& p1 = mVerts[1];
const Point& p2 = mVerts[2];
center = (p0 + p1 + p2)*INV3;
}
PartVal Triangle::TestAgainstPlane(const Plane& plane, float epsilon) const
{
bool Pos = false, Neg = false;
// Loop through all vertices
for(udword i=0;i<3;i++)
{
// Compute side:
sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon);
if (Side < 0) Neg = true;
else if (Side > 0) Pos = true;
}
if (!Pos && !Neg) return TRI_ON_PLANE;
else if (Pos && Neg) return TRI_INTERSECT;
else if (Pos && !Neg) return TRI_PLUS_SPACE;
else if (!Pos && Neg) return TRI_MINUS_SPACE;
// What?!
return TRI_FORCEDWORD;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle moment.
* \param m [out] the moment
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
void Triangle::ComputeMoment(Moment& m)
{
// Compute the area of the triangle
m.mArea = Area();
// Compute the centroid
Center(m.mCentroid);
// Second-order components. Handle zero-area faces.
Point& p = mVerts[0];
Point& q = mVerts[1];
Point& r = mVerts[2];
if(m.mArea==0.0f)
{
// This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the
// sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices.
m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x);
m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y);
m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z);
m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y);
m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z);
m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z);
m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
}
else
{
const float OneOverTwelve = 1.0f / 12.0f;
m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve;
m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve;
m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve;
m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve;
m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve;
m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve;
m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
}
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle's smallest edge length.
* \return the smallest edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MinEdgeLength() const
{
float Min = MAX_FLOAT;
float Length01 = mVerts[0].Distance(mVerts[1]);
float Length02 = mVerts[0].Distance(mVerts[2]);
float Length12 = mVerts[1].Distance(mVerts[2]);
if(Length01 < Min) Min = Length01;
if(Length02 < Min) Min = Length02;
if(Length12 < Min) Min = Length12;
return Min;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes the triangle's largest edge length.
* \return the largest edge length
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float Triangle::MaxEdgeLength() const
{
float Max = MIN_FLOAT;
float Length01 = mVerts[0].Distance(mVerts[1]);
float Length02 = mVerts[0].Distance(mVerts[2]);
float Length12 = mVerts[1].Distance(mVerts[2]);
if(Length01 > Max) Max = Length01;
if(Length02 > Max) Max = Length02;
if(Length12 > Max) Max = Length12;
return Max;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a point on the triangle according to the stabbing information.
* \param u,v [in] point's barycentric coordinates
* \param pt [out] point on triangle
* \param nearvtx [out] index of nearest vertex
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Triangle::ComputePoint(float u, float v, Point& pt, udword* nearvtx) const
{
// Compute point coordinates
pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2];
// Compute nearest vertex if needed
if(nearvtx)
{
// Compute distance vector
Point d(mVerts[0].SquareDistance(pt), // Distance^2 from vertex 0 to point on the face
mVerts[1].SquareDistance(pt), // Distance^2 from vertex 1 to point on the face
mVerts[2].SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face
// Get smallest distance
*nearvtx = d.SmallestAxis();
}
}
void Triangle::Inflate(float fat_coeff, bool constant_border)
{
// Compute triangle center
Point TriangleCenter;
Center(TriangleCenter);
// Don't normalize?
// Normalize => add a constant border, regardless of triangle size
// Don't => add more to big triangles
for(udword i=0;i<3;i++)
{
Point v = mVerts[i] - TriangleCenter;
if(constant_border) v.Normalize();
mVerts[i] += v * fat_coeff;
}
}

View File

@@ -1,84 +1,84 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy triangle class.
* \file IceTriangle.h
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETRIANGLE_H__
#define __ICETRIANGLE_H__
// Forward declarations
class Moment;
// Partitioning values
enum PartVal
{
TRI_MINUS_SPACE = 0, //!< Triangle is in the negative space
TRI_PLUS_SPACE = 1, //!< Triangle is in the positive space
TRI_INTERSECT = 2, //!< Triangle intersects plane
TRI_ON_PLANE = 3, //!< Triangle and plane are coplanar
TRI_FORCEDWORD = 0x7fffffff
};
// A triangle class.
class ICEMATHS_API Triangle
{
public:
//! Constructor
inline_ Triangle() {}
//! Constructor
inline_ Triangle(const Point& p0, const Point& p1, const Point& p2) { mVerts[0]=p0; mVerts[1]=p1; mVerts[2]=p2; }
//! Copy constructor
inline_ Triangle(const Triangle& triangle)
{
mVerts[0] = triangle.mVerts[0];
mVerts[1] = triangle.mVerts[1];
mVerts[2] = triangle.mVerts[2];
}
//! Destructor
inline_ ~Triangle() {}
//! Vertices
Point mVerts[3];
// Methods
void Flip();
float Area() const;
float Perimeter() const;
float Compacity() const;
void Normal(Point& normal) const;
void DenormalizedNormal(Point& normal) const;
void Center(Point& center) const;
inline_ Plane PlaneEquation() const { return Plane(mVerts[0], mVerts[1], mVerts[2]); }
PartVal TestAgainstPlane(const Plane& plane, float epsilon) const;
// float Distance(Point& cp, Point& cq, Tri& tri);
void ComputeMoment(Moment& m);
float MinEdgeLength() const;
float MaxEdgeLength() const;
void ComputePoint(float u, float v, Point& pt, udword* nearvtx=null) const;
void Inflate(float fat_coeff, bool constant_border);
};
#endif // __ICETRIANGLE_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a handy triangle class.
* \file IceTriangle.h
* \author Pierre Terdiman
* \date January, 17, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETRIANGLE_H__
#define __ICETRIANGLE_H__
// Forward declarations
class Moment;
// Partitioning values
enum PartVal
{
TRI_MINUS_SPACE = 0, //!< Triangle is in the negative space
TRI_PLUS_SPACE = 1, //!< Triangle is in the positive space
TRI_INTERSECT = 2, //!< Triangle intersects plane
TRI_ON_PLANE = 3, //!< Triangle and plane are coplanar
TRI_FORCEDWORD = 0x7fffffff
};
// A triangle class.
class ICEMATHS_API Triangle
{
public:
//! Constructor
inline_ Triangle() {}
//! Constructor
inline_ Triangle(const Point& p0, const Point& p1, const Point& p2) { mVerts[0]=p0; mVerts[1]=p1; mVerts[2]=p2; }
//! Copy constructor
inline_ Triangle(const Triangle& triangle)
{
mVerts[0] = triangle.mVerts[0];
mVerts[1] = triangle.mVerts[1];
mVerts[2] = triangle.mVerts[2];
}
//! Destructor
inline_ ~Triangle() {}
//! Vertices
Point mVerts[3];
// Methods
void Flip();
float Area() const;
float Perimeter() const;
float Compacity() const;
void Normal(Point& normal) const;
void DenormalizedNormal(Point& normal) const;
void Center(Point& center) const;
inline_ Plane PlaneEquation() const { return Plane(mVerts[0], mVerts[1], mVerts[2]); }
PartVal TestAgainstPlane(const Plane& plane, float epsilon) const;
// float Distance(Point& cp, Point& cq, Tri& tri);
void ComputeMoment(Moment& m);
float MinEdgeLength() const;
float MaxEdgeLength() const;
void ComputePoint(float u, float v, Point& pt, udword* nearvtx=null) const;
void Inflate(float fat_coeff, bool constant_border);
};
#endif // __ICETRIANGLE_H__

View File

@@ -1,77 +1,77 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a triangle container.
* \file IceTrilist.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETRILIST_H__
#define __ICETRILIST_H__
class ICEMATHS_API TriList : public Container
{
public:
// Constructor / Destructor
TriList() {}
~TriList() {}
inline_ udword GetNbTriangles() const { return GetNbEntries()/9; }
inline_ Triangle* GetTriangles() const { return (Triangle*)GetEntries(); }
void AddTri(const Triangle& tri)
{
Add(tri.mVerts[0].x).Add(tri.mVerts[0].y).Add(tri.mVerts[0].z);
Add(tri.mVerts[1].x).Add(tri.mVerts[1].y).Add(tri.mVerts[1].z);
Add(tri.mVerts[2].x).Add(tri.mVerts[2].y).Add(tri.mVerts[2].z);
}
void AddTri(const Point& p0, const Point& p1, const Point& p2)
{
Add(p0.x).Add(p0.y).Add(p0.z);
Add(p1.x).Add(p1.y).Add(p1.z);
Add(p2.x).Add(p2.y).Add(p2.z);
}
};
class ICEMATHS_API TriangleList : public Container
{
public:
// Constructor / Destructor
TriangleList() {}
~TriangleList() {}
inline_ udword GetNbTriangles() const { return GetNbEntries()/3; }
inline_ IndexedTriangle* GetTriangles() const { return (IndexedTriangle*)GetEntries();}
void AddTriangle(const IndexedTriangle& tri)
{
Add(tri.mVRef[0]).Add(tri.mVRef[1]).Add(tri.mVRef[2]);
}
void AddTriangle(udword vref0, udword vref1, udword vref2)
{
Add(vref0).Add(vref1).Add(vref2);
}
};
#endif //__ICETRILIST_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a triangle container.
* \file IceTrilist.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETRILIST_H__
#define __ICETRILIST_H__
class ICEMATHS_API TriList : public Container
{
public:
// Constructor / Destructor
TriList() {}
~TriList() {}
inline_ udword GetNbTriangles() const { return GetNbEntries()/9; }
inline_ Triangle* GetTriangles() const { return (Triangle*)GetEntries(); }
void AddTri(const Triangle& tri)
{
Add(tri.mVerts[0].x).Add(tri.mVerts[0].y).Add(tri.mVerts[0].z);
Add(tri.mVerts[1].x).Add(tri.mVerts[1].y).Add(tri.mVerts[1].z);
Add(tri.mVerts[2].x).Add(tri.mVerts[2].y).Add(tri.mVerts[2].z);
}
void AddTri(const Point& p0, const Point& p1, const Point& p2)
{
Add(p0.x).Add(p0.y).Add(p0.z);
Add(p1.x).Add(p1.y).Add(p1.z);
Add(p2.x).Add(p2.y).Add(p2.z);
}
};
class ICEMATHS_API TriangleList : public Container
{
public:
// Constructor / Destructor
TriangleList() {}
~TriangleList() {}
inline_ udword GetNbTriangles() const { return GetNbEntries()/3; }
inline_ IndexedTriangle* GetTriangles() const { return (IndexedTriangle*)GetEntries();}
void AddTriangle(const IndexedTriangle& tri)
{
Add(tri.mVRef[0]).Add(tri.mVRef[1]).Add(tri.mVRef[2]);
}
void AddTriangle(udword vref0, udword vref1, udword vref2)
{
Add(vref0).Add(vref1).Add(vref2);
}
};
#endif //__ICETRILIST_H__

View File

@@ -1,181 +1,181 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom types.
* \file IceTypes.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICETYPES_H
#define ICETYPES_H
#define USE_HANDLE_MANAGER
// Constants
#ifndef PI
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
#endif
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
#define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
#define EXP 2.71828182845904523536f //!< e
#define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2)
#define LN2 0.693147180559945f //!< ln(2)
#define INVLN2 1.44269504089f //!< 1.0f / ln(2)
#define INV3 0.33333333333333333333f //!< 1/3
#define INV6 0.16666666666666666666f //!< 1/6
#define INV7 0.14285714285714285714f //!< 1/7
#define INV9 0.11111111111111111111f //!< 1/9
#define INV255 0.00392156862745098039f //!< 1/255
#define SQRT2 1.41421356237f //!< sqrt(2)
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
#define SQRT3 1.73205080757f //!< sqrt(3)
#define INVSQRT3 0.577350269189f //!< 1 / sqrt(3)
#define null 0 //!< our own NULL pointer
// Custom types used in ICE
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
typedef signed short sword; //!< sizeof(sword) must be 2
typedef unsigned short uword; //!< sizeof(uword) must be 2
typedef signed int sdword; //!< sizeof(sdword) must be 4
typedef unsigned int udword; //!< sizeof(udword) must be 4
#ifdef WIN32
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
#elif LINUX
typedef signed long long sqword; //!< sizeof(sqword) must be 8
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
#elif defined(__APPLE__)
typedef signed long long sqword; //!< sizeof(sqword) must be 8
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
#elif defined(_XBOX)
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
#endif
typedef float float32; //!< sizeof(float32) must be 4
typedef double float64; //!< sizeof(float64) must be 8
typedef size_t regsize; //!< sizeof(regsize) must be sizeof(void*)
// For test purpose you can force one of those:
// typedef udword regsize;
// typedef uqword regsize;
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(float32)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(float64)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(regsize)==sizeof(void*));
//! TO BE DOCUMENTED
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
typedef udword DynID; //!< Dynamic identifier
#ifdef USE_HANDLE_MANAGER
typedef udword KID; //!< Kernel ID
// DECLARE_ICE_HANDLE(KID);
#else
typedef uword KID; //!< Kernel ID
#endif
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
#ifdef USE_HANDLE_MANAGER
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
#else
#define INVALID_KID 0xffff //!< Invalid Kernel ID
#endif
#define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value
// Define BOOL if needed
#ifndef BOOL
typedef int BOOL; //!< Another boolean type.
#endif
//! Union of a float and a sdword
typedef union {
float f; //!< The float
sdword d; //!< The integer
}scell;
//! Union of a float and a udword
typedef union {
float f; //!< The float
udword d; //!< The integer
}ucell;
// Type ranges
#define MAX_SBYTE 0x7f //!< max possible sbyte value
#define MIN_SBYTE 0x80 //!< min possible sbyte value
#define MAX_UBYTE 0xff //!< max possible ubyte value
#define MIN_UBYTE 0x00 //!< min possible ubyte value
#define MAX_SWORD 0x7fff //!< max possible sword value
#define MIN_SWORD 0x8000 //!< min possible sword value
#define MAX_UWORD 0xffff //!< max possible uword value
#define MIN_UWORD 0x0000 //!< min possible uword value
#define MAX_SDWORD 0x7fffffff //!< max possible sdword value
#define MIN_SDWORD 0x80000000 //!< min possible sdword value
#define MAX_UDWORD 0xffffffff //!< max possible udword value
#define MIN_UDWORD 0x00000000 //!< min possible udword value
#define MAX_FLOAT FLT_MAX //!< max possible float value
#define MIN_FLOAT (-FLT_MAX) //!< min possible loat value
#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0
#define IEEE_255_0 0x437f0000 //!< integer representation of 255.0
#define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT
#define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT
#define IEEE_UNDERFLOW_LIMIT 0x1a000000
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
typedef void** VTABLE; //!< A V-Table.
#undef MIN
#undef MAX
#define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b
#define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b
#define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c
template<class T> inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; }
template<class T> inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; }
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
/* Obsolete stuff - if needed, move to dedicated header and include in few files using this.
#define SQR(x) ((x)*(x)) //!< Returns x square
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
#define AND & //!< ...
#define OR | //!< ...
#define XOR ^ //!< ...
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
#ifdef _WIN32
// Used to compile legacy code
__forceinline void srand48(udword x) { srand(x); }
__forceinline void srandom(udword x) { srand(x); }
__forceinline double random() { return (double)rand(); }
__forceinline double drand48() { return (double) ( ((double)rand()) / ((double)RAND_MAX) ); }
#endif
*/
#endif // ICETYPES_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom types.
* \file IceTypes.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICETYPES_H
#define ICETYPES_H
#define USE_HANDLE_MANAGER
// Constants
#ifndef PI
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
#endif
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
#define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
#define EXP 2.71828182845904523536f //!< e
#define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2)
#define LN2 0.693147180559945f //!< ln(2)
#define INVLN2 1.44269504089f //!< 1.0f / ln(2)
#define INV3 0.33333333333333333333f //!< 1/3
#define INV6 0.16666666666666666666f //!< 1/6
#define INV7 0.14285714285714285714f //!< 1/7
#define INV9 0.11111111111111111111f //!< 1/9
#define INV255 0.00392156862745098039f //!< 1/255
#define SQRT2 1.41421356237f //!< sqrt(2)
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
#define SQRT3 1.73205080757f //!< sqrt(3)
#define INVSQRT3 0.577350269189f //!< 1 / sqrt(3)
#define null 0 //!< our own NULL pointer
// Custom types used in ICE
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
typedef signed short sword; //!< sizeof(sword) must be 2
typedef unsigned short uword; //!< sizeof(uword) must be 2
typedef signed int sdword; //!< sizeof(sdword) must be 4
typedef unsigned int udword; //!< sizeof(udword) must be 4
#ifdef WIN32
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
#elif LINUX
typedef signed long long sqword; //!< sizeof(sqword) must be 8
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
#elif defined(__APPLE__)
typedef signed long long sqword; //!< sizeof(sqword) must be 8
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
#elif defined(_XBOX)
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
#endif
typedef float float32; //!< sizeof(float32) must be 4
typedef double float64; //!< sizeof(float64) must be 8
typedef size_t regsize; //!< sizeof(regsize) must be sizeof(void*)
// For test purpose you can force one of those:
// typedef udword regsize;
// typedef uqword regsize;
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(float32)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(float64)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(regsize)==sizeof(void*));
//! TO BE DOCUMENTED
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
typedef udword DynID; //!< Dynamic identifier
#ifdef USE_HANDLE_MANAGER
typedef udword KID; //!< Kernel ID
// DECLARE_ICE_HANDLE(KID);
#else
typedef uword KID; //!< Kernel ID
#endif
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
#ifdef USE_HANDLE_MANAGER
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
#else
#define INVALID_KID 0xffff //!< Invalid Kernel ID
#endif
#define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value
// Define BOOL if needed
#ifndef BOOL
typedef int BOOL; //!< Another boolean type.
#endif
//! Union of a float and a sdword
typedef union {
float f; //!< The float
sdword d; //!< The integer
}scell;
//! Union of a float and a udword
typedef union {
float f; //!< The float
udword d; //!< The integer
}ucell;
// Type ranges
#define MAX_SBYTE 0x7f //!< max possible sbyte value
#define MIN_SBYTE 0x80 //!< min possible sbyte value
#define MAX_UBYTE 0xff //!< max possible ubyte value
#define MIN_UBYTE 0x00 //!< min possible ubyte value
#define MAX_SWORD 0x7fff //!< max possible sword value
#define MIN_SWORD 0x8000 //!< min possible sword value
#define MAX_UWORD 0xffff //!< max possible uword value
#define MIN_UWORD 0x0000 //!< min possible uword value
#define MAX_SDWORD 0x7fffffff //!< max possible sdword value
#define MIN_SDWORD 0x80000000 //!< min possible sdword value
#define MAX_UDWORD 0xffffffff //!< max possible udword value
#define MIN_UDWORD 0x00000000 //!< min possible udword value
#define MAX_FLOAT FLT_MAX //!< max possible float value
#define MIN_FLOAT (-FLT_MAX) //!< min possible loat value
#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0
#define IEEE_255_0 0x437f0000 //!< integer representation of 255.0
#define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT
#define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT
#define IEEE_UNDERFLOW_LIMIT 0x1a000000
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
typedef void** VTABLE; //!< A V-Table.
#undef MIN
#undef MAX
#define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b
#define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b
#define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c
template<class T> inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; }
template<class T> inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; }
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
/* Obsolete stuff - if needed, move to dedicated header and include in few files using this.
#define SQR(x) ((x)*(x)) //!< Returns x square
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
#define AND & //!< ...
#define OR | //!< ...
#define XOR ^ //!< ...
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
#ifdef _WIN32
// Used to compile legacy code
__forceinline void srand48(udword x) { srand(x); }
__forceinline void srandom(udword x) { srand(x); }
__forceinline double random() { return (double)rand(); }
__forceinline double drand48() { return (double) ( ((double)rand()) / ((double)RAND_MAX) ); }
#endif
*/
#endif // ICETYPES_H

View File

@@ -1,55 +1,55 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.cpp
* \author Pierre Terdiman (collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword IceCore::Alignment(udword address)
{
// Returns 0 for null addresses
if(!address) return 0;
// Test all bits
udword Align = 1;
for(udword i=1;i<32;i++)
{
// Returns as soon as the alignment is broken
if(address&Align) return Align;
Align<<=1;
}
// Here all bits are null, except the highest one (else the address would be null)
return Align;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.cpp
* \author Pierre Terdiman (collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword IceCore::Alignment(udword address)
{
// Returns 0 for null addresses
if(!address) return 0;
// Test all bits
udword Align = 1;
for(udword i=1;i<32;i++)
{
// Returns as soon as the alignment is broken
if(address&Align) return Align;
Align<<=1;
}
// Here all bits are null, except the highest one (else the address would be null)
return Align;
}

View File

@@ -1,377 +1,377 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.h
* \author Pierre Terdiman (personal code + collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEUTILS_H
#define ICEUTILS_H
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
#define END_RUNONCE __RunOnce__ = true;}}
//! Reverse all the bits in a 32 bit word (from Steve Baker's Cute Code Collection)
//! (each line can be done in any order.
inline_ void ReverseBits(udword& n)
{
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
// Etc for larger integers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
}
//! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection)
inline_ udword CountBits(udword n)
{
// This relies of the fact that the count of n bits can NOT overflow
// an n bit integer. EG: 1 bit count takes a 1 bit integer, 2 bit counts
// 2 bit integer, 3 bit count requires only a 2 bit integer.
// So we add all bit pairs, then each nible, then each byte etc...
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
// Etc for larger integers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
return n;
}
//! Even faster?
inline_ udword CountBits2(udword bits)
{
bits = bits - ((bits >> 1) & 0x55555555);
bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333);
bits = ((bits >> 4) + bits) & 0x0F0F0F0F;
return (bits * 0x01010101) >> 24;
}
// "Population Count (Ones Count)
// The population count of a binary integer value x is the number of one bits in the value. Although many machines have
// single instructions for this, the single instructions are usually microcoded loops that test a bit per cycle; a log-time
// algorithm coded in C is often faster. The following code uses a variable-precision SWAR algorithm to perform a tree
// reduction adding the bits in a 32-bit value:"
inline_ udword ones32(udword x)
{
/* 32-bit recursive reduction using SWAR...
but first step is mapping 2-bit values
into sum of 2 1-bit values in sneaky way
*/
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
x += (x >> 8);
x += (x >> 16);
return (x & 0x0000003f);
// "It is worthwhile noting that the SWAR population count algorithm given above can be improved upon for the case of
// counting the population of multi-word bit sets. How? The last few steps in the reduction are using only a portion
// of the SWAR width to produce their results; thus, it would be possible to combine these steps across multiple words
// being reduced. One additional note: the AMD Athlon optimization guidelines suggest a very similar algorithm that
// replaces the last three lines with return((x * 0x01010101) >> 24);. For the Athlon (which has a very fast integer
// multiply), I would have expected AMD's code to be faster... but it is actually 6% slower according to my benchmarks
// using a 1.2GHz Athlon (a Thunderbird). Why? Well, it so happens that GCC doesn't use a multiply instruction - it
// writes out the equivalent shift and add sequence!"
}
// "Trailing Zero Count
// Given the Least Significant 1 Bit and Population Count (Ones Count) algorithms, it is trivial to combine them to
// construct a trailing zero count (as pointed-out by Joe Bowbeer):"
inline_ udword tzc(sdword x)
{
return(ones32((x & -x) - 1));
}
//! Spread out bits. EG 00001111 -> 0101010101
//! 00001010 -> 0100010000
//! This is used to interleave two integers to produce a `Morton Key'
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
//! Order is important.
inline_ void SpreadBits(udword& n)
{
n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16);
n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8);
n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4);
n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2);
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
}
// "Next Largest Power of 2
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
// largest power of 2. For a 32-bit value:"
inline_ udword NextPowerOfTwo(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x+1;
}
//! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection)
inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); }
//! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection)
inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); }
//! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection)
inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<<n); }
//! Classic XOR swap (from Steve Baker's Cute Code Collection)
//! x ^= y; /* x' = (x^y) */
//! y ^= x; /* y' = (y^(x^y)) = x */
//! x ^= y; /* x' = (x^y)^x = y */
inline_ void Swap(udword& x, udword& y) { x ^= y; y ^= x; x ^= y; }
//! Little/Big endian (from Steve Baker's Cute Code Collection)
//!
//! Extra comments by Kenny Hoff:
//! Determines the byte-ordering of the current machine (little or big endian)
//! by setting an integer value to 1 (so least significant bit is now 1); take
//! the address of the int and cast to a byte pointer (treat integer as an
//! array of four bytes); check the value of the first byte (must be 0 or 1).
//! If the value is 1, then the first byte least significant byte and this
//! implies LITTLE endian. If the value is 0, the first byte is the most
//! significant byte, BIG endian. Examples:
//! integer 1 on BIG endian: 00000000 00000000 00000000 00000001
//! integer 1 on LITTLE endian: 00000001 00000000 00000000 00000000
//!---------------------------------------------------------------------------
//! int IsLittleEndian() { int x=1; return ( ((char*)(&x))[0] ); }
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
//!< Alternative abs function
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
// "Integer Minimum or Maximum
// Given 2's complement integer values x and y, the minimum can be computed without any branches as
// x+(((y-x)>>(WORDBITS-1))&(y-x)).
// Logically, this works because the shift by (WORDBITS-1) replicates the sign bit to create a mask
// -- be aware, however, that the C language does not require that shifts are signed even if their
// operands are signed, so there is a potential portability problem. Additionally, one might think
// that a shift by any number greater than or equal to WORDBITS would have the same effect, but many
// instruction sets have shifts that behave strangely when such shift distances are specified.
// Of course, maximum can be computed using the same trick:
// x-(((x-y)>>(WORDBITS-1))&(x-y))."
//!< Alternative min function
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
//!< Alternative max function
inline_ sdword max_(sdword a, sdword b) { sdword delta = a-b; return a - (delta&(delta>>31)); }
// "Integer Selection
// A branchless, lookup-free, alternative to code like if (a<b) x=c; else x=d; is ((((a-b) >> (WORDBITS-1)) & (c^d)) ^ d).
// This code assumes that the shift is signed, which, of course, C does not promise."
inline_ sdword IntegerSelection(sdword a, sdword b, sdword c, sdword d)
{
return ((((a-b)>>31) & (c^d)) ^ d);
}
// Determine if one of the bytes in a 4 byte word is zero
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
// "Most Significant 1 Bit
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
// yields the most significant bit. For a 32-bit value:"
inline_ udword msb32(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return (x & ~(x >> 1));
}
// "Gray Code Conversion
// A Gray code is any binary coding sequence in which only a single bit position changes as we move from one value to the next.
// There are many such codes, but the traditional one is computed such that the Kth Gray code is K^(K>>1).
//
// The well-known algorithm for conversion from Gray to binary is a linear sequence of XORs that makes it seem each bit must be
// dealt with separately. Fortunately, that is equivalent to a parallel prefix XOR that can be computed using SWAR techniques
// in log time. For 32-bit Gray code values produced as described above, the conversion from Gray code back to unsigned binary is:"
inline_ udword g2b(udword gray)
{
gray ^= (gray >> 16);
gray ^= (gray >> 8);
gray ^= (gray >> 4);
gray ^= (gray >> 2);
gray ^= (gray >> 1);
return gray;
}
/*
"Just call it repeatedly with various input values and always with the same variable as "memory".
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
does no filtering at all.
I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed
to the more typical FIR (Finite Impulse Response).
Also, I'd say that you can make more intelligent and interesting filters than this, for example filters
that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter
to be applied before this one, of course."
(JCAB on Flipcode)
*/
inline_ float FeedbackFilter(float val, float& memory, float sharpness)
{
ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter");
if(sharpness<0.0f) sharpness = 0.0f;
else if(sharpness>1.0f) sharpness = 1.0f;
return memory = val * sharpness + memory * (1.0f - sharpness);
}
//! "If you can guarantee that your input domain (i.e. value of x) is slightly
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
//! following code to clamp the resulting value into [-32768,+32767] range:"
inline_ int ClampToInt16(int x)
{
// ASSERT(abs(x) < (int)((1<<31u)-32767));
int delta = 32767 - x;
x += (delta>>31) & delta;
delta = x + 32768;
x -= (delta>>31) & delta;
return x;
}
// Generic functions
template<class Type> inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; }
template<class Type> inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((x<lo) ? lo : (x>hi) ? hi : x); }
template<class Type> inline_ void TSort(Type& a, Type& b)
{
if(a>b) TSwap(a, b);
}
template<class Type> inline_ void TSort(Type& a, Type& b, Type& c)
{
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
}
// Prevent nasty user-manipulations (strategy borrowed from Charles Bloom)
// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); }
// ... actually this is better !
#define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object);
//! TO BE DOCUMENTED
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
//! TO BE DOCUMENTED
#if !defined(_XBOX)
// Already defined on Xbox.
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION ICECORE_API udword Alignment(udword address);
#define IS_ALIGNED_2(x) ((x&1)==0)
#define IS_ALIGNED_4(x) ((x&3)==0)
#define IS_ALIGNED_8(x) ((x&7)==0)
// Updates a pointer with "stride" bytes
inline_ void UpdatePtr(void*& ptr, udword stride) { ptr = ((ubyte*)ptr) + stride; }
// From Jon Watte IIRC
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
// Compute implicit coords from an index:
// The idea is to get back 2D coords from a 1D index.
// For example:
//
// 0 1 2 ... nbu-1
// nbu nbu+1 i ...
//
// We have i, we're looking for the equivalent (u=2, v=1) location.
// i = u + v*nbu
// <=> i/nbu = u/nbu + v
// Since 0 <= u < nbu, u/nbu = 0 (integer)
// Hence: v = i/nbu
// Then we simply put it back in the original equation to compute u = i - v*nbu
inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu)
{
v = i / nbu;
u = i - (v * nbu);
}
// In 3D: i = u + v*nbu + w*nbu*nbv
// <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w
// u/(nbu*nbv) is null since u/nbu was null already.
// v/nbv is null as well for the same reason.
// Hence w = i/(nbu*nbv)
// Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu
inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv)
{
w = i / (nbu_nbv);
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
}
// Calling fsincos instead of fsin+fcos. Twice faster.
inline_ void FSinCos(float& c, float& s, float f)
{
float LocalCos, LocalSin;
float Local = f;
#ifdef WIN32
_asm fld Local
_asm fsincos
_asm fstp LocalCos
_asm fstp LocalSin
#elif LINUX
asm("fld Local\n\t"
"fsincos\n\t"
"fstp LocalCos\n\t"
"fstp LocalSin\n\t"
);
#endif
c = LocalCos;
s = LocalSin;
}
// Modulo3 macros. See http://www.codercorner.com/Modulo3.htm
#define GET_NEXT_INDICES(i, j, k) \
k = 0x01000201; \
k>>=(i<<3); \
j = k & 0xff; \
k>>=8; \
k&=0xff;
#define GET_NEXT_INDICES2(i, j, k) \
j = ( 9 >> (i<<1)) & 3; \
k = (18 >> (i<<1)) & 3;
// 0=>1, 1=>2, 2=>0
inline_ udword Modulo3(udword i)
{
ASSERT(i==0 || i==1 || i==2);
return (9 >> (i << 1)) & 3;
}
#endif // ICEUTILS_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.h
* \author Pierre Terdiman (personal code + collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef ICEUTILS_H
#define ICEUTILS_H
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
#define END_RUNONCE __RunOnce__ = true;}}
//! Reverse all the bits in a 32 bit word (from Steve Baker's Cute Code Collection)
//! (each line can be done in any order.
inline_ void ReverseBits(udword& n)
{
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
// Etc for larger integers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
}
//! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection)
inline_ udword CountBits(udword n)
{
// This relies of the fact that the count of n bits can NOT overflow
// an n bit integer. EG: 1 bit count takes a 1 bit integer, 2 bit counts
// 2 bit integer, 3 bit count requires only a 2 bit integer.
// So we add all bit pairs, then each nible, then each byte etc...
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
// Etc for larger integers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
return n;
}
//! Even faster?
inline_ udword CountBits2(udword bits)
{
bits = bits - ((bits >> 1) & 0x55555555);
bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333);
bits = ((bits >> 4) + bits) & 0x0F0F0F0F;
return (bits * 0x01010101) >> 24;
}
// "Population Count (Ones Count)
// The population count of a binary integer value x is the number of one bits in the value. Although many machines have
// single instructions for this, the single instructions are usually microcoded loops that test a bit per cycle; a log-time
// algorithm coded in C is often faster. The following code uses a variable-precision SWAR algorithm to perform a tree
// reduction adding the bits in a 32-bit value:"
inline_ udword ones32(udword x)
{
/* 32-bit recursive reduction using SWAR...
but first step is mapping 2-bit values
into sum of 2 1-bit values in sneaky way
*/
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
x += (x >> 8);
x += (x >> 16);
return (x & 0x0000003f);
// "It is worthwhile noting that the SWAR population count algorithm given above can be improved upon for the case of
// counting the population of multi-word bit sets. How? The last few steps in the reduction are using only a portion
// of the SWAR width to produce their results; thus, it would be possible to combine these steps across multiple words
// being reduced. One additional note: the AMD Athlon optimization guidelines suggest a very similar algorithm that
// replaces the last three lines with return((x * 0x01010101) >> 24);. For the Athlon (which has a very fast integer
// multiply), I would have expected AMD's code to be faster... but it is actually 6% slower according to my benchmarks
// using a 1.2GHz Athlon (a Thunderbird). Why? Well, it so happens that GCC doesn't use a multiply instruction - it
// writes out the equivalent shift and add sequence!"
}
// "Trailing Zero Count
// Given the Least Significant 1 Bit and Population Count (Ones Count) algorithms, it is trivial to combine them to
// construct a trailing zero count (as pointed-out by Joe Bowbeer):"
inline_ udword tzc(sdword x)
{
return(ones32((x & -x) - 1));
}
//! Spread out bits. EG 00001111 -> 0101010101
//! 00001010 -> 0100010000
//! This is used to interleave two integers to produce a `Morton Key'
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
//! Order is important.
inline_ void SpreadBits(udword& n)
{
n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16);
n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8);
n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4);
n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2);
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
}
// "Next Largest Power of 2
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
// largest power of 2. For a 32-bit value:"
inline_ udword NextPowerOfTwo(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x+1;
}
//! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection)
inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); }
//! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection)
inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); }
//! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection)
inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<<n); }
//! Classic XOR swap (from Steve Baker's Cute Code Collection)
//! x ^= y; /* x' = (x^y) */
//! y ^= x; /* y' = (y^(x^y)) = x */
//! x ^= y; /* x' = (x^y)^x = y */
inline_ void Swap(udword& x, udword& y) { x ^= y; y ^= x; x ^= y; }
//! Little/Big endian (from Steve Baker's Cute Code Collection)
//!
//! Extra comments by Kenny Hoff:
//! Determines the byte-ordering of the current machine (little or big endian)
//! by setting an integer value to 1 (so least significant bit is now 1); take
//! the address of the int and cast to a byte pointer (treat integer as an
//! array of four bytes); check the value of the first byte (must be 0 or 1).
//! If the value is 1, then the first byte least significant byte and this
//! implies LITTLE endian. If the value is 0, the first byte is the most
//! significant byte, BIG endian. Examples:
//! integer 1 on BIG endian: 00000000 00000000 00000000 00000001
//! integer 1 on LITTLE endian: 00000001 00000000 00000000 00000000
//!---------------------------------------------------------------------------
//! int IsLittleEndian() { int x=1; return ( ((char*)(&x))[0] ); }
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
//!< Alternative abs function
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
// "Integer Minimum or Maximum
// Given 2's complement integer values x and y, the minimum can be computed without any branches as
// x+(((y-x)>>(WORDBITS-1))&(y-x)).
// Logically, this works because the shift by (WORDBITS-1) replicates the sign bit to create a mask
// -- be aware, however, that the C language does not require that shifts are signed even if their
// operands are signed, so there is a potential portability problem. Additionally, one might think
// that a shift by any number greater than or equal to WORDBITS would have the same effect, but many
// instruction sets have shifts that behave strangely when such shift distances are specified.
// Of course, maximum can be computed using the same trick:
// x-(((x-y)>>(WORDBITS-1))&(x-y))."
//!< Alternative min function
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
//!< Alternative max function
inline_ sdword max_(sdword a, sdword b) { sdword delta = a-b; return a - (delta&(delta>>31)); }
// "Integer Selection
// A branchless, lookup-free, alternative to code like if (a<b) x=c; else x=d; is ((((a-b) >> (WORDBITS-1)) & (c^d)) ^ d).
// This code assumes that the shift is signed, which, of course, C does not promise."
inline_ sdword IntegerSelection(sdword a, sdword b, sdword c, sdword d)
{
return ((((a-b)>>31) & (c^d)) ^ d);
}
// Determine if one of the bytes in a 4 byte word is zero
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
// "Most Significant 1 Bit
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
// yields the most significant bit. For a 32-bit value:"
inline_ udword msb32(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return (x & ~(x >> 1));
}
// "Gray Code Conversion
// A Gray code is any binary coding sequence in which only a single bit position changes as we move from one value to the next.
// There are many such codes, but the traditional one is computed such that the Kth Gray code is K^(K>>1).
//
// The well-known algorithm for conversion from Gray to binary is a linear sequence of XORs that makes it seem each bit must be
// dealt with separately. Fortunately, that is equivalent to a parallel prefix XOR that can be computed using SWAR techniques
// in log time. For 32-bit Gray code values produced as described above, the conversion from Gray code back to unsigned binary is:"
inline_ udword g2b(udword gray)
{
gray ^= (gray >> 16);
gray ^= (gray >> 8);
gray ^= (gray >> 4);
gray ^= (gray >> 2);
gray ^= (gray >> 1);
return gray;
}
/*
"Just call it repeatedly with various input values and always with the same variable as "memory".
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
does no filtering at all.
I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed
to the more typical FIR (Finite Impulse Response).
Also, I'd say that you can make more intelligent and interesting filters than this, for example filters
that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter
to be applied before this one, of course."
(JCAB on Flipcode)
*/
inline_ float FeedbackFilter(float val, float& memory, float sharpness)
{
ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter");
if(sharpness<0.0f) sharpness = 0.0f;
else if(sharpness>1.0f) sharpness = 1.0f;
return memory = val * sharpness + memory * (1.0f - sharpness);
}
//! "If you can guarantee that your input domain (i.e. value of x) is slightly
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
//! following code to clamp the resulting value into [-32768,+32767] range:"
inline_ int ClampToInt16(int x)
{
// ASSERT(abs(x) < (int)((1<<31u)-32767));
int delta = 32767 - x;
x += (delta>>31) & delta;
delta = x + 32768;
x -= (delta>>31) & delta;
return x;
}
// Generic functions
template<class Type> inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; }
template<class Type> inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((x<lo) ? lo : (x>hi) ? hi : x); }
template<class Type> inline_ void TSort(Type& a, Type& b)
{
if(a>b) TSwap(a, b);
}
template<class Type> inline_ void TSort(Type& a, Type& b, Type& c)
{
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
}
// Prevent nasty user-manipulations (strategy borrowed from Charles Bloom)
// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); }
// ... actually this is better !
#define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object);
//! TO BE DOCUMENTED
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
//! TO BE DOCUMENTED
#if !defined(_XBOX)
// Already defined on Xbox.
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION ICECORE_API udword Alignment(udword address);
#define IS_ALIGNED_2(x) ((x&1)==0)
#define IS_ALIGNED_4(x) ((x&3)==0)
#define IS_ALIGNED_8(x) ((x&7)==0)
// Updates a pointer with "stride" bytes
inline_ void UpdatePtr(void*& ptr, udword stride) { ptr = ((ubyte*)ptr) + stride; }
// From Jon Watte IIRC
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
// Compute implicit coords from an index:
// The idea is to get back 2D coords from a 1D index.
// For example:
//
// 0 1 2 ... nbu-1
// nbu nbu+1 i ...
//
// We have i, we're looking for the equivalent (u=2, v=1) location.
// i = u + v*nbu
// <=> i/nbu = u/nbu + v
// Since 0 <= u < nbu, u/nbu = 0 (integer)
// Hence: v = i/nbu
// Then we simply put it back in the original equation to compute u = i - v*nbu
inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu)
{
v = i / nbu;
u = i - (v * nbu);
}
// In 3D: i = u + v*nbu + w*nbu*nbv
// <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w
// u/(nbu*nbv) is null since u/nbu was null already.
// v/nbv is null as well for the same reason.
// Hence w = i/(nbu*nbv)
// Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu
inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv)
{
w = i / (nbu_nbv);
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
}
// Calling fsincos instead of fsin+fcos. Twice faster.
inline_ void FSinCos(float& c, float& s, float f)
{
float LocalCos, LocalSin;
float Local = f;
#ifdef WIN32
_asm fld Local
_asm fsincos
_asm fstp LocalCos
_asm fstp LocalSin
#elif LINUX
asm("fld Local\n\t"
"fsincos\n\t"
"fstp LocalCos\n\t"
"fstp LocalSin\n\t"
);
#endif
c = LocalCos;
s = LocalSin;
}
// Modulo3 macros. See http://www.codercorner.com/Modulo3.htm
#define GET_NEXT_INDICES(i, j, k) \
k = 0x01000201; \
k>>=(i<<3); \
j = k & 0xff; \
k>>=8; \
k&=0xff;
#define GET_NEXT_INDICES2(i, j, k) \
j = ( 9 >> (i<<1)) & 3; \
k = (18 >> (i<<1)) & 3;
// 0=>1, 1=>2, 2=>0
inline_ udword Modulo3(udword i)
{
ASSERT(i==0 || i==1 || i==2);
return (9 >> (i << 1)) & 3;
}
#endif // ICEUTILS_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,361 +1,361 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a list of 32-bits values.
* Use this class when you need to store an unknown number of values. The list is automatically
* resized and can contains 32-bits entities (dwords or floats)
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace IceCore;
// Static members
#ifdef CONTAINER_STATS
udword Container::mNbContainers = 0;
udword Container::mUsedRam = 0;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. No entries allocated there.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. Also allocates a given number of entries.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
SetSize(size);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Copy constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
*this = object;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor. Frees everything and leaves.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::~Container()
{
Empty();
#ifdef CONTAINER_STATS
mNbContainers--;
mUsedRam-=GetUsedRam();
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::Empty()
{
#ifdef CONTAINER_STATS
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
DELETEARRAY(mEntries);
mCurNbEntries = mMaxNbEntries = 0;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resizes the container.
* \param needed [in] assume the container can be added at least "needed" values
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Resize(udword needed)
{
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get more entries
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
// Get some bytes for new entries
udword* NewEntries = new udword[mMaxNbEntries];
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data if needed
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
DELETEARRAY(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::SetSize(udword nb)
{
// Make sure it's empty
Empty();
// Checkings
if(!nb) return false;
// Initialize for nb entries
mMaxNbEntries = nb;
// Get some bytes for new entries
mEntries = new udword[mMaxNbEntries];
CHECKALLOC(mEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Refit()
{
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
if(!mMaxNbEntries) return false;
// Get just enough bytes
udword* NewEntries = new udword[mMaxNbEntries];
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
DELETEARRAY(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the container already contains a given value.
* \param entry [in] the value to look for in the container
* \param location [out] a possible pointer to store the entry location
* \see Add(udword entry)
* \see Add(float entry)
* \see Empty()
* \return true if the value has been found in the container, else false.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Contains(udword entry, udword* location) const
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
if(location) *location = i;
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Delete(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
DeleteIndex(i);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::DeleteKeepingOrder(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i.
// Shift entries to preserve order. You really should use a linked list instead.
mCurNbEntries--;
for(udword j=i;j<mCurNbEntries;j++)
{
mEntries[j] = mEntries[j+1];
}
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the next entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the next entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindNext(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location++;
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the previous entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindPrev(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location--;
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the ram used by the container.
* \return the ram used in bytes.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Container::GetUsedRam() const
{
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
}
void Container::operator=(const Container& object)
{
SetSize(object.GetNbEntries());
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
mCurNbEntries = mMaxNbEntries;
}
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.cpp
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a list of 32-bits values.
* Use this class when you need to store an unknown number of values. The list is automatically
* resized and can contains 32-bits entities (dwords or floats)
*
* \class Container
* \author Pierre Terdiman
* \version 1.0
* \date 08.15.98
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace IceCore;
// Static members
#ifdef CONTAINER_STATS
udword Container::mNbContainers = 0;
udword Container::mUsedRam = 0;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. No entries allocated there.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor. Also allocates a given number of entries.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
SetSize(size);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Copy constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
{
#ifdef CONTAINER_STATS
mNbContainers++;
mUsedRam+=sizeof(Container);
#endif
*this = object;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor. Frees everything and leaves.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container::~Container()
{
Empty();
#ifdef CONTAINER_STATS
mNbContainers--;
mUsedRam-=GetUsedRam();
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::Empty()
{
#ifdef CONTAINER_STATS
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
DELETEARRAY(mEntries);
mCurNbEntries = mMaxNbEntries = 0;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resizes the container.
* \param needed [in] assume the container can be added at least "needed" values
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Resize(udword needed)
{
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get more entries
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
// Get some bytes for new entries
udword* NewEntries = new udword[mMaxNbEntries];
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data if needed
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
DELETEARRAY(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::SetSize(udword nb)
{
// Make sure it's empty
Empty();
// Checkings
if(!nb) return false;
// Initialize for nb entries
mMaxNbEntries = nb;
// Get some bytes for new entries
mEntries = new udword[mMaxNbEntries];
CHECKALLOC(mEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Refit()
{
#ifdef CONTAINER_STATS
// Subtract previous amount of bytes
mUsedRam-=mMaxNbEntries*sizeof(udword);
#endif
// Get just enough entries
mMaxNbEntries = mCurNbEntries;
if(!mMaxNbEntries) return false;
// Get just enough bytes
udword* NewEntries = new udword[mMaxNbEntries];
CHECKALLOC(NewEntries);
#ifdef CONTAINER_STATS
// Add current amount of bytes
mUsedRam+=mMaxNbEntries*sizeof(udword);
#endif
// Copy old data
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
// Delete old data
DELETEARRAY(mEntries);
// Assign new pointer
mEntries = NewEntries;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the container already contains a given value.
* \param entry [in] the value to look for in the container
* \param location [out] a possible pointer to store the entry location
* \see Add(udword entry)
* \see Add(float entry)
* \see Empty()
* \return true if the value has been found in the container, else false.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Contains(udword entry, udword* location) const
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
if(location) *location = i;
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::Delete(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
DeleteIndex(i);
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
* \param entry [in] the value to delete.
* \return true if the value has been found in the container, else false.
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Container::DeleteKeepingOrder(udword entry)
{
// Look for the entry
for(udword i=0;i<mCurNbEntries;i++)
{
if(mEntries[i]==entry)
{
// Entry has been found at index i.
// Shift entries to preserve order. You really should use a linked list instead.
mCurNbEntries--;
for(udword j=i;j<mCurNbEntries;j++)
{
mEntries[j] = mEntries[j+1];
}
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the next entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the next entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindNext(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location++;
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the previous entry, starting from input one.
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
* \param find_mode [in] wrap/clamp
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Container::FindPrev(udword& entry, FindMode find_mode)
{
udword Location;
if(Contains(entry, &Location))
{
Location--;
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
entry = mEntries[Location];
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the ram used by the container.
* \return the ram used in bytes.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Container::GetUsedRam() const
{
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
}
void Container::operator=(const Container& object)
{
SetSize(object.GetNbEntries());
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
mCurNbEntries = mMaxNbEntries;
}

View File

@@ -1,228 +1,228 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICECONTAINER_H__
#define __ICECONTAINER_H__
#define CONTAINER_STATS
enum FindMode
{
FIND_CLAMP,
FIND_WRAP,
FIND_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API Container
{
public:
// Constructor / Destructor
Container();
Container(const Container& object);
Container(udword size, float growth_factor);
~Container();
// Management
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a udword to store in the container
* \see Add(float entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(udword entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = entry;
return *this;
}
inline_ Container& Add(const udword* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
mCurNbEntries+=nb;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a float to store in the container
* \see Add(udword entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(float entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = IR(entry);
return *this;
}
inline_ Container& Add(const float* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float));
mCurNbEntries+=nb;
return *this;
}
//! Add unique [slow]
inline_ Container& AddUnique(udword entry)
{
if(!Contains(entry)) Add(entry);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Empty();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again.
* That's a kind of temporal coherence.
* \see Empty()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Reset()
{
// Avoid the write if possible
// ### CMOV
if(mCurNbEntries) mCurNbEntries = 0;
}
// HANDLE WITH CARE
inline_ void ForceSize(udword size)
{
mCurNbEntries = size;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetSize(udword nb);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Refit();
// Checks whether the container already contains a given value.
bool Contains(udword entry, udword* location=null) const;
// Deletes an entry - doesn't preserve insertion order.
bool Delete(udword entry);
// Deletes an entry - does preserve insertion order.
bool DeleteKeepingOrder(udword entry);
//! Deletes the very last entry.
inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; }
//! Deletes the entry whose index is given
inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; }
// Helpers
Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP);
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
// Data access.
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
inline_ udword GetFirst() const { return mEntries[0]; }
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
// Growth control
inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor
inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
//! Read-access as an array
inline_ udword operator[](udword i) const { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
//! Write-access as an array
inline_ udword& operator[](udword i) { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
// Stats
udword GetUsedRam() const;
//! Operator for "Container A = Container B"
void operator = (const Container& object);
#ifdef CONTAINER_STATS
inline_ udword GetNbContainers() const { return mNbContainers; }
inline_ udword GetTotalBytes() const { return mUsedRam; }
private:
static udword mNbContainers; //!< Number of containers around
static udword mUsedRam; //!< Amount of bytes used by containers in the system
#endif
private:
// Resizing
bool Resize(udword needed=1);
// Data
udword mMaxNbEntries; //!< Maximum possible number of entries
udword mCurNbEntries; //!< Current number of entries
udword* mEntries; //!< List of entries
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
};
#endif // __ICECONTAINER_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a simple container class.
* \file IceContainer.h
* \author Pierre Terdiman
* \date February, 5, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICECONTAINER_H__
#define __ICECONTAINER_H__
#define CONTAINER_STATS
enum FindMode
{
FIND_CLAMP,
FIND_WRAP,
FIND_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API Container
{
public:
// Constructor / Destructor
Container();
Container(const Container& object);
Container(udword size, float growth_factor);
~Container();
// Management
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a udword to store in the container
* \see Add(float entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(udword entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = entry;
return *this;
}
inline_ Container& Add(const udword* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
mCurNbEntries+=nb;
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A O(1) method to add a value in the container. The container is automatically resized if needed.
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
* costs a lot more than the call overhead...
*
* \param entry [in] a float to store in the container
* \see Add(udword entry)
* \see Empty()
* \see Contains(udword entry)
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ Container& Add(float entry)
{
// Resize if needed
if(mCurNbEntries==mMaxNbEntries) Resize();
// Add new entry
mEntries[mCurNbEntries++] = IR(entry);
return *this;
}
inline_ Container& Add(const float* entries, udword nb)
{
// Resize if needed
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
// Add new entry
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float));
mCurNbEntries+=nb;
return *this;
}
//! Add unique [slow]
inline_ Container& AddUnique(udword entry)
{
if(!Contains(entry)) Add(entry);
return *this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Clears the container. All stored values are deleted, and it frees used ram.
* \see Reset()
* \return Self-Reference
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Container& Empty();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again.
* That's a kind of temporal coherence.
* \see Empty()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Reset()
{
// Avoid the write if possible
// ### CMOV
if(mCurNbEntries) mCurNbEntries = 0;
}
// HANDLE WITH CARE
inline_ void ForceSize(udword size)
{
mCurNbEntries = size;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the initial size of the container. If it already contains something, it's discarded.
* \param nb [in] Number of entries
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetSize(udword nb);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the container and get rid of unused bytes.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Refit();
// Checks whether the container already contains a given value.
bool Contains(udword entry, udword* location=null) const;
// Deletes an entry - doesn't preserve insertion order.
bool Delete(udword entry);
// Deletes an entry - does preserve insertion order.
bool DeleteKeepingOrder(udword entry);
//! Deletes the very last entry.
inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; }
//! Deletes the entry whose index is given
inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; }
// Helpers
Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP);
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
// Data access.
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
inline_ udword GetFirst() const { return mEntries[0]; }
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
// Growth control
inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor
inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
//! Read-access as an array
inline_ udword operator[](udword i) const { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
//! Write-access as an array
inline_ udword& operator[](udword i) { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
// Stats
udword GetUsedRam() const;
//! Operator for "Container A = Container B"
void operator = (const Container& object);
#ifdef CONTAINER_STATS
inline_ udword GetNbContainers() const { return mNbContainers; }
inline_ udword GetTotalBytes() const { return mUsedRam; }
private:
static udword mNbContainers; //!< Number of containers around
static udword mUsedRam; //!< Amount of bytes used by containers in the system
#endif
private:
// Resizing
bool Resize(udword needed=1);
// Data
udword mMaxNbEntries; //!< Maximum possible number of entries
udword mCurNbEntries; //!< Current number of entries
udword* mEntries; //!< List of entries
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
};
#endif // __ICECONTAINER_H__

View File

@@ -1,333 +1,333 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains FPU related code.
* \file IceFPU.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEFPU_H__
#define __ICEFPU_H__
#define SIGN_BITMASK 0x80000000
//! Integer representation of a floating-point value.
#define IR(x) ((udword&)(x))
//! Signed integer representation of a floating-point value.
#define SIR(x) ((sdword&)(x))
//! Absolute integer representation of a floating-point value
#define AIR(x) (IR(x)&0x7fffffff)
//! Floating-point representation of an integer value.
#define FR(x) ((float&)(x))
//! Integer-based comparison of a floating point value.
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
//! Fast fabs for floating-point values. It just clears the sign bit.
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
inline_ float FastFabs(float x)
{
udword FloatBits = IR(x)&0x7fffffff;
return FR(FloatBits);
}
//! Fast square root for floating-point values.
inline_ float FastSqrt(float square)
{
float retval;
__asm {
mov eax, square
sub eax, 0x3F800000
sar eax, 1
add eax, 0x3F800000
mov [retval], eax
}
return retval;
}
//! Saturates positive to zero.
inline_ float fsat(float f)
{
udword y = (udword&)f & ~((sdword&)f >>31);
return (float&)y;
}
//! Computes 1.0f / sqrtf(x).
inline_ float frsqrt(float f)
{
float x = f * 0.5f;
udword y = 0x5f3759df - ((udword&)f >> 1);
// Iteration...
(float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) );
// Result
return (float&)y;
}
//! Computes 1.0f / sqrtf(x). Comes from NVIDIA.
inline_ float InvSqrt(const float& x)
{
udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1;
float y = *(float*)&tmp;
return y * (1.47f - 0.47f * x * y * y);
}
//! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above.
//! See http://www.magic-software.com/3DGEDInvSqrt.html
inline_ float RSqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = * (long *) &y;
i = 0x5f3759df - (i >> 1);
y = * (float *) &i;
y = y * (threehalfs - (x2 * y * y));
return y;
}
//! TO BE DOCUMENTED
inline_ float fsqrt(float f)
{
udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000;
// Iteration...?
// (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f;
// Result
return (float&)y;
}
//! Returns the float ranged espilon value.
inline_ float fepsilon(float f)
{
udword b = (udword&)f & 0xff800000;
udword a = b | 0x00000001;
(float&)a -= (float&)b;
// Result
return (float&)a;
}
//! Is the float valid ?
inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; }
inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; }
inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; }
inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; }
inline_ bool IsValidFloat(float value)
{
if(IsNAN(value)) return false;
if(IsIndeterminate(value)) return false;
if(IsPlusInf(value)) return false;
if(IsMinusInf(value)) return false;
return true;
}
#define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x));
/*
//! FPU precision setting function.
inline_ void SetFPU()
{
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.
{
uword wTemp, wSave;
__asm fstcw wSave
if (wSave & 0x300 || // Not single mode
0x3f != (wSave & 0x3f) || // Exceptions enabled
wSave & 0xC00) // Not round to nearest mode
{
__asm
{
mov ax, wSave
and ax, not 300h ;; single mode
or ax, 3fh ;; disable all exceptions
and ax, not 0xC00 ;; round to nearest mode
mov wTemp, ax
fldcw wTemp
}
}
}
}
*/
//! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON)
inline_ float ComputeFloatEpsilon()
{
float f = 1.0f;
((udword&)f)^=1;
return f - 1.0f; // You can check it's the same as FLT_EPSILON
}
inline_ bool IsFloatZero(float x, float epsilon=1e-6f)
{
return x*x < epsilon;
}
#define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0
#define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0
#define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0
#define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0
#define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1
#define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1
#define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1
#define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1
#define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2
#define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2
#define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2
#define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2
#define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3
#define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3
#define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3
#define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3
#define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4
#define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4
#define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4
#define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4
#define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5
#define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5
#define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5
#define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5
#define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6
#define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6
#define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6
#define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6
#define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7
#define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7
#define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7
#define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7
//! A global function to find MAX(a,b) using FCOMI/FCMOV
inline_ float FCMax2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b) using FCOMI/FCMOV
inline_ float FCMin2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVNB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MAX(a,b,c) using FCOMI/FCMOV
inline_ float FCMax3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MIN(a,b,c) using FCOMI/FCMOV
inline_ float FCMin3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
inline_ int ConvertToSortable(float f)
{
int& Fi = (int&)f;
int Fmask = (Fi>>31);
Fi ^= Fmask;
Fmask &= ~(1<<31);
Fi -= Fmask;
return Fi;
}
enum FPUMode
{
FPU_FLOOR = 0,
FPU_CEIL = 1,
FPU_BEST = 2,
FPU_FORCE_DWORD = 0x7fffffff
};
FUNCTION ICECORE_API FPUMode GetFPUMode();
FUNCTION ICECORE_API void SaveFPU();
FUNCTION ICECORE_API void RestoreFPU();
FUNCTION ICECORE_API void SetFPUFloorMode();
FUNCTION ICECORE_API void SetFPUCeilMode();
FUNCTION ICECORE_API void SetFPUBestMode();
FUNCTION ICECORE_API void SetFPUPrecision24();
FUNCTION ICECORE_API void SetFPUPrecision53();
FUNCTION ICECORE_API void SetFPUPrecision64();
FUNCTION ICECORE_API void SetFPURoundingChop();
FUNCTION ICECORE_API void SetFPURoundingUp();
FUNCTION ICECORE_API void SetFPURoundingDown();
FUNCTION ICECORE_API void SetFPURoundingNear();
FUNCTION ICECORE_API int intChop(const float& f);
FUNCTION ICECORE_API int intFloor(const float& f);
FUNCTION ICECORE_API int intCeil(const float& f);
#endif // __ICEFPU_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains FPU related code.
* \file IceFPU.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEFPU_H__
#define __ICEFPU_H__
#define SIGN_BITMASK 0x80000000
//! Integer representation of a floating-point value.
#define IR(x) ((udword&)(x))
//! Signed integer representation of a floating-point value.
#define SIR(x) ((sdword&)(x))
//! Absolute integer representation of a floating-point value
#define AIR(x) (IR(x)&0x7fffffff)
//! Floating-point representation of an integer value.
#define FR(x) ((float&)(x))
//! Integer-based comparison of a floating point value.
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
//! Fast fabs for floating-point values. It just clears the sign bit.
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
inline_ float FastFabs(float x)
{
udword FloatBits = IR(x)&0x7fffffff;
return FR(FloatBits);
}
//! Fast square root for floating-point values.
inline_ float FastSqrt(float square)
{
float retval;
__asm {
mov eax, square
sub eax, 0x3F800000
sar eax, 1
add eax, 0x3F800000
mov [retval], eax
}
return retval;
}
//! Saturates positive to zero.
inline_ float fsat(float f)
{
udword y = (udword&)f & ~((sdword&)f >>31);
return (float&)y;
}
//! Computes 1.0f / sqrtf(x).
inline_ float frsqrt(float f)
{
float x = f * 0.5f;
udword y = 0x5f3759df - ((udword&)f >> 1);
// Iteration...
(float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) );
// Result
return (float&)y;
}
//! Computes 1.0f / sqrtf(x). Comes from NVIDIA.
inline_ float InvSqrt(const float& x)
{
udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1;
float y = *(float*)&tmp;
return y * (1.47f - 0.47f * x * y * y);
}
//! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above.
//! See http://www.magic-software.com/3DGEDInvSqrt.html
inline_ float RSqrt(float number)
{
long i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = * (long *) &y;
i = 0x5f3759df - (i >> 1);
y = * (float *) &i;
y = y * (threehalfs - (x2 * y * y));
return y;
}
//! TO BE DOCUMENTED
inline_ float fsqrt(float f)
{
udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000;
// Iteration...?
// (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f;
// Result
return (float&)y;
}
//! Returns the float ranged espilon value.
inline_ float fepsilon(float f)
{
udword b = (udword&)f & 0xff800000;
udword a = b | 0x00000001;
(float&)a -= (float&)b;
// Result
return (float&)a;
}
//! Is the float valid ?
inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; }
inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; }
inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; }
inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; }
inline_ bool IsValidFloat(float value)
{
if(IsNAN(value)) return false;
if(IsIndeterminate(value)) return false;
if(IsPlusInf(value)) return false;
if(IsMinusInf(value)) return false;
return true;
}
#define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x));
/*
//! FPU precision setting function.
inline_ void SetFPU()
{
// This function evaluates whether the floating-point
// control word is set to single precision/round to nearest/
// exceptions disabled. If these conditions don't hold, the
// function changes the control word to set them and returns
// TRUE, putting the old control word value in the passback
// location pointed to by pwOldCW.
{
uword wTemp, wSave;
__asm fstcw wSave
if (wSave & 0x300 || // Not single mode
0x3f != (wSave & 0x3f) || // Exceptions enabled
wSave & 0xC00) // Not round to nearest mode
{
__asm
{
mov ax, wSave
and ax, not 300h ;; single mode
or ax, 3fh ;; disable all exceptions
and ax, not 0xC00 ;; round to nearest mode
mov wTemp, ax
fldcw wTemp
}
}
}
}
*/
//! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON)
inline_ float ComputeFloatEpsilon()
{
float f = 1.0f;
((udword&)f)^=1;
return f - 1.0f; // You can check it's the same as FLT_EPSILON
}
inline_ bool IsFloatZero(float x, float epsilon=1e-6f)
{
return x*x < epsilon;
}
#define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0
#define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0
#define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0
#define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0
#define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1
#define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1
#define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1
#define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1
#define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2
#define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2
#define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2
#define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2
#define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3
#define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3
#define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3
#define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3
#define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4
#define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4
#define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4
#define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4
#define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5
#define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5
#define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5
#define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5
#define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6
#define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6
#define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6
#define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6
#define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7
#define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7
#define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7
#define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7
//! A global function to find MAX(a,b) using FCOMI/FCMOV
inline_ float FCMax2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MIN(a,b) using FCOMI/FCMOV
inline_ float FCMin2(float a, float b)
{
float Res;
_asm fld [a]
_asm fld [b]
FCOMI_ST1
FCMOVNB_ST1
_asm fstp [Res]
_asm fcomp
return Res;
}
//! A global function to find MAX(a,b,c) using FCOMI/FCMOV
inline_ float FCMax3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVB_ST1
FCOMI_ST2
FCMOVB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
//! A global function to find MIN(a,b,c) using FCOMI/FCMOV
inline_ float FCMin3(float a, float b, float c)
{
float Res;
_asm fld [a]
_asm fld [b]
_asm fld [c]
FCOMI_ST1
FCMOVNB_ST1
FCOMI_ST2
FCMOVNB_ST2
_asm fstp [Res]
_asm fcompp
return Res;
}
inline_ int ConvertToSortable(float f)
{
int& Fi = (int&)f;
int Fmask = (Fi>>31);
Fi ^= Fmask;
Fmask &= ~(1<<31);
Fi -= Fmask;
return Fi;
}
enum FPUMode
{
FPU_FLOOR = 0,
FPU_CEIL = 1,
FPU_BEST = 2,
FPU_FORCE_DWORD = 0x7fffffff
};
FUNCTION ICECORE_API FPUMode GetFPUMode();
FUNCTION ICECORE_API void SaveFPU();
FUNCTION ICECORE_API void RestoreFPU();
FUNCTION ICECORE_API void SetFPUFloorMode();
FUNCTION ICECORE_API void SetFPUCeilMode();
FUNCTION ICECORE_API void SetFPUBestMode();
FUNCTION ICECORE_API void SetFPUPrecision24();
FUNCTION ICECORE_API void SetFPUPrecision53();
FUNCTION ICECORE_API void SetFPUPrecision64();
FUNCTION ICECORE_API void SetFPURoundingChop();
FUNCTION ICECORE_API void SetFPURoundingUp();
FUNCTION ICECORE_API void SetFPURoundingDown();
FUNCTION ICECORE_API void SetFPURoundingNear();
FUNCTION ICECORE_API int intChop(const float& f);
FUNCTION ICECORE_API int intFloor(const float& f);
FUNCTION ICECORE_API int intCeil(const float& f);
#endif // __ICEFPU_H__

View File

@@ -1,121 +1,121 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains all memory macros.
* \file IceMemoryMacros.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEMEMORYMACROS_H__
#define __ICEMEMORYMACROS_H__
#undef ZeroMemory
#undef CopyMemory
#undef MoveMemory
#undef FillMemory
//! Clears a buffer.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
//! \see MoveMemory
inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); }
//! Fills a buffer with a given byte.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \param val [in] the byte value
//! \see StoreDwords
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); }
//! Fills a buffer with a given dword.
//! \param addr [in] buffer address
//! \param nb [in] number of dwords to write
//! \param value [in] the dword value
//! \see FillMemory
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
//! \warning writes nb*4 bytes !
inline_ void StoreDwords(udword* dest, udword nb, udword value)
{
// The asm code below **SHOULD** be equivalent to one of those C versions
// or the other if your compiled is good: (checked on VC++ 6.0)
//
// 1) while(nb--) *dest++ = value;
//
// 2) for(udword i=0;i<nb;i++) dest[i] = value;
//
_asm push eax
_asm push ecx
_asm push edi
_asm mov edi, dest
_asm mov ecx, nb
_asm mov eax, value
_asm rep stosd
_asm pop edi
_asm pop ecx
_asm pop eax
}
//! Copies a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see MoveMemory
inline_ void CopyMemory(void* dest, const void* src, udword size) { memcpy(dest, src, size); }
//! Moves a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
inline_ void MoveMemory(void* dest, const void* src, udword size) { memmove(dest, src, size); }
#define SIZEOFOBJECT sizeof(*this) //!< Gives the size of current object. Avoid some mistakes (e.g. "sizeof(this)").
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); } //!< Clears current object. Laziness is my business. HANDLE WITH CARE.
#define DELETESINGLE(x) if (x) { delete x; x = null; } //!< Deletes an instance of a class.
#define DELETEARRAY(x) if (x) { delete []x; x = null; } //!< Deletes an array.
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; } //!< Safe D3D-style release
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release
#ifdef __ICEERROR_H__
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE.
#else
#define CHECKALLOC(x) if(!x) return false;
#endif
//! Standard allocation cycle
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
#endif // __ICEMEMORYMACROS_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains all memory macros.
* \file IceMemoryMacros.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEMEMORYMACROS_H__
#define __ICEMEMORYMACROS_H__
#undef ZeroMemory
#undef CopyMemory
#undef MoveMemory
#undef FillMemory
//! Clears a buffer.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
//! \see MoveMemory
inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); }
//! Fills a buffer with a given byte.
//! \param addr [in] buffer address
//! \param size [in] buffer length
//! \param val [in] the byte value
//! \see StoreDwords
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); }
//! Fills a buffer with a given dword.
//! \param addr [in] buffer address
//! \param nb [in] number of dwords to write
//! \param value [in] the dword value
//! \see FillMemory
//! \see ZeroMemory
//! \see CopyMemory
//! \see MoveMemory
//! \warning writes nb*4 bytes !
inline_ void StoreDwords(udword* dest, udword nb, udword value)
{
// The asm code below **SHOULD** be equivalent to one of those C versions
// or the other if your compiled is good: (checked on VC++ 6.0)
//
// 1) while(nb--) *dest++ = value;
//
// 2) for(udword i=0;i<nb;i++) dest[i] = value;
//
_asm push eax
_asm push ecx
_asm push edi
_asm mov edi, dest
_asm mov ecx, nb
_asm mov eax, value
_asm rep stosd
_asm pop edi
_asm pop ecx
_asm pop eax
}
//! Copies a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see MoveMemory
inline_ void CopyMemory(void* dest, const void* src, udword size) { memcpy(dest, src, size); }
//! Moves a buffer.
//! \param addr [in] destination buffer address
//! \param addr [in] source buffer address
//! \param size [in] buffer length
//! \see ZeroMemory
//! \see FillMemory
//! \see StoreDwords
//! \see CopyMemory
inline_ void MoveMemory(void* dest, const void* src, udword size) { memmove(dest, src, size); }
#define SIZEOFOBJECT sizeof(*this) //!< Gives the size of current object. Avoid some mistakes (e.g. "sizeof(this)").
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); } //!< Clears current object. Laziness is my business. HANDLE WITH CARE.
#define DELETESINGLE(x) if (x) { delete x; x = null; } //!< Deletes an instance of a class.
#define DELETEARRAY(x) if (x) { delete []x; x = null; } //!< Deletes an array.
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; } //!< Safe D3D-style release
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release
#ifdef __ICEERROR_H__
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE.
#else
#define CHECKALLOC(x) if(!x) return false;
#endif
//! Standard allocation cycle
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
#endif // __ICEMEMORYMACROS_H__

View File

@@ -1,144 +1,144 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains preprocessor stuff. This should be the first included header.
* \file IcePreprocessor.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPREPROCESSOR_H__
#define __ICEPREPROCESSOR_H__
// Check platform
#if defined( _WIN32 ) || defined( WIN32 )
#pragma message("Compiling on Windows...")
#define PLATFORM_WINDOWS
#else
#pragma message("Compiling on unknown platform...")
#endif
// Check compiler
#if defined(_MSC_VER)
#pragma message("Compiling with VC++...")
#define COMPILER_VISUAL_CPP
#else
#pragma message("Compiling with unknown compiler...")
#endif
// Check compiler options. If this file is included in user-apps, this
// shouldn't be needed, so that they can use what they like best.
#ifndef ICE_DONT_CHECK_COMPILER_OPTIONS
#ifdef COMPILER_VISUAL_CPP
#if defined(_CHAR_UNSIGNED)
#endif
#if defined(_CPPRTTI)
#error Please disable RTTI...
#endif
#if defined(_CPPUNWIND)
#error Please disable exceptions...
#endif
#if defined(_MT)
// Multithreading
#endif
#endif
#endif
// Check debug mode
#ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it.
#ifndef _DEBUG
#define _DEBUG
#endif
#endif
#ifdef _DEBUG
// Here you may define items for debug builds
#endif
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
#ifndef ICE_NO_DLL
#ifdef ICECORE_EXPORTS
#define ICECORE_API __declspec(dllexport)
#else
#define ICECORE_API __declspec(dllimport)
#endif
#else
#define ICECORE_API
#endif
// Don't override new/delete
// #define DEFAULT_NEWDELETE
#define DONT_TRACK_MEMORY_LEAKS
#define FUNCTION extern "C"
// Cosmetic stuff [mainly useful with multiple inheritance]
#define override(base_class) virtual
// Our own inline keyword, so that:
// - we can switch to __forceinline to check it's really better or not
// - we can remove __forceinline if the compiler doesn't support it
// #define inline_ __forceinline
// #define inline_ inline
// Contributed by Bruce Mitchener
#if defined(COMPILER_VISUAL_CPP)
#define inline_ __forceinline
// #define inline_ inline
#elif defined(__GNUC__) && __GNUC__ < 3
#define inline_ inline
#elif defined(__GNUC__)
#define inline_ inline __attribute__ ((always_inline))
#else
#define inline_ inline
#endif
// Down the hatch
#pragma inline_depth( 255 )
#ifdef COMPILER_VISUAL_CPP
#pragma intrinsic(memcmp)
#pragma intrinsic(memcpy)
#pragma intrinsic(memset)
#pragma intrinsic(strcat)
#pragma intrinsic(strcmp)
#pragma intrinsic(strcpy)
#pragma intrinsic(strlen)
#pragma intrinsic(abs)
#pragma intrinsic(labs)
#endif
// ANSI compliance
#ifdef _DEBUG
// Remove painful warning in debug
inline_ bool __False__(){ return false; }
#define for if(__False__()){} else for
#else
#define for if(0){} else for
#endif
#endif // __ICEPREPROCESSOR_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains preprocessor stuff. This should be the first included header.
* \file IcePreprocessor.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEPREPROCESSOR_H__
#define __ICEPREPROCESSOR_H__
// Check platform
#if defined( _WIN32 ) || defined( WIN32 )
#pragma message("Compiling on Windows...")
#define PLATFORM_WINDOWS
#else
#pragma message("Compiling on unknown platform...")
#endif
// Check compiler
#if defined(_MSC_VER)
#pragma message("Compiling with VC++...")
#define COMPILER_VISUAL_CPP
#else
#pragma message("Compiling with unknown compiler...")
#endif
// Check compiler options. If this file is included in user-apps, this
// shouldn't be needed, so that they can use what they like best.
#ifndef ICE_DONT_CHECK_COMPILER_OPTIONS
#ifdef COMPILER_VISUAL_CPP
#if defined(_CHAR_UNSIGNED)
#endif
#if defined(_CPPRTTI)
#error Please disable RTTI...
#endif
#if defined(_CPPUNWIND)
#error Please disable exceptions...
#endif
#if defined(_MT)
// Multithreading
#endif
#endif
#endif
// Check debug mode
#ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it.
#ifndef _DEBUG
#define _DEBUG
#endif
#endif
#ifdef _DEBUG
// Here you may define items for debug builds
#endif
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
#ifndef ICE_NO_DLL
#ifdef ICECORE_EXPORTS
#define ICECORE_API __declspec(dllexport)
#else
#define ICECORE_API __declspec(dllimport)
#endif
#else
#define ICECORE_API
#endif
// Don't override new/delete
// #define DEFAULT_NEWDELETE
#define DONT_TRACK_MEMORY_LEAKS
#define FUNCTION extern "C"
// Cosmetic stuff [mainly useful with multiple inheritance]
#define override(base_class) virtual
// Our own inline keyword, so that:
// - we can switch to __forceinline to check it's really better or not
// - we can remove __forceinline if the compiler doesn't support it
// #define inline_ __forceinline
// #define inline_ inline
// Contributed by Bruce Mitchener
#if defined(COMPILER_VISUAL_CPP)
#define inline_ __forceinline
// #define inline_ inline
#elif defined(__GNUC__) && __GNUC__ < 3
#define inline_ inline
#elif defined(__GNUC__)
#define inline_ inline __attribute__ ((always_inline))
#else
#define inline_ inline
#endif
// Down the hatch
#pragma inline_depth( 255 )
#ifdef COMPILER_VISUAL_CPP
#pragma intrinsic(memcmp)
#pragma intrinsic(memcpy)
#pragma intrinsic(memset)
#pragma intrinsic(strcat)
#pragma intrinsic(strcmp)
#pragma intrinsic(strcpy)
#pragma intrinsic(strlen)
#pragma intrinsic(abs)
#pragma intrinsic(labs)
#endif
// ANSI compliance
#ifdef _DEBUG
// Remove painful warning in debug
inline_ bool __False__(){ return false; }
#define for if(__False__()){} else for
#else
#define for if(0){} else for
#endif
#endif // __ICEPREPROCESSOR_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +1,81 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains source code from the article "Radix Sort Revisited".
* \file IceRevisitedRadix.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERADIXSORT_H__
#define __ICERADIXSORT_H__
//! Allocate histograms & offsets locally
#define RADIX_LOCAL_RAM
enum RadixHint
{
RADIX_SIGNED, //!< Input values are signed
RADIX_UNSIGNED, //!< Input values are unsigned
RADIX_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API RadixSort
{
public:
// Constructor/Destructor
RadixSort();
~RadixSort();
// Sorting methods
RadixSort& Sort(const udword* input, udword nb, RadixHint hint=RADIX_SIGNED);
RadixSort& Sort(const float* input, udword nb);
//! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
inline_ const udword* GetRanks() const { return mRanks; }
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
inline_ udword* GetRecyclable() const { return mRanks2; }
// Stats
udword GetUsedRam() const;
//! Returns the total number of calls to the radix sorter.
inline_ udword GetNbTotalCalls() const { return mTotalCalls; }
//! Returns the number of eraly exits due to temporal coherence.
inline_ udword GetNbHits() const { return mNbHits; }
private:
#ifndef RADIX_LOCAL_RAM
udword* mHistogram; //!< Counters for each byte
udword* mOffset; //!< Offsets (nearly a cumulative distribution function)
#endif
udword mCurrentSize; //!< Current size of the indices list
udword* mRanks; //!< Two lists, swapped each pass
udword* mRanks2;
// Stats
udword mTotalCalls; //!< Total number of calls to the sort routine
udword mNbHits; //!< Number of early exits due to coherence
// Internal methods
void CheckResize(udword nb);
bool Resize(udword nb);
};
#endif // __ICERADIXSORT_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains source code from the article "Radix Sort Revisited".
* \file IceRevisitedRadix.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICERADIXSORT_H__
#define __ICERADIXSORT_H__
//! Allocate histograms & offsets locally
#define RADIX_LOCAL_RAM
enum RadixHint
{
RADIX_SIGNED, //!< Input values are signed
RADIX_UNSIGNED, //!< Input values are unsigned
RADIX_FORCE_DWORD = 0x7fffffff
};
class ICECORE_API RadixSort
{
public:
// Constructor/Destructor
RadixSort();
~RadixSort();
// Sorting methods
RadixSort& Sort(const udword* input, udword nb, RadixHint hint=RADIX_SIGNED);
RadixSort& Sort(const float* input, udword nb);
//! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
inline_ const udword* GetRanks() const { return mRanks; }
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
inline_ udword* GetRecyclable() const { return mRanks2; }
// Stats
udword GetUsedRam() const;
//! Returns the total number of calls to the radix sorter.
inline_ udword GetNbTotalCalls() const { return mTotalCalls; }
//! Returns the number of eraly exits due to temporal coherence.
inline_ udword GetNbHits() const { return mNbHits; }
private:
#ifndef RADIX_LOCAL_RAM
udword* mHistogram; //!< Counters for each byte
udword* mOffset; //!< Offsets (nearly a cumulative distribution function)
#endif
udword mCurrentSize; //!< Current size of the indices list
udword* mRanks; //!< Two lists, swapped each pass
udword* mRanks2;
// Stats
udword mTotalCalls; //!< Total number of calls to the sort routine
udword mNbHits; //!< Number of early exits due to coherence
// Internal methods
void CheckResize(udword nb);
bool Resize(udword nb);
};
#endif // __ICERADIXSORT_H__

View File

@@ -1,173 +1,173 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom types.
* \file IceTypes.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETYPES_H__
#define __ICETYPES_H__
#define USE_HANDLE_MANAGER
// Constants
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
#define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
#define EXP 2.71828182845904523536f //!< e
#define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2)
#define LN2 0.693147180559945f //!< ln(2)
#define INVLN2 1.44269504089f //!< 1.0f / ln(2)
#define INV3 0.33333333333333333333f //!< 1/3
#define INV6 0.16666666666666666666f //!< 1/6
#define INV7 0.14285714285714285714f //!< 1/7
#define INV9 0.11111111111111111111f //!< 1/9
#define INV255 0.00392156862745098039f //!< 1/255
#define SQRT2 1.41421356237f //!< sqrt(2)
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
#define SQRT3 1.73205080757f //!< sqrt(3)
#define INVSQRT3 0.577350269189f //!< 1 / sqrt(3)
#define null 0 //!< our own NULL pointer
// Custom types used in ICE
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
typedef signed short sword; //!< sizeof(sword) must be 2
typedef unsigned short uword; //!< sizeof(uword) must be 2
typedef signed int sdword; //!< sizeof(sdword) must be 4
typedef unsigned int udword; //!< sizeof(udword) must be 4
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
typedef float float32; //!< sizeof(float32) must be 4
typedef double float64; //!< sizeof(float64) must be 4
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
//! TO BE DOCUMENTED
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
typedef udword DynID; //!< Dynamic identifier
#ifdef USE_HANDLE_MANAGER
typedef udword KID; //!< Kernel ID
// DECLARE_ICE_HANDLE(KID);
#else
typedef uword KID; //!< Kernel ID
#endif
typedef udword RTYPE; //!< Relationship-type (!) between owners and references
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
#ifdef USE_HANDLE_MANAGER
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
#else
#define INVALID_KID 0xffff //!< Invalid Kernel ID
#endif
#define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value
// Define BOOL if needed
#ifndef BOOL
typedef int BOOL; //!< Another boolean type.
#endif
//! Union of a float and a sdword
typedef union {
float f; //!< The float
sdword d; //!< The integer
}scell;
//! Union of a float and a udword
typedef union {
float f; //!< The float
udword d; //!< The integer
}ucell;
// Type ranges
#define MAX_SBYTE 0x7f //!< max possible sbyte value
#define MIN_SBYTE 0x80 //!< min possible sbyte value
#define MAX_UBYTE 0xff //!< max possible ubyte value
#define MIN_UBYTE 0x00 //!< min possible ubyte value
#define MAX_SWORD 0x7fff //!< max possible sword value
#define MIN_SWORD 0x8000 //!< min possible sword value
#define MAX_UWORD 0xffff //!< max possible uword value
#define MIN_UWORD 0x0000 //!< min possible uword value
#define MAX_SDWORD 0x7fffffff //!< max possible sdword value
#define MIN_SDWORD 0x80000000 //!< min possible sdword value
#define MAX_UDWORD 0xffffffff //!< max possible udword value
#define MIN_UDWORD 0x00000000 //!< min possible udword value
#define MAX_FLOAT FLT_MAX //!< max possible float value
#define MIN_FLOAT (-FLT_MAX) //!< min possible loat value
#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0
#define IEEE_255_0 0x437f0000 //!< integer representation of 255.0
#define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT
#define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT
#define IEEE_UNDERFLOW_LIMIT 0x1a000000
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
typedef void** VTABLE; //!< A V-Table.
#undef MIN
#undef MAX
#define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b
#define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b
#define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c
template<class T> inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; }
template<class T> inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; }
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
#define SQR(x) ((x)*(x)) //!< Returns x square
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
#define AND & //!< ...
#define OR | //!< ...
#define XOR ^ //!< ...
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
#ifdef _WIN32
# define srand48(x) srand((unsigned int) (x))
# define srandom(x) srand((unsigned int) (x))
# define random() ((double) rand())
# define drand48() ((double) (((double) rand()) / ((double) RAND_MAX)))
#endif
#endif // __ICETYPES_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains custom types.
* \file IceTypes.h
* \author Pierre Terdiman
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICETYPES_H__
#define __ICETYPES_H__
#define USE_HANDLE_MANAGER
// Constants
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
#define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
#define EXP 2.71828182845904523536f //!< e
#define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2)
#define LN2 0.693147180559945f //!< ln(2)
#define INVLN2 1.44269504089f //!< 1.0f / ln(2)
#define INV3 0.33333333333333333333f //!< 1/3
#define INV6 0.16666666666666666666f //!< 1/6
#define INV7 0.14285714285714285714f //!< 1/7
#define INV9 0.11111111111111111111f //!< 1/9
#define INV255 0.00392156862745098039f //!< 1/255
#define SQRT2 1.41421356237f //!< sqrt(2)
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
#define SQRT3 1.73205080757f //!< sqrt(3)
#define INVSQRT3 0.577350269189f //!< 1 / sqrt(3)
#define null 0 //!< our own NULL pointer
// Custom types used in ICE
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
typedef signed short sword; //!< sizeof(sword) must be 2
typedef unsigned short uword; //!< sizeof(uword) must be 2
typedef signed int sdword; //!< sizeof(sdword) must be 4
typedef unsigned int udword; //!< sizeof(udword) must be 4
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
typedef float float32; //!< sizeof(float32) must be 4
typedef double float64; //!< sizeof(float64) must be 4
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1);
ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2);
ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
//! TO BE DOCUMENTED
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
typedef udword DynID; //!< Dynamic identifier
#ifdef USE_HANDLE_MANAGER
typedef udword KID; //!< Kernel ID
// DECLARE_ICE_HANDLE(KID);
#else
typedef uword KID; //!< Kernel ID
#endif
typedef udword RTYPE; //!< Relationship-type (!) between owners and references
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
#ifdef USE_HANDLE_MANAGER
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
#else
#define INVALID_KID 0xffff //!< Invalid Kernel ID
#endif
#define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value
// Define BOOL if needed
#ifndef BOOL
typedef int BOOL; //!< Another boolean type.
#endif
//! Union of a float and a sdword
typedef union {
float f; //!< The float
sdword d; //!< The integer
}scell;
//! Union of a float and a udword
typedef union {
float f; //!< The float
udword d; //!< The integer
}ucell;
// Type ranges
#define MAX_SBYTE 0x7f //!< max possible sbyte value
#define MIN_SBYTE 0x80 //!< min possible sbyte value
#define MAX_UBYTE 0xff //!< max possible ubyte value
#define MIN_UBYTE 0x00 //!< min possible ubyte value
#define MAX_SWORD 0x7fff //!< max possible sword value
#define MIN_SWORD 0x8000 //!< min possible sword value
#define MAX_UWORD 0xffff //!< max possible uword value
#define MIN_UWORD 0x0000 //!< min possible uword value
#define MAX_SDWORD 0x7fffffff //!< max possible sdword value
#define MIN_SDWORD 0x80000000 //!< min possible sdword value
#define MAX_UDWORD 0xffffffff //!< max possible udword value
#define MIN_UDWORD 0x00000000 //!< min possible udword value
#define MAX_FLOAT FLT_MAX //!< max possible float value
#define MIN_FLOAT (-FLT_MAX) //!< min possible loat value
#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0
#define IEEE_255_0 0x437f0000 //!< integer representation of 255.0
#define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT
#define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT
#define IEEE_UNDERFLOW_LIMIT 0x1a000000
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
typedef void** VTABLE; //!< A V-Table.
#undef MIN
#undef MAX
#define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b
#define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b
#define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c
template<class T> inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; }
template<class T> inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; }
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
#define SQR(x) ((x)*(x)) //!< Returns x square
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
#define AND & //!< ...
#define OR | //!< ...
#define XOR ^ //!< ...
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
#ifdef _WIN32
# define srand48(x) srand((unsigned int) (x))
# define srandom(x) srand((unsigned int) (x))
# define random() ((double) rand())
# define drand48() ((double) (((double) rand()) / ((double) RAND_MAX)))
#endif
#endif // __ICETYPES_H__

View File

@@ -1,272 +1,272 @@
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.h
* \author Pierre Terdiman (collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEUTILS_H__
#define __ICEUTILS_H__
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
#define END_RUNONCE __RunOnce__ = true;}}
//! Reverse all the bits in a 32 bit word (from Steve Baker's Cute Code Collection)
//! (each line can be done in any order.
inline_ void ReverseBits(udword& n)
{
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
// Etc for larger intergers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
}
//! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection)
inline_ udword CountBits(udword n)
{
// This relies of the fact that the count of n bits can NOT overflow
// an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts
// 2 bit interger, 3 bit count requires only a 2 bit interger.
// So we add all bit pairs, then each nible, then each byte etc...
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
// Etc for larger intergers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
return n;
}
//! Even faster?
inline_ udword CountBits2(udword bits)
{
bits = bits - ((bits >> 1) & 0x55555555);
bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333);
bits = ((bits >> 4) + bits) & 0x0F0F0F0F;
return (bits * 0x01010101) >> 24;
}
//! Spread out bits. EG 00001111 -> 0101010101
//! 00001010 -> 0100010000
//! This is used to interleve to intergers to produce a `Morten Key'
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
//! Order is important.
inline_ void SpreadBits(udword& n)
{
n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16);
n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8);
n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4);
n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2);
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
}
// Next Largest Power of 2
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
// largest power of 2. For a 32-bit value:
inline_ udword nlpo2(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x+1;
}
//! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection)
inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); }
//! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection)
inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); }
//! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection)
inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<<n); }
//! Classic XOR swap (from Steve Baker's Cute Code Collection)
//! x ^= y; /* x' = (x^y) */
//! y ^= x; /* y' = (y^(x^y)) = x */
//! x ^= y; /* x' = (x^y)^x = y */
inline_ void Swap(udword& x, udword& y) { x ^= y; y ^= x; x ^= y; }
//! Little/Big endian (from Steve Baker's Cute Code Collection)
//!
//! Extra comments by Kenny Hoff:
//! Determines the byte-ordering of the current machine (little or big endian)
//! by setting an integer value to 1 (so least significant bit is now 1); take
//! the address of the int and cast to a byte pointer (treat integer as an
//! array of four bytes); check the value of the first byte (must be 0 or 1).
//! If the value is 1, then the first byte least significant byte and this
//! implies LITTLE endian. If the value is 0, the first byte is the most
//! significant byte, BIG endian. Examples:
//! integer 1 on BIG endian: 00000000 00000000 00000000 00000001
//! integer 1 on LITTLE endian: 00000001 00000000 00000000 00000000
//!---------------------------------------------------------------------------
//! int IsLittleEndian() { int x=1; return ( ((char*)(&x))[0] ); }
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
//!< Alternative abs function
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
//!< Alternative min function
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
// Determine if one of the bytes in a 4 byte word is zero
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
// Most Significant 1 Bit
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
// yields the most significant bit. For a 32-bit value:
inline_ udword msb32(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return (x & ~(x >> 1));
}
/*
"Just call it repeatedly with various input values and always with the same variable as "memory".
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
does no filtering at all.
I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed
to the more typical FIR (Finite Impulse Response).
Also, I'd say that you can make more intelligent and interesting filters than this, for example filters
that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter
to be applied before this one, of course."
(JCAB on Flipcode)
*/
inline_ float FeedbackFilter(float val, float& memory, float sharpness)
{
ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter");
if(sharpness<0.0f) sharpness = 0.0f;
else if(sharpness>1.0f) sharpness = 1.0f;
return memory = val * sharpness + memory * (1.0f - sharpness);
}
//! If you can guarantee that your input domain (i.e. value of x) is slightly
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
//! following code to clamp the resulting value into [-32768,+32767] range:
inline_ int ClampToInt16(int x)
{
// ASSERT(abs(x) < (int)((1<<31u)-32767));
int delta = 32767 - x;
x += (delta>>31) & delta;
delta = x + 32768;
x -= (delta>>31) & delta;
return x;
}
// Generic functions
template<class Type> inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; }
template<class Type> inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((x<lo) ? lo : (x>hi) ? hi : x); }
template<class Type> inline_ void TSort(Type& a, Type& b)
{
if(a>b) TSwap(a, b);
}
template<class Type> inline_ void TSort(Type& a, Type& b, Type& c)
{
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
}
// Prevent nasty user-manipulations (strategy borrowed from Charles Bloom)
// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); }
// ... actually this is better !
#define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object);
//! TO BE DOCUMENTED
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
//! TO BE DOCUMENTED
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION ICECORE_API udword Alignment(udword address);
#define IS_ALIGNED_2(x) ((x&1)==0)
#define IS_ALIGNED_4(x) ((x&3)==0)
#define IS_ALIGNED_8(x) ((x&7)==0)
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
// Compute implicit coords from an index:
// The idea is to get back 2D coords from a 1D index.
// For example:
//
// 0 1 2 ... nbu-1
// nbu nbu+1 i ...
//
// We have i, we're looking for the equivalent (u=2, v=1) location.
// i = u + v*nbu
// <=> i/nbu = u/nbu + v
// Since 0 <= u < nbu, u/nbu = 0 (integer)
// Hence: v = i/nbu
// Then we simply put it back in the original equation to compute u = i - v*nbu
inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu)
{
v = i / nbu;
u = i - (v * nbu);
}
// In 3D: i = u + v*nbu + w*nbu*nbv
// <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w
// u/(nbu*nbv) is null since u/nbu was null already.
// v/nbv is null as well for the same reason.
// Hence w = i/(nbu*nbv)
// Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu
inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv)
{
w = i / (nbu_nbv);
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
}
#endif // __ICEUTILS_H__
/*
* ICE / OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains misc. useful macros & defines.
* \file IceUtils.h
* \author Pierre Terdiman (collected from various sources)
* \date April, 4, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __ICEUTILS_H__
#define __ICEUTILS_H__
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
#define END_RUNONCE __RunOnce__ = true;}}
//! Reverse all the bits in a 32 bit word (from Steve Baker's Cute Code Collection)
//! (each line can be done in any order.
inline_ void ReverseBits(udword& n)
{
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
// Etc for larger intergers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
}
//! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection)
inline_ udword CountBits(udword n)
{
// This relies of the fact that the count of n bits can NOT overflow
// an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts
// 2 bit interger, 3 bit count requires only a 2 bit interger.
// So we add all bit pairs, then each nible, then each byte etc...
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
// Etc for larger intergers (64 bits in Java)
// NOTE: the >> operation must be unsigned! (>>> in java)
return n;
}
//! Even faster?
inline_ udword CountBits2(udword bits)
{
bits = bits - ((bits >> 1) & 0x55555555);
bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333);
bits = ((bits >> 4) + bits) & 0x0F0F0F0F;
return (bits * 0x01010101) >> 24;
}
//! Spread out bits. EG 00001111 -> 0101010101
//! 00001010 -> 0100010000
//! This is used to interleve to intergers to produce a `Morten Key'
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
//! Order is important.
inline_ void SpreadBits(udword& n)
{
n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16);
n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8);
n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4);
n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2);
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
}
// Next Largest Power of 2
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
// largest power of 2. For a 32-bit value:
inline_ udword nlpo2(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x+1;
}
//! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection)
inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); }
//! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection)
inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); }
//! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection)
inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<<n); }
//! Classic XOR swap (from Steve Baker's Cute Code Collection)
//! x ^= y; /* x' = (x^y) */
//! y ^= x; /* y' = (y^(x^y)) = x */
//! x ^= y; /* x' = (x^y)^x = y */
inline_ void Swap(udword& x, udword& y) { x ^= y; y ^= x; x ^= y; }
//! Little/Big endian (from Steve Baker's Cute Code Collection)
//!
//! Extra comments by Kenny Hoff:
//! Determines the byte-ordering of the current machine (little or big endian)
//! by setting an integer value to 1 (so least significant bit is now 1); take
//! the address of the int and cast to a byte pointer (treat integer as an
//! array of four bytes); check the value of the first byte (must be 0 or 1).
//! If the value is 1, then the first byte least significant byte and this
//! implies LITTLE endian. If the value is 0, the first byte is the most
//! significant byte, BIG endian. Examples:
//! integer 1 on BIG endian: 00000000 00000000 00000000 00000001
//! integer 1 on LITTLE endian: 00000001 00000000 00000000 00000000
//!---------------------------------------------------------------------------
//! int IsLittleEndian() { int x=1; return ( ((char*)(&x))[0] ); }
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
//!< Alternative abs function
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
//!< Alternative min function
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
// Determine if one of the bytes in a 4 byte word is zero
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
// Most Significant 1 Bit
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
// yields the most significant bit. For a 32-bit value:
inline_ udword msb32(udword x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return (x & ~(x >> 1));
}
/*
"Just call it repeatedly with various input values and always with the same variable as "memory".
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
does no filtering at all.
I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed
to the more typical FIR (Finite Impulse Response).
Also, I'd say that you can make more intelligent and interesting filters than this, for example filters
that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter
to be applied before this one, of course."
(JCAB on Flipcode)
*/
inline_ float FeedbackFilter(float val, float& memory, float sharpness)
{
ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter");
if(sharpness<0.0f) sharpness = 0.0f;
else if(sharpness>1.0f) sharpness = 1.0f;
return memory = val * sharpness + memory * (1.0f - sharpness);
}
//! If you can guarantee that your input domain (i.e. value of x) is slightly
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
//! following code to clamp the resulting value into [-32768,+32767] range:
inline_ int ClampToInt16(int x)
{
// ASSERT(abs(x) < (int)((1<<31u)-32767));
int delta = 32767 - x;
x += (delta>>31) & delta;
delta = x + 32768;
x -= (delta>>31) & delta;
return x;
}
// Generic functions
template<class Type> inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; }
template<class Type> inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((x<lo) ? lo : (x>hi) ? hi : x); }
template<class Type> inline_ void TSort(Type& a, Type& b)
{
if(a>b) TSwap(a, b);
}
template<class Type> inline_ void TSort(Type& a, Type& b, Type& c)
{
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
if(a>b) TSwap(a, b);
if(b>c) TSwap(b, c);
}
// Prevent nasty user-manipulations (strategy borrowed from Charles Bloom)
// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); }
// ... actually this is better !
#define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object);
//! TO BE DOCUMENTED
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
//! TO BE DOCUMENTED
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns the alignment of the input address.
* \fn Alignment()
* \param address [in] address to check
* \return the best alignment (e.g. 1 for odd addresses, etc)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FUNCTION ICECORE_API udword Alignment(udword address);
#define IS_ALIGNED_2(x) ((x&1)==0)
#define IS_ALIGNED_4(x) ((x&3)==0)
#define IS_ALIGNED_8(x) ((x&7)==0)
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
// Compute implicit coords from an index:
// The idea is to get back 2D coords from a 1D index.
// For example:
//
// 0 1 2 ... nbu-1
// nbu nbu+1 i ...
//
// We have i, we're looking for the equivalent (u=2, v=1) location.
// i = u + v*nbu
// <=> i/nbu = u/nbu + v
// Since 0 <= u < nbu, u/nbu = 0 (integer)
// Hence: v = i/nbu
// Then we simply put it back in the original equation to compute u = i - v*nbu
inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu)
{
v = i / nbu;
u = i - (v * nbu);
}
// In 3D: i = u + v*nbu + w*nbu*nbv
// <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w
// u/(nbu*nbv) is null since u/nbu was null already.
// v/nbv is null as well for the same reason.
// Hence w = i/(nbu*nbv)
// Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu
inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv)
{
w = i / (nbu_nbv);
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
}
#endif // __ICEUTILS_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +1,106 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an AABB collider.
* \file OPC_AABBCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_AABBCOLLIDER_H__
#define __OPC_AABBCOLLIDER_H__
struct OPCODE_API AABBCache : VolumeCache
{
AABBCache() : FatCoeff(1.1f)
{
FatBox.mCenter.Zero();
FatBox.mExtents.Zero();
}
// Cached faces signature
CollisionAABB FatBox; //!< Box used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere
};
class OPCODE_API AABBCollider : public VolumeCollider
{
public:
// Constructor / Destructor
AABBCollider();
virtual ~AABBCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a box cache
* \param box [in] collision AABB in world space
* \param model [in] Opcode model to collide with
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(AABBCache& cache, const CollisionAABB& box, const Model& model);
//
bool Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree);
protected:
CollisionAABB mBox; //!< Query box in (center, extents) form
Point mMin; //!< Query box min point
Point mMax; //!< Query box max point
// Leaf description
Point mLeafVerts[3]; //!< Triangle vertices
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL AABBContainsBox(const Point& bc, const Point& be);
inline_ BOOL AABBAABBOverlap(const Point& b, const Point& Pb);
inline_ BOOL TriBoxOverlap();
// Init methods
BOOL InitQuery(AABBCache& cache, const CollisionAABB& box);
};
class OPCODE_API HybridAABBCollider : public AABBCollider
{
public:
// Constructor / Destructor
HybridAABBCollider();
virtual ~HybridAABBCollider();
bool Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_AABBCOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an AABB collider.
* \file OPC_AABBCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_AABBCOLLIDER_H__
#define __OPC_AABBCOLLIDER_H__
struct OPCODE_API AABBCache : VolumeCache
{
AABBCache() : FatCoeff(1.1f)
{
FatBox.mCenter.Zero();
FatBox.mExtents.Zero();
}
// Cached faces signature
CollisionAABB FatBox; //!< Box used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere
};
class OPCODE_API AABBCollider : public VolumeCollider
{
public:
// Constructor / Destructor
AABBCollider();
virtual ~AABBCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a box cache
* \param box [in] collision AABB in world space
* \param model [in] Opcode model to collide with
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(AABBCache& cache, const CollisionAABB& box, const Model& model);
//
bool Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree);
protected:
CollisionAABB mBox; //!< Query box in (center, extents) form
Point mMin; //!< Query box min point
Point mMax; //!< Query box max point
// Leaf description
Point mLeafVerts[3]; //!< Triangle vertices
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL AABBContainsBox(const Point& bc, const Point& be);
inline_ BOOL AABBAABBOverlap(const Point& b, const Point& Pb);
inline_ BOOL TriBoxOverlap();
// Init methods
BOOL InitQuery(AABBCache& cache, const CollisionAABB& box);
};
class OPCODE_API HybridAABBCollider : public AABBCollider
{
public:
// Constructor / Destructor
HybridAABBCollider();
virtual ~HybridAABBCollider();
bool Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_AABBCOLLIDER_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,146 +1,146 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a versatile AABB tree.
* \file OPC_AABBTree.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_AABBTREE_H__
#define __OPC_AABBTREE_H__
#ifdef OPC_NO_NEG_VANILLA_TREE
//! TO BE DOCUMENTED
#define IMPLEMENT_TREE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
base_class(); \
~base_class(); \
/* Data access */ \
inline_ const volume* Get##volume() const { return &mBV; } \
/* Clear the last bit */ \
inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \
inline_ const base_class* GetNeg() const { const base_class* P = GetPos(); return P ? P+1 : null;} \
\
/* We don't need to test both nodes since we can't have one without the other */ \
inline_ bool IsLeaf() const { return !GetPos(); } \
\
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
protected: \
/* Tree-independent data */ \
/* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \
/* Whatever happens we need the two children and the enclosing volume.*/ \
volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \
udword mPos; /* "Positive" & "Negative" children */
#else
//! TO BE DOCUMENTED
#define IMPLEMENT_TREE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
base_class(); \
~base_class(); \
/* Data access */ \
inline_ const volume* Get##volume() const { return &mBV; } \
/* Clear the last bit */ \
inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \
inline_ const base_class* GetNeg() const { return (const base_class*)(mNeg&~1); } \
\
/* inline_ bool IsLeaf() const { return (!GetPos() && !GetNeg()); } */ \
/* We don't need to test both nodes since we can't have one without the other */ \
inline_ bool IsLeaf() const { return !GetPos(); } \
\
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
protected: \
/* Tree-independent data */ \
/* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \
/* Whatever happens we need the two children and the enclosing volume.*/ \
volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \
udword mPos; /* "Positive" child */ \
udword mNeg; /* "Negative" child */
#endif
typedef void (*CullingCallback) (udword nb_primitives, udword* node_primitives, BOOL need_clipping, void* user_data);
class OPCODE_API AABBTreeNode
{
IMPLEMENT_TREE(AABBTreeNode, AABB)
public:
// Data access
inline_ const udword* GetPrimitives() const { return mNodePrimitives; }
inline_ udword GetNbPrimitives() const { return mNbPrimitives; }
protected:
// Tree-dependent data
udword* mNodePrimitives; //!< Node-related primitives (shortcut to a position in mIndices below)
udword mNbPrimitives; //!< Number of primitives for this node
// Internal methods
udword Split(udword axis, AABBTreeBuilder* builder);
bool Subdivide(AABBTreeBuilder* builder);
void _BuildHierarchy(AABBTreeBuilder* builder);
void _Refit(AABBTreeBuilder* builder);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called for each node by the walking code.
* \param current [in] current node
* \param depth [in] current node's depth
* \param user_data [in] user-defined data
* \return true to recurse through children, else false to bypass them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef bool (*WalkingCallback) (const AABBTreeNode* current, udword depth, void* user_data);
class OPCODE_API AABBTree : public AABBTreeNode
{
public:
// Constructor / Destructor
AABBTree();
~AABBTree();
// Build
bool Build(AABBTreeBuilder* builder);
void Release();
// Data access
inline_ const udword* GetIndices() const { return mIndices; } //!< Catch the indices
inline_ udword GetNbNodes() const { return mTotalNbNodes; } //!< Catch the number of nodes
// Infos
bool IsComplete() const;
// Stats
udword ComputeDepth() const;
udword GetUsedBytes() const;
udword Walk(WalkingCallback callback, void* user_data) const;
bool Refit(AABBTreeBuilder* builder);
bool Refit2(AABBTreeBuilder* builder);
private:
udword* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation).
AABBTreeNode* mPool; //!< Linear pool of nodes for complete trees. Null otherwise. [Opcode 1.3]
// Stats
udword mTotalNbNodes; //!< Number of nodes in the tree.
};
#endif // __OPC_AABBTREE_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a versatile AABB tree.
* \file OPC_AABBTree.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_AABBTREE_H__
#define __OPC_AABBTREE_H__
#ifdef OPC_NO_NEG_VANILLA_TREE
//! TO BE DOCUMENTED
#define IMPLEMENT_TREE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
base_class(); \
~base_class(); \
/* Data access */ \
inline_ const volume* Get##volume() const { return &mBV; } \
/* Clear the last bit */ \
inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \
inline_ const base_class* GetNeg() const { const base_class* P = GetPos(); return P ? P+1 : null;} \
\
/* We don't need to test both nodes since we can't have one without the other */ \
inline_ bool IsLeaf() const { return !GetPos(); } \
\
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
protected: \
/* Tree-independent data */ \
/* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \
/* Whatever happens we need the two children and the enclosing volume.*/ \
volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \
udword mPos; /* "Positive" & "Negative" children */
#else
//! TO BE DOCUMENTED
#define IMPLEMENT_TREE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
base_class(); \
~base_class(); \
/* Data access */ \
inline_ const volume* Get##volume() const { return &mBV; } \
/* Clear the last bit */ \
inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \
inline_ const base_class* GetNeg() const { return (const base_class*)(mNeg&~1); } \
\
/* inline_ bool IsLeaf() const { return (!GetPos() && !GetNeg()); } */ \
/* We don't need to test both nodes since we can't have one without the other */ \
inline_ bool IsLeaf() const { return !GetPos(); } \
\
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
protected: \
/* Tree-independent data */ \
/* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \
/* Whatever happens we need the two children and the enclosing volume.*/ \
volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \
udword mPos; /* "Positive" child */ \
udword mNeg; /* "Negative" child */
#endif
typedef void (*CullingCallback) (udword nb_primitives, udword* node_primitives, BOOL need_clipping, void* user_data);
class OPCODE_API AABBTreeNode
{
IMPLEMENT_TREE(AABBTreeNode, AABB)
public:
// Data access
inline_ const udword* GetPrimitives() const { return mNodePrimitives; }
inline_ udword GetNbPrimitives() const { return mNbPrimitives; }
protected:
// Tree-dependent data
udword* mNodePrimitives; //!< Node-related primitives (shortcut to a position in mIndices below)
udword mNbPrimitives; //!< Number of primitives for this node
// Internal methods
udword Split(udword axis, AABBTreeBuilder* builder);
bool Subdivide(AABBTreeBuilder* builder);
void _BuildHierarchy(AABBTreeBuilder* builder);
void _Refit(AABBTreeBuilder* builder);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called for each node by the walking code.
* \param current [in] current node
* \param depth [in] current node's depth
* \param user_data [in] user-defined data
* \return true to recurse through children, else false to bypass them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef bool (*WalkingCallback) (const AABBTreeNode* current, udword depth, void* user_data);
class OPCODE_API AABBTree : public AABBTreeNode
{
public:
// Constructor / Destructor
AABBTree();
~AABBTree();
// Build
bool Build(AABBTreeBuilder* builder);
void Release();
// Data access
inline_ const udword* GetIndices() const { return mIndices; } //!< Catch the indices
inline_ udword GetNbNodes() const { return mTotalNbNodes; } //!< Catch the number of nodes
// Infos
bool IsComplete() const;
// Stats
udword ComputeDepth() const;
udword GetUsedBytes() const;
udword Walk(WalkingCallback callback, void* user_data) const;
bool Refit(AABBTreeBuilder* builder);
bool Refit2(AABBTreeBuilder* builder);
private:
udword* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation).
AABBTreeNode* mPool; //!< Linear pool of nodes for complete trees. Null otherwise. [Opcode 1.3]
// Stats
udword mTotalNbNodes; //!< Number of nodes in the tree.
};
#endif // __OPC_AABBTREE_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,159 +1,159 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an array-based version of the sweep-and-prune algorithm
* \file OPC_ArraySAP.h
* \author Pierre Terdiman
* \date December, 2, 2007
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef OPC_ARRAYSAP_H
#define OPC_ARRAYSAP_H
#pragma pack(1)
struct OPCODE_API ASAP_Pair
{
uword id0;
uword id1;
const void* object0;
const void* object1;
//#ifdef PAIR_USER_DATA
void* userData;
//#endif
inline_ const void* GetObject0() const { return (const void*)(size_t(object0) & ~3); }
inline_ const void* GetObject1() const { return (const void*)(size_t(object1) & ~3); }
inline_ size_t IsInArray() const { return size_t(object0) & 1; }
inline_ size_t IsRemoved() const { return size_t(object1) & 1; }
inline_ size_t IsNew() const { return size_t(object0) & 2; }
private:
inline_ void SetInArray() { object0 = (const void*)(size_t(object0) | 1); }
inline_ void SetRemoved() { object1 = (const void*)(size_t(object1) | 1); }
inline_ void SetNew() { object0 = (const void*)(size_t(object0) | 2); }
inline_ void ClearInArray() { object0 = (const void*)(size_t(object0) & ~1); }
inline_ void ClearRemoved() { object1 = (const void*)(size_t(object1) & ~1); }
inline_ void ClearNew() { object0 = (const void*)(size_t(object0) & ~2); }
friend class ArraySAP;
};
#pragma pack()
class OPCODE_API ASAP_PairManager
{
public:
ASAP_PairManager();
~ASAP_PairManager();
void Purge();
void ShrinkMemory();
const ASAP_Pair* AddPair (uword id0, uword id1, const void* object0, const void* object1);
bool RemovePair (uword id0, uword id1);
bool RemovePairs (const BitArray& array);
const ASAP_Pair* FindPair (uword id0, uword id1) const;
inline_ udword GetPairIndex(const ASAP_Pair* pair) const
{
return ((udword)((size_t(pair) - size_t(mActivePairs)))/sizeof(ASAP_Pair));
}
udword mHashSize;
udword mMask;
udword mNbActivePairs;
udword* mHashTable;
udword* mNext;
ASAP_Pair* mActivePairs;
inline_ ASAP_Pair* FindPair(uword id0, uword id1, udword hash_value) const;
void RemovePair(uword id0, uword id1, udword hash_value, udword pair_index);
void ReallocPairs();
};
typedef void* (*SAP_CreatePair)(const void* object0, const void* object1, void* user_data);
typedef void (*SAP_DeletePair)(const void* object0, const void* object1, void* user_data, void* pair_user_data);
// Forward declarations
class ASAP_EndPoint;
class ASAP_Box;
struct IAABB;
struct CreateData;
class OPCODE_API ArraySAP : public Allocateable
{
public:
ArraySAP();
~ArraySAP();
udword AddObject(void* object, uword guid, const AABB& box);
bool RemoveObject(udword handle);
bool UpdateObject(udword handle, const AABB& box);
udword DumpPairs(SAP_CreatePair create_cb, SAP_DeletePair delete_cb, void* cb_user_data, ASAP_Pair** pairs=null);
private:
Container mData;
ASAP_PairManager mPairs;
inline_ void AddPair(const void* object0, const void* object1, uword id0, uword id1)
{
ASSERT(object0);
ASAP_Pair* UP = (ASAP_Pair*)mPairs.AddPair(id0, id1, null, null);
ASSERT(UP);
if(UP->object0)
{
// Persistent pair
}
else
{
// New pair
ASSERT(!(int(object0)&1));
ASSERT(!(int(object1)&1));
UP->object0 = object0;
UP->object1 = object1;
UP->SetInArray();
mData.Add(mPairs.GetPairIndex(UP));
UP->SetNew();
}
UP->ClearRemoved();
}
inline_ void RemovePair(const void* object0, const void* object1, uword id0, uword id1)
{
ASAP_Pair* UP = (ASAP_Pair*)mPairs.FindPair(id0, id1);
if(UP)
{
if(!UP->IsInArray())
{
UP->SetInArray();
mData.Add(mPairs.GetPairIndex(UP));
}
UP->SetRemoved();
}
}
udword mNbBoxes;
udword mMaxNbBoxes;
ASAP_Box* mBoxes;
ASAP_EndPoint* mEndPoints[3];
udword mFirstFree;
void ResizeBoxArray();
// For batch creation
Container mCreated;
void BatchCreate();
void InsertEndPoints(udword axis, const ASAP_EndPoint* end_points, udword nb_endpoints);
bool CompleteBoxPruning2(udword nb, const IAABB* array, const Axes& axes, const CreateData* batched);
bool BipartiteBoxPruning2(udword nb0, const IAABB* array0, udword nb1, const IAABB* array1, const Axes& axes, const CreateData* batched, const udword* box_indices);
// For batch removal
Container mRemoved;
void BatchRemove();
};
#endif // OPC_ARRAYSAP_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an array-based version of the sweep-and-prune algorithm
* \file OPC_ArraySAP.h
* \author Pierre Terdiman
* \date December, 2, 2007
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef OPC_ARRAYSAP_H
#define OPC_ARRAYSAP_H
#pragma pack(1)
struct OPCODE_API ASAP_Pair
{
uword id0;
uword id1;
const void* object0;
const void* object1;
//#ifdef PAIR_USER_DATA
void* userData;
//#endif
inline_ const void* GetObject0() const { return (const void*)(size_t(object0) & ~3); }
inline_ const void* GetObject1() const { return (const void*)(size_t(object1) & ~3); }
inline_ size_t IsInArray() const { return size_t(object0) & 1; }
inline_ size_t IsRemoved() const { return size_t(object1) & 1; }
inline_ size_t IsNew() const { return size_t(object0) & 2; }
private:
inline_ void SetInArray() { object0 = (const void*)(size_t(object0) | 1); }
inline_ void SetRemoved() { object1 = (const void*)(size_t(object1) | 1); }
inline_ void SetNew() { object0 = (const void*)(size_t(object0) | 2); }
inline_ void ClearInArray() { object0 = (const void*)(size_t(object0) & ~1); }
inline_ void ClearRemoved() { object1 = (const void*)(size_t(object1) & ~1); }
inline_ void ClearNew() { object0 = (const void*)(size_t(object0) & ~2); }
friend class ArraySAP;
};
#pragma pack()
class OPCODE_API ASAP_PairManager
{
public:
ASAP_PairManager();
~ASAP_PairManager();
void Purge();
void ShrinkMemory();
const ASAP_Pair* AddPair (uword id0, uword id1, const void* object0, const void* object1);
bool RemovePair (uword id0, uword id1);
bool RemovePairs (const BitArray& array);
const ASAP_Pair* FindPair (uword id0, uword id1) const;
inline_ udword GetPairIndex(const ASAP_Pair* pair) const
{
return ((udword)((size_t(pair) - size_t(mActivePairs)))/sizeof(ASAP_Pair));
}
udword mHashSize;
udword mMask;
udword mNbActivePairs;
udword* mHashTable;
udword* mNext;
ASAP_Pair* mActivePairs;
inline_ ASAP_Pair* FindPair(uword id0, uword id1, udword hash_value) const;
void RemovePair(uword id0, uword id1, udword hash_value, udword pair_index);
void ReallocPairs();
};
typedef void* (*SAP_CreatePair)(const void* object0, const void* object1, void* user_data);
typedef void (*SAP_DeletePair)(const void* object0, const void* object1, void* user_data, void* pair_user_data);
// Forward declarations
class ASAP_EndPoint;
class ASAP_Box;
struct IAABB;
struct CreateData;
class OPCODE_API ArraySAP : public Allocateable
{
public:
ArraySAP();
~ArraySAP();
udword AddObject(void* object, uword guid, const AABB& box);
bool RemoveObject(udword handle);
bool UpdateObject(udword handle, const AABB& box);
udword DumpPairs(SAP_CreatePair create_cb, SAP_DeletePair delete_cb, void* cb_user_data, ASAP_Pair** pairs=null);
private:
Container mData;
ASAP_PairManager mPairs;
inline_ void AddPair(const void* object0, const void* object1, uword id0, uword id1)
{
ASSERT(object0);
ASAP_Pair* UP = (ASAP_Pair*)mPairs.AddPair(id0, id1, null, null);
ASSERT(UP);
if(UP->object0)
{
// Persistent pair
}
else
{
// New pair
ASSERT(!(int(object0)&1));
ASSERT(!(int(object1)&1));
UP->object0 = object0;
UP->object1 = object1;
UP->SetInArray();
mData.Add(mPairs.GetPairIndex(UP));
UP->SetNew();
}
UP->ClearRemoved();
}
inline_ void RemovePair(const void* object0, const void* object1, uword id0, uword id1)
{
ASAP_Pair* UP = (ASAP_Pair*)mPairs.FindPair(id0, id1);
if(UP)
{
if(!UP->IsInArray())
{
UP->SetInArray();
mData.Add(mPairs.GetPairIndex(UP));
}
UP->SetRemoved();
}
}
udword mNbBoxes;
udword mMaxNbBoxes;
ASAP_Box* mBoxes;
ASAP_EndPoint* mEndPoints[3];
udword mFirstFree;
void ResizeBoxArray();
// For batch creation
Container mCreated;
void BatchCreate();
void InsertEndPoints(udword axis, const ASAP_EndPoint* end_points, udword nb_endpoints);
bool CompleteBoxPruning2(udword nb, const IAABB* array, const Axes& axes, const CreateData* batched);
bool BipartiteBoxPruning2(udword nb0, const IAABB* array0, udword nb1, const IAABB* array1, const Axes& axes, const CreateData* batched, const udword* box_indices);
// For batch removal
Container mRemoved;
void BatchRemove();
};
#endif // OPC_ARRAYSAP_H

View File

@@ -1,147 +1,147 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base model interface.
* \file OPC_BaseModel.cpp
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The base class for collision models.
*
* \class BaseModel
* \author Pierre Terdiman
* \version 1.3
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OPCODECREATE::OPCODECREATE()
{
mIMesh = null;
mSettings.mRules = SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER;
mSettings.mLimit = 1; // Mandatory for complete trees
mNoLeaf = true;
mQuantized = true;
#ifdef __MESHMERIZER_H__
mCollisionHull = false;
#endif // __MESHMERIZER_H__
mKeepOriginal = false;
mCanRemap = false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BaseModel::BaseModel() : mIMesh(null), mModelCode(0), mSource(null), mTree(null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BaseModel::~BaseModel()
{
ReleaseBase();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases everything.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void BaseModel::ReleaseBase()
{
DELETESINGLE(mSource);
DELETESINGLE(mTree);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates an optimized tree according to user-settings, and setups mModelCode.
* \param no_leaf [in] true for "no leaf" tree
* \param quantized [in] true for quantized tree
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BaseModel::CreateTree(bool no_leaf, bool quantized)
{
DELETESINGLE(mTree);
// Setup model code
if(no_leaf) mModelCode |= OPC_NO_LEAF;
else mModelCode &= ~OPC_NO_LEAF;
if(quantized) mModelCode |= OPC_QUANTIZED;
else mModelCode &= ~OPC_QUANTIZED;
// Create the correct class
if(mModelCode & OPC_NO_LEAF)
{
if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedNoLeafTree;
else mTree = new AABBNoLeafTree;
}
else
{
if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedTree;
else mTree = new AABBCollisionTree;
}
CHECKALLOC(mTree);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BaseModel::Refit()
{
// Refit the optimized tree
return mTree->Refit(mIMesh);
// Old code kept for reference : refit the source tree then rebuild !
// if(!mSource) return false;
// // Ouch...
// mSource->Refit(&mTB);
// // Ouch...
// return mTree->Build(mSource);
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base model interface.
* \file OPC_BaseModel.cpp
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The base class for collision models.
*
* \class BaseModel
* \author Pierre Terdiman
* \version 1.3
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OPCODECREATE::OPCODECREATE()
{
mIMesh = null;
mSettings.mRules = SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER;
mSettings.mLimit = 1; // Mandatory for complete trees
mNoLeaf = true;
mQuantized = true;
#ifdef __MESHMERIZER_H__
mCollisionHull = false;
#endif // __MESHMERIZER_H__
mKeepOriginal = false;
mCanRemap = false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BaseModel::BaseModel() : mIMesh(null), mModelCode(0), mSource(null), mTree(null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BaseModel::~BaseModel()
{
ReleaseBase();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases everything.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void BaseModel::ReleaseBase()
{
DELETESINGLE(mSource);
DELETESINGLE(mTree);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Creates an optimized tree according to user-settings, and setups mModelCode.
* \param no_leaf [in] true for "no leaf" tree
* \param quantized [in] true for quantized tree
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BaseModel::CreateTree(bool no_leaf, bool quantized)
{
DELETESINGLE(mTree);
// Setup model code
if(no_leaf) mModelCode |= OPC_NO_LEAF;
else mModelCode &= ~OPC_NO_LEAF;
if(quantized) mModelCode |= OPC_QUANTIZED;
else mModelCode &= ~OPC_QUANTIZED;
// Create the correct class
if(mModelCode & OPC_NO_LEAF)
{
if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedNoLeafTree;
else mTree = new AABBNoLeafTree;
}
else
{
if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedTree;
else mTree = new AABBCollisionTree;
}
CHECKALLOC(mTree);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BaseModel::Refit()
{
// Refit the optimized tree
return mTree->Refit(mIMesh);
// Old code kept for reference : refit the source tree then rebuild !
// if(!mSource) return false;
// // Ouch...
// mSource->Refit(&mTB);
// // Ouch...
// return mTree->Build(mSource);
}

View File

@@ -1,184 +1,184 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base model interface.
* \file OPC_BaseModel.h
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_BASEMODEL_H__
#define __OPC_BASEMODEL_H__
//! Model creation structure
struct OPCODE_API OPCODECREATE
{
//! Constructor
OPCODECREATE();
MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*)
BuildSettings mSettings; //!< Builder's settings
bool mNoLeaf; //!< true => discard leaf nodes (else use a normal tree)
bool mQuantized; //!< true => quantize the tree (else use a normal tree)
#ifdef __MESHMERIZER_H__
bool mCollisionHull; //!< true => use convex hull + GJK
#endif // __MESHMERIZER_H__
bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose)
bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays
// (*) This pointer is saved internally and used by OPCODE until collision structures are released,
// so beware of the object's lifetime.
};
enum ModelFlag
{
OPC_QUANTIZED = (1<<0), //!< Compressed/uncompressed tree
OPC_NO_LEAF = (1<<1), //!< Leaf/NoLeaf tree
OPC_SINGLE_NODE = (1<<2) //!< Special case for 1-node models
};
class OPCODE_API BaseModel
{
public:
// Constructor/Destructor
BaseModel();
virtual ~BaseModel();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(const OPCODECREATE& create) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual udword GetUsedBytes() const = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the source tree.
* \return generic tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBTree* GetSourceTree() const { return mSource; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBOptimizedTree* GetTree() const { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ AABBOptimizedTree* GetTree() { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of nodes in the tree.
* Should be 2*N-1 for normal trees and N-1 for optimized ones.
* \return number of nodes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the tree has leaf nodes or not.
* \return true if the tree has leaf nodes (normal tree), else false (optimized tree)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasLeafNodes() const { return !(mModelCode & OPC_NO_LEAF); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the tree is quantized or not.
* \return true if the tree is quantized
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsQuantized() const { return mModelCode & OPC_QUANTIZED; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the model has a single node or not. This special case must be handled separately.
* \return true if the model has only 1 node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the model's code.
* \return model's code
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetModelCode() const { return mModelCode; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the mesh interface.
* \return mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const MeshInterface* GetMeshInterface() const { return mIMesh; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the mesh interface.
* \param imesh [in] mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMeshInterface(const MeshInterface* imesh) { mIMesh = imesh; }
protected:
const MeshInterface* mIMesh; //!< User-defined mesh interface
udword mModelCode; //!< Model code = combination of ModelFlag(s)
AABBTree* mSource; //!< Original source tree
AABBOptimizedTree* mTree; //!< Optimized tree owned by the model
// Internal methods
void ReleaseBase();
bool CreateTree(bool no_leaf, bool quantized);
};
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base model interface.
* \file OPC_BaseModel.h
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_BASEMODEL_H__
#define __OPC_BASEMODEL_H__
//! Model creation structure
struct OPCODE_API OPCODECREATE
{
//! Constructor
OPCODECREATE();
MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*)
BuildSettings mSettings; //!< Builder's settings
bool mNoLeaf; //!< true => discard leaf nodes (else use a normal tree)
bool mQuantized; //!< true => quantize the tree (else use a normal tree)
#ifdef __MESHMERIZER_H__
bool mCollisionHull; //!< true => use convex hull + GJK
#endif // __MESHMERIZER_H__
bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose)
bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays
// (*) This pointer is saved internally and used by OPCODE until collision structures are released,
// so beware of the object's lifetime.
};
enum ModelFlag
{
OPC_QUANTIZED = (1<<0), //!< Compressed/uncompressed tree
OPC_NO_LEAF = (1<<1), //!< Leaf/NoLeaf tree
OPC_SINGLE_NODE = (1<<2) //!< Special case for 1-node models
};
class OPCODE_API BaseModel
{
public:
// Constructor/Destructor
BaseModel();
virtual ~BaseModel();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(const OPCODECREATE& create) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual udword GetUsedBytes() const = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the source tree.
* \return generic tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBTree* GetSourceTree() const { return mSource; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const AABBOptimizedTree* GetTree() const { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the tree.
* \return the collision tree
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ AABBOptimizedTree* GetTree() { return mTree; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of nodes in the tree.
* Should be 2*N-1 for normal trees and N-1 for optimized ones.
* \return number of nodes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the tree has leaf nodes or not.
* \return true if the tree has leaf nodes (normal tree), else false (optimized tree)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasLeafNodes() const { return !(mModelCode & OPC_NO_LEAF); }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the tree is quantized or not.
* \return true if the tree is quantized
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsQuantized() const { return mModelCode & OPC_QUANTIZED; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks whether the model has a single node or not. This special case must be handled separately.
* \return true if the model has only 1 node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the model's code.
* \return model's code
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetModelCode() const { return mModelCode; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the mesh interface.
* \return mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const MeshInterface* GetMeshInterface() const { return mIMesh; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the mesh interface.
* \param imesh [in] mesh interface
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMeshInterface(const MeshInterface* imesh) { mIMesh = imesh; }
protected:
const MeshInterface* mIMesh; //!< User-defined mesh interface
udword mModelCode; //!< Model code = combination of ModelFlag(s)
AABBTree* mSource; //!< Original source tree
AABBOptimizedTree* mTree; //!< Optimized tree owned by the model
// Internal methods
void ReleaseBase();
bool CreateTree(bool no_leaf, bool quantized);
};
#endif //__OPC_BASEMODEL_H__

View File

@@ -1,139 +1,139 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* OBB-OBB overlap test using the separating axis theorem.
* - original code by Gomez / Gamasutra (similar to Gottschalk's one in RAPID)
* - optimized for AABB trees by computing the rotation matrix once (SOLID-fashion)
* - the fabs matrix is precomputed as well and epsilon-tweaked (RAPID-style, we found this almost mandatory)
* - Class III axes can be disabled... (SOLID & Intel fashion)
* - ...or enabled to perform some profiling
* - CPU comparisons used when appropriate
* - lazy evaluation sometimes saves some work in case of early exits (unlike SOLID)
*
* \param ea [in] extents from box A
* \param ca [in] center from box A
* \param eb [in] extents from box B
* \param cb [in] center from box B
* \return true if boxes overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL AABBTreeCollider::BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb)
{
// Stats
mNbBVBVTests++;
float t,t2;
// Class I : A's basis vectors
float Tx = (mR1to0.m[0][0]*cb.x + mR1to0.m[1][0]*cb.y + mR1to0.m[2][0]*cb.z) + mT1to0.x - ca.x;
t = ea.x + eb.x*mAR.m[0][0] + eb.y*mAR.m[1][0] + eb.z*mAR.m[2][0];
if(GREATER(Tx, t)) return FALSE;
float Ty = (mR1to0.m[0][1]*cb.x + mR1to0.m[1][1]*cb.y + mR1to0.m[2][1]*cb.z) + mT1to0.y - ca.y;
t = ea.y + eb.x*mAR.m[0][1] + eb.y*mAR.m[1][1] + eb.z*mAR.m[2][1];
if(GREATER(Ty, t)) return FALSE;
float Tz = (mR1to0.m[0][2]*cb.x + mR1to0.m[1][2]*cb.y + mR1to0.m[2][2]*cb.z) + mT1to0.z - ca.z;
t = ea.z + eb.x*mAR.m[0][2] + eb.y*mAR.m[1][2] + eb.z*mAR.m[2][2];
if(GREATER(Tz, t)) return FALSE;
// Class II : B's basis vectors
t = Tx*mR1to0.m[0][0] + Ty*mR1to0.m[0][1] + Tz*mR1to0.m[0][2]; t2 = ea.x*mAR.m[0][0] + ea.y*mAR.m[0][1] + ea.z*mAR.m[0][2] + eb.x;
if(GREATER(t, t2)) return FALSE;
t = Tx*mR1to0.m[1][0] + Ty*mR1to0.m[1][1] + Tz*mR1to0.m[1][2]; t2 = ea.x*mAR.m[1][0] + ea.y*mAR.m[1][1] + ea.z*mAR.m[1][2] + eb.y;
if(GREATER(t, t2)) return FALSE;
t = Tx*mR1to0.m[2][0] + Ty*mR1to0.m[2][1] + Tz*mR1to0.m[2][2]; t2 = ea.x*mAR.m[2][0] + ea.y*mAR.m[2][1] + ea.z*mAR.m[2][2] + eb.z;
if(GREATER(t, t2)) return FALSE;
// Class III : 9 cross products
// Cool trick: always perform the full test for first level, regardless of settings.
// That way pathological cases (such as the pencils scene) are quickly rejected anyway !
if(mFullBoxBoxTest || mNbBVBVTests==1)
{
t = Tz*mR1to0.m[0][1] - Ty*mR1to0.m[0][2]; t2 = ea.y*mAR.m[0][2] + ea.z*mAR.m[0][1] + eb.y*mAR.m[2][0] + eb.z*mAR.m[1][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B0
t = Tz*mR1to0.m[1][1] - Ty*mR1to0.m[1][2]; t2 = ea.y*mAR.m[1][2] + ea.z*mAR.m[1][1] + eb.x*mAR.m[2][0] + eb.z*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B1
t = Tz*mR1to0.m[2][1] - Ty*mR1to0.m[2][2]; t2 = ea.y*mAR.m[2][2] + ea.z*mAR.m[2][1] + eb.x*mAR.m[1][0] + eb.y*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B2
t = Tx*mR1to0.m[0][2] - Tz*mR1to0.m[0][0]; t2 = ea.x*mAR.m[0][2] + ea.z*mAR.m[0][0] + eb.y*mAR.m[2][1] + eb.z*mAR.m[1][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B0
t = Tx*mR1to0.m[1][2] - Tz*mR1to0.m[1][0]; t2 = ea.x*mAR.m[1][2] + ea.z*mAR.m[1][0] + eb.x*mAR.m[2][1] + eb.z*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B1
t = Tx*mR1to0.m[2][2] - Tz*mR1to0.m[2][0]; t2 = ea.x*mAR.m[2][2] + ea.z*mAR.m[2][0] + eb.x*mAR.m[1][1] + eb.y*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B2
t = Ty*mR1to0.m[0][0] - Tx*mR1to0.m[0][1]; t2 = ea.x*mAR.m[0][1] + ea.y*mAR.m[0][0] + eb.y*mAR.m[2][2] + eb.z*mAR.m[1][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B0
t = Ty*mR1to0.m[1][0] - Tx*mR1to0.m[1][1]; t2 = ea.x*mAR.m[1][1] + ea.y*mAR.m[1][0] + eb.x*mAR.m[2][2] + eb.z*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B1
t = Ty*mR1to0.m[2][0] - Tx*mR1to0.m[2][1]; t2 = ea.x*mAR.m[2][1] + ea.y*mAR.m[2][0] + eb.x*mAR.m[1][2] + eb.y*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B2
}
return TRUE;
}
//! A dedicated version when one box is constant
inline_ BOOL OBBCollider::BoxBoxOverlap(const Point& extents, const Point& center)
{
// Stats
mNbVolumeBVTests++;
float t,t2;
// Class I : A's basis vectors
float Tx = mTBoxToModel.x - center.x; t = extents.x + mBBx1; if(GREATER(Tx, t)) return FALSE;
float Ty = mTBoxToModel.y - center.y; t = extents.y + mBBy1; if(GREATER(Ty, t)) return FALSE;
float Tz = mTBoxToModel.z - center.z; t = extents.z + mBBz1; if(GREATER(Tz, t)) return FALSE;
// Class II : B's basis vectors
t = Tx*mRBoxToModel.m[0][0] + Ty*mRBoxToModel.m[0][1] + Tz*mRBoxToModel.m[0][2];
t2 = extents.x*mAR.m[0][0] + extents.y*mAR.m[0][1] + extents.z*mAR.m[0][2] + mBoxExtents.x;
if(GREATER(t, t2)) return FALSE;
t = Tx*mRBoxToModel.m[1][0] + Ty*mRBoxToModel.m[1][1] + Tz*mRBoxToModel.m[1][2];
t2 = extents.x*mAR.m[1][0] + extents.y*mAR.m[1][1] + extents.z*mAR.m[1][2] + mBoxExtents.y;
if(GREATER(t, t2)) return FALSE;
t = Tx*mRBoxToModel.m[2][0] + Ty*mRBoxToModel.m[2][1] + Tz*mRBoxToModel.m[2][2];
t2 = extents.x*mAR.m[2][0] + extents.y*mAR.m[2][1] + extents.z*mAR.m[2][2] + mBoxExtents.z;
if(GREATER(t, t2)) return FALSE;
// Class III : 9 cross products
// Cool trick: always perform the full test for first level, regardless of settings.
// That way pathological cases (such as the pencils scene) are quickly rejected anyway !
if(mFullBoxBoxTest || mNbVolumeBVTests==1)
{
t = Tz*mRBoxToModel.m[0][1] - Ty*mRBoxToModel.m[0][2]; t2 = extents.y*mAR.m[0][2] + extents.z*mAR.m[0][1] + mBB_1; if(GREATER(t, t2)) return FALSE; // L = A0 x B0
t = Tz*mRBoxToModel.m[1][1] - Ty*mRBoxToModel.m[1][2]; t2 = extents.y*mAR.m[1][2] + extents.z*mAR.m[1][1] + mBB_2; if(GREATER(t, t2)) return FALSE; // L = A0 x B1
t = Tz*mRBoxToModel.m[2][1] - Ty*mRBoxToModel.m[2][2]; t2 = extents.y*mAR.m[2][2] + extents.z*mAR.m[2][1] + mBB_3; if(GREATER(t, t2)) return FALSE; // L = A0 x B2
t = Tx*mRBoxToModel.m[0][2] - Tz*mRBoxToModel.m[0][0]; t2 = extents.x*mAR.m[0][2] + extents.z*mAR.m[0][0] + mBB_4; if(GREATER(t, t2)) return FALSE; // L = A1 x B0
t = Tx*mRBoxToModel.m[1][2] - Tz*mRBoxToModel.m[1][0]; t2 = extents.x*mAR.m[1][2] + extents.z*mAR.m[1][0] + mBB_5; if(GREATER(t, t2)) return FALSE; // L = A1 x B1
t = Tx*mRBoxToModel.m[2][2] - Tz*mRBoxToModel.m[2][0]; t2 = extents.x*mAR.m[2][2] + extents.z*mAR.m[2][0] + mBB_6; if(GREATER(t, t2)) return FALSE; // L = A1 x B2
t = Ty*mRBoxToModel.m[0][0] - Tx*mRBoxToModel.m[0][1]; t2 = extents.x*mAR.m[0][1] + extents.y*mAR.m[0][0] + mBB_7; if(GREATER(t, t2)) return FALSE; // L = A2 x B0
t = Ty*mRBoxToModel.m[1][0] - Tx*mRBoxToModel.m[1][1]; t2 = extents.x*mAR.m[1][1] + extents.y*mAR.m[1][0] + mBB_8; if(GREATER(t, t2)) return FALSE; // L = A2 x B1
t = Ty*mRBoxToModel.m[2][0] - Tx*mRBoxToModel.m[2][1]; t2 = extents.x*mAR.m[2][1] + extents.y*mAR.m[2][0] + mBB_9; if(GREATER(t, t2)) return FALSE; // L = A2 x B2
}
return TRUE;
}
//! A special version for 2 axis-aligned boxes
inline_ BOOL AABBCollider::AABBAABBOverlap(const Point& extents, const Point& center)
{
// Stats
mNbVolumeBVTests++;
float tx = mBox.mCenter.x - center.x; float ex = extents.x + mBox.mExtents.x; if(GREATER(tx, ex)) return FALSE;
float ty = mBox.mCenter.y - center.y; float ey = extents.y + mBox.mExtents.y; if(GREATER(ty, ey)) return FALSE;
float tz = mBox.mCenter.z - center.z; float ez = extents.z + mBox.mExtents.z; if(GREATER(tz, ez)) return FALSE;
return TRUE;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* OBB-OBB overlap test using the separating axis theorem.
* - original code by Gomez / Gamasutra (similar to Gottschalk's one in RAPID)
* - optimized for AABB trees by computing the rotation matrix once (SOLID-fashion)
* - the fabs matrix is precomputed as well and epsilon-tweaked (RAPID-style, we found this almost mandatory)
* - Class III axes can be disabled... (SOLID & Intel fashion)
* - ...or enabled to perform some profiling
* - CPU comparisons used when appropriate
* - lazy evaluation sometimes saves some work in case of early exits (unlike SOLID)
*
* \param ea [in] extents from box A
* \param ca [in] center from box A
* \param eb [in] extents from box B
* \param cb [in] center from box B
* \return true if boxes overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL AABBTreeCollider::BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb)
{
// Stats
mNbBVBVTests++;
float t,t2;
// Class I : A's basis vectors
float Tx = (mR1to0.m[0][0]*cb.x + mR1to0.m[1][0]*cb.y + mR1to0.m[2][0]*cb.z) + mT1to0.x - ca.x;
t = ea.x + eb.x*mAR.m[0][0] + eb.y*mAR.m[1][0] + eb.z*mAR.m[2][0];
if(GREATER(Tx, t)) return FALSE;
float Ty = (mR1to0.m[0][1]*cb.x + mR1to0.m[1][1]*cb.y + mR1to0.m[2][1]*cb.z) + mT1to0.y - ca.y;
t = ea.y + eb.x*mAR.m[0][1] + eb.y*mAR.m[1][1] + eb.z*mAR.m[2][1];
if(GREATER(Ty, t)) return FALSE;
float Tz = (mR1to0.m[0][2]*cb.x + mR1to0.m[1][2]*cb.y + mR1to0.m[2][2]*cb.z) + mT1to0.z - ca.z;
t = ea.z + eb.x*mAR.m[0][2] + eb.y*mAR.m[1][2] + eb.z*mAR.m[2][2];
if(GREATER(Tz, t)) return FALSE;
// Class II : B's basis vectors
t = Tx*mR1to0.m[0][0] + Ty*mR1to0.m[0][1] + Tz*mR1to0.m[0][2]; t2 = ea.x*mAR.m[0][0] + ea.y*mAR.m[0][1] + ea.z*mAR.m[0][2] + eb.x;
if(GREATER(t, t2)) return FALSE;
t = Tx*mR1to0.m[1][0] + Ty*mR1to0.m[1][1] + Tz*mR1to0.m[1][2]; t2 = ea.x*mAR.m[1][0] + ea.y*mAR.m[1][1] + ea.z*mAR.m[1][2] + eb.y;
if(GREATER(t, t2)) return FALSE;
t = Tx*mR1to0.m[2][0] + Ty*mR1to0.m[2][1] + Tz*mR1to0.m[2][2]; t2 = ea.x*mAR.m[2][0] + ea.y*mAR.m[2][1] + ea.z*mAR.m[2][2] + eb.z;
if(GREATER(t, t2)) return FALSE;
// Class III : 9 cross products
// Cool trick: always perform the full test for first level, regardless of settings.
// That way pathological cases (such as the pencils scene) are quickly rejected anyway !
if(mFullBoxBoxTest || mNbBVBVTests==1)
{
t = Tz*mR1to0.m[0][1] - Ty*mR1to0.m[0][2]; t2 = ea.y*mAR.m[0][2] + ea.z*mAR.m[0][1] + eb.y*mAR.m[2][0] + eb.z*mAR.m[1][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B0
t = Tz*mR1to0.m[1][1] - Ty*mR1to0.m[1][2]; t2 = ea.y*mAR.m[1][2] + ea.z*mAR.m[1][1] + eb.x*mAR.m[2][0] + eb.z*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B1
t = Tz*mR1to0.m[2][1] - Ty*mR1to0.m[2][2]; t2 = ea.y*mAR.m[2][2] + ea.z*mAR.m[2][1] + eb.x*mAR.m[1][0] + eb.y*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B2
t = Tx*mR1to0.m[0][2] - Tz*mR1to0.m[0][0]; t2 = ea.x*mAR.m[0][2] + ea.z*mAR.m[0][0] + eb.y*mAR.m[2][1] + eb.z*mAR.m[1][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B0
t = Tx*mR1to0.m[1][2] - Tz*mR1to0.m[1][0]; t2 = ea.x*mAR.m[1][2] + ea.z*mAR.m[1][0] + eb.x*mAR.m[2][1] + eb.z*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B1
t = Tx*mR1to0.m[2][2] - Tz*mR1to0.m[2][0]; t2 = ea.x*mAR.m[2][2] + ea.z*mAR.m[2][0] + eb.x*mAR.m[1][1] + eb.y*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B2
t = Ty*mR1to0.m[0][0] - Tx*mR1to0.m[0][1]; t2 = ea.x*mAR.m[0][1] + ea.y*mAR.m[0][0] + eb.y*mAR.m[2][2] + eb.z*mAR.m[1][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B0
t = Ty*mR1to0.m[1][0] - Tx*mR1to0.m[1][1]; t2 = ea.x*mAR.m[1][1] + ea.y*mAR.m[1][0] + eb.x*mAR.m[2][2] + eb.z*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B1
t = Ty*mR1to0.m[2][0] - Tx*mR1to0.m[2][1]; t2 = ea.x*mAR.m[2][1] + ea.y*mAR.m[2][0] + eb.x*mAR.m[1][2] + eb.y*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B2
}
return TRUE;
}
//! A dedicated version when one box is constant
inline_ BOOL OBBCollider::BoxBoxOverlap(const Point& extents, const Point& center)
{
// Stats
mNbVolumeBVTests++;
float t,t2;
// Class I : A's basis vectors
float Tx = mTBoxToModel.x - center.x; t = extents.x + mBBx1; if(GREATER(Tx, t)) return FALSE;
float Ty = mTBoxToModel.y - center.y; t = extents.y + mBBy1; if(GREATER(Ty, t)) return FALSE;
float Tz = mTBoxToModel.z - center.z; t = extents.z + mBBz1; if(GREATER(Tz, t)) return FALSE;
// Class II : B's basis vectors
t = Tx*mRBoxToModel.m[0][0] + Ty*mRBoxToModel.m[0][1] + Tz*mRBoxToModel.m[0][2];
t2 = extents.x*mAR.m[0][0] + extents.y*mAR.m[0][1] + extents.z*mAR.m[0][2] + mBoxExtents.x;
if(GREATER(t, t2)) return FALSE;
t = Tx*mRBoxToModel.m[1][0] + Ty*mRBoxToModel.m[1][1] + Tz*mRBoxToModel.m[1][2];
t2 = extents.x*mAR.m[1][0] + extents.y*mAR.m[1][1] + extents.z*mAR.m[1][2] + mBoxExtents.y;
if(GREATER(t, t2)) return FALSE;
t = Tx*mRBoxToModel.m[2][0] + Ty*mRBoxToModel.m[2][1] + Tz*mRBoxToModel.m[2][2];
t2 = extents.x*mAR.m[2][0] + extents.y*mAR.m[2][1] + extents.z*mAR.m[2][2] + mBoxExtents.z;
if(GREATER(t, t2)) return FALSE;
// Class III : 9 cross products
// Cool trick: always perform the full test for first level, regardless of settings.
// That way pathological cases (such as the pencils scene) are quickly rejected anyway !
if(mFullBoxBoxTest || mNbVolumeBVTests==1)
{
t = Tz*mRBoxToModel.m[0][1] - Ty*mRBoxToModel.m[0][2]; t2 = extents.y*mAR.m[0][2] + extents.z*mAR.m[0][1] + mBB_1; if(GREATER(t, t2)) return FALSE; // L = A0 x B0
t = Tz*mRBoxToModel.m[1][1] - Ty*mRBoxToModel.m[1][2]; t2 = extents.y*mAR.m[1][2] + extents.z*mAR.m[1][1] + mBB_2; if(GREATER(t, t2)) return FALSE; // L = A0 x B1
t = Tz*mRBoxToModel.m[2][1] - Ty*mRBoxToModel.m[2][2]; t2 = extents.y*mAR.m[2][2] + extents.z*mAR.m[2][1] + mBB_3; if(GREATER(t, t2)) return FALSE; // L = A0 x B2
t = Tx*mRBoxToModel.m[0][2] - Tz*mRBoxToModel.m[0][0]; t2 = extents.x*mAR.m[0][2] + extents.z*mAR.m[0][0] + mBB_4; if(GREATER(t, t2)) return FALSE; // L = A1 x B0
t = Tx*mRBoxToModel.m[1][2] - Tz*mRBoxToModel.m[1][0]; t2 = extents.x*mAR.m[1][2] + extents.z*mAR.m[1][0] + mBB_5; if(GREATER(t, t2)) return FALSE; // L = A1 x B1
t = Tx*mRBoxToModel.m[2][2] - Tz*mRBoxToModel.m[2][0]; t2 = extents.x*mAR.m[2][2] + extents.z*mAR.m[2][0] + mBB_6; if(GREATER(t, t2)) return FALSE; // L = A1 x B2
t = Ty*mRBoxToModel.m[0][0] - Tx*mRBoxToModel.m[0][1]; t2 = extents.x*mAR.m[0][1] + extents.y*mAR.m[0][0] + mBB_7; if(GREATER(t, t2)) return FALSE; // L = A2 x B0
t = Ty*mRBoxToModel.m[1][0] - Tx*mRBoxToModel.m[1][1]; t2 = extents.x*mAR.m[1][1] + extents.y*mAR.m[1][0] + mBB_8; if(GREATER(t, t2)) return FALSE; // L = A2 x B1
t = Ty*mRBoxToModel.m[2][0] - Tx*mRBoxToModel.m[2][1]; t2 = extents.x*mAR.m[2][1] + extents.y*mAR.m[2][0] + mBB_9; if(GREATER(t, t2)) return FALSE; // L = A2 x B2
}
return TRUE;
}
//! A special version for 2 axis-aligned boxes
inline_ BOOL AABBCollider::AABBAABBOverlap(const Point& extents, const Point& center)
{
// Stats
mNbVolumeBVTests++;
float tx = mBox.mCenter.x - center.x; float ex = extents.x + mBox.mExtents.x; if(GREATER(tx, ex)) return FALSE;
float ty = mBox.mCenter.y - center.y; float ey = extents.y + mBox.mExtents.y; if(GREATER(ty, ey)) return FALSE;
float tz = mBox.mCenter.z - center.z; float ez = extents.z + mBox.mExtents.z; if(GREATER(tz, ez)) return FALSE;
return TRUE;
}

View File

@@ -1,376 +1,376 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for box pruning.
* \file IceBoxPruning.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
You could use a complex sweep-and-prune as implemented in I-Collide.
You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems.
You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2.
Or you could use this.
Faster ? I don't know. Probably not. It would be a shame. But who knows ?
Easier ? Definitely. Enjoy the sheer simplicity.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
inline_ void FindRunningIndex(udword& index, float* array, udword* sorted, int last, float max)
{
int First=index;
while(First<=last)
{
index = (First+last)>>1;
if(max>array[sorted[index]]) First = index+1;
else last = index-1;
}
}
// ### could be log(n) !
// and maybe use cmp integers
// InsertionSort has better coherence, RadixSort is better for one-shot queries.
#define PRUNING_SORTER RadixSort
//#define PRUNING_SORTER InsertionSort
// Static for coherence
static PRUNING_SORTER* gCompletePruningSorter = null;
static PRUNING_SORTER* gBipartitePruningSorter0 = null;
static PRUNING_SORTER* gBipartitePruningSorter1 = null;
inline_ PRUNING_SORTER* GetCompletePruningSorter()
{
if(!gCompletePruningSorter) gCompletePruningSorter = ICE_NEW(PRUNING_SORTER);
return gCompletePruningSorter;
}
inline_ PRUNING_SORTER* GetBipartitePruningSorter0()
{
if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = ICE_NEW(PRUNING_SORTER);
return gBipartitePruningSorter0;
}
inline_ PRUNING_SORTER* GetBipartitePruningSorter1()
{
if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = ICE_NEW(PRUNING_SORTER);
return gBipartitePruningSorter1;
}
void ReleasePruningSorters()
{
DELETESINGLE(gBipartitePruningSorter1);
DELETESINGLE(gBipartitePruningSorter0);
DELETESINGLE(gCompletePruningSorter);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
* \param nb0 [in] number of boxes in the first set
* \param array0 [in] array of boxes for the first set
* \param nb1 [in] number of boxes in the second set
* \param array1 [in] array of boxes for the second set
* \param pairs [out] array of overlapping pairs
* \param axes [in] projection order (0,2,1 is often best)
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes)
{
// Checkings
if(!nb0 || !array0 || !nb1 || !array1) return false;
// Catch axes
udword Axis0 = axes.mAxis0;
udword Axis1 = axes.mAxis1;
udword Axis2 = axes.mAxis2;
// Allocate some temporary data
float* MinPosList0 = new float[nb0];
float* MinPosList1 = new float[nb1];
// 1) Build main lists using the primary axis
for(udword i=0;i<nb0;i++) MinPosList0[i] = array0[i]->GetMin(Axis0);
for(udword i=0;i<nb1;i++) MinPosList1[i] = array1[i]->GetMin(Axis0);
// 2) Sort the lists
PRUNING_SORTER* RS0 = GetBipartitePruningSorter0();
PRUNING_SORTER* RS1 = GetBipartitePruningSorter1();
const udword* Sorted0 = RS0->Sort(MinPosList0, nb0).GetRanks();
const udword* Sorted1 = RS1->Sort(MinPosList1, nb1).GetRanks();
// 3) Prune the lists
udword Index0, Index1;
const udword* const LastSorted0 = &Sorted0[nb0];
const udword* const LastSorted1 = &Sorted1[nb1];
const udword* RunningAddress0 = Sorted0;
const udword* RunningAddress1 = Sorted1;
while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0)
{
Index0 = *Sorted0++;
while(RunningAddress1<LastSorted1 && MinPosList1[*RunningAddress1]<MinPosList0[Index0]) RunningAddress1++;
const udword* RunningAddress2_1 = RunningAddress1;
while(RunningAddress2_1<LastSorted1 && MinPosList1[Index1 = *RunningAddress2_1++]<=array0[Index0]->GetMax(Axis0))
{
if(array0[Index0]->Intersect(*array1[Index1], Axis1))
{
if(array0[Index0]->Intersect(*array1[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
}
}
////
while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1)
{
Index0 = *Sorted1++;
while(RunningAddress0<LastSorted0 && MinPosList0[*RunningAddress0]<=MinPosList1[Index0]) RunningAddress0++;
const udword* RunningAddress2_0 = RunningAddress0;
while(RunningAddress2_0<LastSorted0 && MinPosList0[Index1 = *RunningAddress2_0++]<=array1[Index0]->GetMax(Axis0))
{
if(array0[Index1]->Intersect(*array1[Index0], Axis1))
{
if(array0[Index1]->Intersect(*array1[Index0], Axis2))
{
pairs.AddPair(Index1, Index0);
}
}
}
}
DELETEARRAY(MinPosList1);
DELETEARRAY(MinPosList0);
return true;
}
#define ORIGINAL_VERSION
//#define JOAKIM
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
* \param nb [in] number of boxes
* \param array [in] array of boxes
* \param pairs [out] array of overlapping pairs
* \param axes [in] projection order (0,2,1 is often best)
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes)
{
// Checkings
if(!nb || !array) return false;
// Catch axes
udword Axis0 = axes.mAxis0;
udword Axis1 = axes.mAxis1;
udword Axis2 = axes.mAxis2;
#ifdef ORIGINAL_VERSION
// Allocate some temporary data
// float* PosList = new float[nb];
float* PosList = new float[nb+1];
// 1) Build main list using the primary axis
for(udword i=0;i<nb;i++) PosList[i] = array[i]->GetMin(Axis0);
PosList[nb++] = MAX_FLOAT;
// 2) Sort the list
PRUNING_SORTER* RS = GetCompletePruningSorter();
const udword* Sorted = RS->Sort(PosList, nb).GetRanks();
// 3) Prune the list
const udword* const LastSorted = &Sorted[nb];
const udword* RunningAddress = Sorted;
udword Index0, Index1;
while(RunningAddress<LastSorted && Sorted<LastSorted)
{
Index0 = *Sorted++;
// while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
while(PosList[*RunningAddress++]<PosList[Index0]);
if(RunningAddress<LastSorted)
{
const udword* RunningAddress2 = RunningAddress;
// while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
while(PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
{
// if(Index0!=Index1)
// {
if(array[Index0]->Intersect(*array[Index1], Axis1))
{
if(array[Index0]->Intersect(*array[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
// }
}
}
}
DELETEARRAY(PosList);
#endif
#ifdef JOAKIM
// Allocate some temporary data
// float* PosList = new float[nb];
float* MinList = new float[nb+1];
// 1) Build main list using the primary axis
for(udword i=0;i<nb;i++) MinList[i] = array[i]->GetMin(Axis0);
MinList[nb] = MAX_FLOAT;
// 2) Sort the list
PRUNING_SORTER* RS = GetCompletePruningSorter();
udword* Sorted = RS->Sort(MinList, nb+1).GetRanks();
// 3) Prune the list
// const udword* const LastSorted = &Sorted[nb];
// const udword* const LastSorted = &Sorted[nb-1];
const udword* RunningAddress = Sorted;
udword Index0, Index1;
// while(RunningAddress<LastSorted && Sorted<LastSorted)
// while(RunningAddress<LastSorted)
while(RunningAddress<&Sorted[nb])
// while(Sorted<LastSorted)
{
// Index0 = *Sorted++;
Index0 = *RunningAddress++;
// while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
// while(PosList[*RunningAddress++]<PosList[Index0]);
//RunningAddress = Sorted;
// if(RunningAddress<LastSorted)
{
const udword* RunningAddress2 = RunningAddress;
// while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
// float CurrentMin = array[Index0]->GetMin(Axis0);
float CurrentMax = array[Index0]->GetMax(Axis0);
while(MinList[Index1 = *RunningAddress2] <= CurrentMax)
// while(PosList[Index1 = *RunningAddress] <= CurrentMax)
{
// if(Index0!=Index1)
// {
if(array[Index0]->Intersect(*array[Index1], Axis1))
{
if(array[Index0]->Intersect(*array[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
// }
RunningAddress2++;
// RunningAddress++;
}
}
}
DELETEARRAY(MinList);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Brute-force versions are kept:
// - to check the optimized versions return the correct list of intersections
// - to check the speed of the optimized code against the brute-force one
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
* \param nb0 [in] number of boxes in the first set
* \param array0 [in] array of boxes for the first set
* \param nb1 [in] number of boxes in the second set
* \param array1 [in] array of boxes for the second set
* \param pairs [out] array of overlapping pairs
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs)
{
// Checkings
if(!nb0 || !array0 || !nb1 || !array1) return false;
// Brute-force nb0*nb1 overlap tests
for(udword i=0;i<nb0;i++)
{
for(udword j=0;j<nb1;j++)
{
if(array0[i]->Intersect(*array1[j])) pairs.AddPair(i, j);
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
* \param nb [in] number of boxes
* \param array [in] array of boxes
* \param pairs [out] array of overlapping pairs
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs)
{
// Checkings
if(!nb || !array) return false;
// Brute-force n(n-1)/2 overlap tests
for(udword i=0;i<nb;i++)
{
for(udword j=i+1;j<nb;j++)
{
if(array[i]->Intersect(*array[j])) pairs.AddPair(i, j);
}
}
return true;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for box pruning.
* \file IceBoxPruning.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
You could use a complex sweep-and-prune as implemented in I-Collide.
You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems.
You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2.
Or you could use this.
Faster ? I don't know. Probably not. It would be a shame. But who knows ?
Easier ? Definitely. Enjoy the sheer simplicity.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
inline_ void FindRunningIndex(udword& index, float* array, udword* sorted, int last, float max)
{
int First=index;
while(First<=last)
{
index = (First+last)>>1;
if(max>array[sorted[index]]) First = index+1;
else last = index-1;
}
}
// ### could be log(n) !
// and maybe use cmp integers
// InsertionSort has better coherence, RadixSort is better for one-shot queries.
#define PRUNING_SORTER RadixSort
//#define PRUNING_SORTER InsertionSort
// Static for coherence
static PRUNING_SORTER* gCompletePruningSorter = null;
static PRUNING_SORTER* gBipartitePruningSorter0 = null;
static PRUNING_SORTER* gBipartitePruningSorter1 = null;
inline_ PRUNING_SORTER* GetCompletePruningSorter()
{
if(!gCompletePruningSorter) gCompletePruningSorter = ICE_NEW(PRUNING_SORTER);
return gCompletePruningSorter;
}
inline_ PRUNING_SORTER* GetBipartitePruningSorter0()
{
if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = ICE_NEW(PRUNING_SORTER);
return gBipartitePruningSorter0;
}
inline_ PRUNING_SORTER* GetBipartitePruningSorter1()
{
if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = ICE_NEW(PRUNING_SORTER);
return gBipartitePruningSorter1;
}
void ReleasePruningSorters()
{
DELETESINGLE(gBipartitePruningSorter1);
DELETESINGLE(gBipartitePruningSorter0);
DELETESINGLE(gCompletePruningSorter);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
* \param nb0 [in] number of boxes in the first set
* \param array0 [in] array of boxes for the first set
* \param nb1 [in] number of boxes in the second set
* \param array1 [in] array of boxes for the second set
* \param pairs [out] array of overlapping pairs
* \param axes [in] projection order (0,2,1 is often best)
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes)
{
// Checkings
if(!nb0 || !array0 || !nb1 || !array1) return false;
// Catch axes
udword Axis0 = axes.mAxis0;
udword Axis1 = axes.mAxis1;
udword Axis2 = axes.mAxis2;
// Allocate some temporary data
float* MinPosList0 = new float[nb0];
float* MinPosList1 = new float[nb1];
// 1) Build main lists using the primary axis
for(udword i=0;i<nb0;i++) MinPosList0[i] = array0[i]->GetMin(Axis0);
for(udword i=0;i<nb1;i++) MinPosList1[i] = array1[i]->GetMin(Axis0);
// 2) Sort the lists
PRUNING_SORTER* RS0 = GetBipartitePruningSorter0();
PRUNING_SORTER* RS1 = GetBipartitePruningSorter1();
const udword* Sorted0 = RS0->Sort(MinPosList0, nb0).GetRanks();
const udword* Sorted1 = RS1->Sort(MinPosList1, nb1).GetRanks();
// 3) Prune the lists
udword Index0, Index1;
const udword* const LastSorted0 = &Sorted0[nb0];
const udword* const LastSorted1 = &Sorted1[nb1];
const udword* RunningAddress0 = Sorted0;
const udword* RunningAddress1 = Sorted1;
while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0)
{
Index0 = *Sorted0++;
while(RunningAddress1<LastSorted1 && MinPosList1[*RunningAddress1]<MinPosList0[Index0]) RunningAddress1++;
const udword* RunningAddress2_1 = RunningAddress1;
while(RunningAddress2_1<LastSorted1 && MinPosList1[Index1 = *RunningAddress2_1++]<=array0[Index0]->GetMax(Axis0))
{
if(array0[Index0]->Intersect(*array1[Index1], Axis1))
{
if(array0[Index0]->Intersect(*array1[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
}
}
////
while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1)
{
Index0 = *Sorted1++;
while(RunningAddress0<LastSorted0 && MinPosList0[*RunningAddress0]<=MinPosList1[Index0]) RunningAddress0++;
const udword* RunningAddress2_0 = RunningAddress0;
while(RunningAddress2_0<LastSorted0 && MinPosList0[Index1 = *RunningAddress2_0++]<=array1[Index0]->GetMax(Axis0))
{
if(array0[Index1]->Intersect(*array1[Index0], Axis1))
{
if(array0[Index1]->Intersect(*array1[Index0], Axis2))
{
pairs.AddPair(Index1, Index0);
}
}
}
}
DELETEARRAY(MinPosList1);
DELETEARRAY(MinPosList0);
return true;
}
#define ORIGINAL_VERSION
//#define JOAKIM
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
* \param nb [in] number of boxes
* \param array [in] array of boxes
* \param pairs [out] array of overlapping pairs
* \param axes [in] projection order (0,2,1 is often best)
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes)
{
// Checkings
if(!nb || !array) return false;
// Catch axes
udword Axis0 = axes.mAxis0;
udword Axis1 = axes.mAxis1;
udword Axis2 = axes.mAxis2;
#ifdef ORIGINAL_VERSION
// Allocate some temporary data
// float* PosList = new float[nb];
float* PosList = new float[nb+1];
// 1) Build main list using the primary axis
for(udword i=0;i<nb;i++) PosList[i] = array[i]->GetMin(Axis0);
PosList[nb++] = MAX_FLOAT;
// 2) Sort the list
PRUNING_SORTER* RS = GetCompletePruningSorter();
const udword* Sorted = RS->Sort(PosList, nb).GetRanks();
// 3) Prune the list
const udword* const LastSorted = &Sorted[nb];
const udword* RunningAddress = Sorted;
udword Index0, Index1;
while(RunningAddress<LastSorted && Sorted<LastSorted)
{
Index0 = *Sorted++;
// while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
while(PosList[*RunningAddress++]<PosList[Index0]);
if(RunningAddress<LastSorted)
{
const udword* RunningAddress2 = RunningAddress;
// while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
while(PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
{
// if(Index0!=Index1)
// {
if(array[Index0]->Intersect(*array[Index1], Axis1))
{
if(array[Index0]->Intersect(*array[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
// }
}
}
}
DELETEARRAY(PosList);
#endif
#ifdef JOAKIM
// Allocate some temporary data
// float* PosList = new float[nb];
float* MinList = new float[nb+1];
// 1) Build main list using the primary axis
for(udword i=0;i<nb;i++) MinList[i] = array[i]->GetMin(Axis0);
MinList[nb] = MAX_FLOAT;
// 2) Sort the list
PRUNING_SORTER* RS = GetCompletePruningSorter();
udword* Sorted = RS->Sort(MinList, nb+1).GetRanks();
// 3) Prune the list
// const udword* const LastSorted = &Sorted[nb];
// const udword* const LastSorted = &Sorted[nb-1];
const udword* RunningAddress = Sorted;
udword Index0, Index1;
// while(RunningAddress<LastSorted && Sorted<LastSorted)
// while(RunningAddress<LastSorted)
while(RunningAddress<&Sorted[nb])
// while(Sorted<LastSorted)
{
// Index0 = *Sorted++;
Index0 = *RunningAddress++;
// while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
// while(PosList[*RunningAddress++]<PosList[Index0]);
//RunningAddress = Sorted;
// if(RunningAddress<LastSorted)
{
const udword* RunningAddress2 = RunningAddress;
// while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0))
// float CurrentMin = array[Index0]->GetMin(Axis0);
float CurrentMax = array[Index0]->GetMax(Axis0);
while(MinList[Index1 = *RunningAddress2] <= CurrentMax)
// while(PosList[Index1 = *RunningAddress] <= CurrentMax)
{
// if(Index0!=Index1)
// {
if(array[Index0]->Intersect(*array[Index1], Axis1))
{
if(array[Index0]->Intersect(*array[Index1], Axis2))
{
pairs.AddPair(Index0, Index1);
}
}
// }
RunningAddress2++;
// RunningAddress++;
}
}
}
DELETEARRAY(MinList);
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Brute-force versions are kept:
// - to check the optimized versions return the correct list of intersections
// - to check the speed of the optimized code against the brute-force one
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
* \param nb0 [in] number of boxes in the first set
* \param array0 [in] array of boxes for the first set
* \param nb1 [in] number of boxes in the second set
* \param array1 [in] array of boxes for the second set
* \param pairs [out] array of overlapping pairs
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs)
{
// Checkings
if(!nb0 || !array0 || !nb1 || !array1) return false;
// Brute-force nb0*nb1 overlap tests
for(udword i=0;i<nb0;i++)
{
for(udword j=0;j<nb1;j++)
{
if(array0[i]->Intersect(*array1[j])) pairs.AddPair(i, j);
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
* \param nb [in] number of boxes
* \param array [in] array of boxes
* \param pairs [out] array of overlapping pairs
* \return true if success.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Opcode::BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs)
{
// Checkings
if(!nb || !array) return false;
// Brute-force n(n-1)/2 overlap tests
for(udword i=0;i<nb;i++)
{
for(udword j=i+1;j<nb;j++)
{
if(array[i]->Intersect(*array[j])) pairs.AddPair(i, j);
}
}
return true;
}

View File

@@ -1,40 +1,40 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for box pruning.
* \file IceBoxPruning.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_BOXPRUNING_H__
#define __OPC_BOXPRUNING_H__
// Optimized versions
FUNCTION OPCODE_API bool CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes);
FUNCTION OPCODE_API bool BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes);
// Brute-force versions
FUNCTION OPCODE_API bool BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs);
FUNCTION OPCODE_API bool BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs);
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for box pruning.
* \file IceBoxPruning.h
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_BOXPRUNING_H__
#define __OPC_BOXPRUNING_H__
// Optimized versions
FUNCTION OPCODE_API bool CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes);
FUNCTION OPCODE_API bool BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes);
// Brute-force versions
FUNCTION OPCODE_API bool BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs);
FUNCTION OPCODE_API bool BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs);
#endif //__OPC_BOXPRUNING_H__

View File

@@ -1,63 +1,63 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base collider class.
* \file OPC_Collider.cpp
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains the abstract class for colliders.
*
* \class Collider
* \author Pierre Terdiman
* \version 1.3
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Collider::Collider() :
mFlags (0),
mCurrentModel (null),
mIMesh (null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Collider::~Collider()
{
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base collider class.
* \file OPC_Collider.cpp
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains the abstract class for colliders.
*
* \class Collider
* \author Pierre Terdiman
* \version 1.3
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Collider::Collider() :
mFlags (0),
mCurrentModel (null),
mIMesh (null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Collider::~Collider()
{
}

View File

@@ -1,185 +1,185 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base collider class.
* \file OPC_Collider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_COLLIDER_H__
#define __OPC_COLLIDER_H__
enum CollisionFlag
{
OPC_FIRST_CONTACT = (1<<0), //!< Report all contacts (false) or only first one (true)
OPC_TEMPORAL_COHERENCE = (1<<1), //!< Use temporal coherence or not
OPC_CONTACT = (1<<2), //!< Final contact status after a collision query
OPC_TEMPORAL_HIT = (1<<3), //!< There has been an early exit due to temporal coherence
OPC_NO_PRIMITIVE_TESTS = (1<<4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries)
OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT,
OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT,
OPC_FORCE_DWORD = 0x7fffffff
};
class OPCODE_API Collider
{
public:
// Constructor / Destructor
Collider();
virtual ~Collider();
// Collision report
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the last collision status after a collision query.
* \return true if a collision occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the "first contact" mode.
* \return true if "first contact" mode is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the temporal coherence mode.
* \return true if temporal coherence is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a first contact has already been found.
* \return true if a first contact has been found and we can stop a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND)==OPC_CONTACT_FOUND; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks there's been an early exit due to temporal coherence;
* \return true if a temporal hit has occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks primitive tests are enabled;
* \return true if primitive tests must be skipped
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; }
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reports all contacts (false) or first contact only (true)
* \param flag [in] true for first contact, false for all contacts
* \see SetTemporalCoherence(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFirstContact(bool flag)
{
if(flag) mFlags |= OPC_FIRST_CONTACT;
else mFlags &= ~OPC_FIRST_CONTACT;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable temporal coherence.
* \param flag [in] true to enable temporal coherence, false to discard it
* \see SetFirstContact(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetTemporalCoherence(bool flag)
{
if(flag) mFlags |= OPC_TEMPORAL_COHERENCE;
else mFlags &= ~OPC_TEMPORAL_COHERENCE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable primitive tests.
* \param flag [in] true to enable primitive tests, false to discard them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetPrimitiveTests(bool flag)
{
if(!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS;
else mFlags &= ~OPC_NO_PRIMITIVE_TESTS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual const char* ValidateSettings() = 0;
protected:
udword mFlags; //!< Bit flags
const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces)
// User mesh interface
const MeshInterface* mIMesh; //!< User-defined mesh interface
// Internal methods
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups current collision model
* \param model [in] current collision model
* \return TRUE if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Setup(const BaseModel* model)
{
// Keep track of current model
mCurrentModel = model;
if(!mCurrentModel) return FALSE;
mIMesh = model->GetMeshInterface();
return mIMesh!=null;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; }
};
#endif // __OPC_COLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains base collider class.
* \file OPC_Collider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_COLLIDER_H__
#define __OPC_COLLIDER_H__
enum CollisionFlag
{
OPC_FIRST_CONTACT = (1<<0), //!< Report all contacts (false) or only first one (true)
OPC_TEMPORAL_COHERENCE = (1<<1), //!< Use temporal coherence or not
OPC_CONTACT = (1<<2), //!< Final contact status after a collision query
OPC_TEMPORAL_HIT = (1<<3), //!< There has been an early exit due to temporal coherence
OPC_NO_PRIMITIVE_TESTS = (1<<4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries)
OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT,
OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT,
OPC_FORCE_DWORD = 0x7fffffff
};
class OPCODE_API Collider
{
public:
// Constructor / Destructor
Collider();
virtual ~Collider();
// Collision report
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the last collision status after a collision query.
* \return true if a collision occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the "first contact" mode.
* \return true if "first contact" mode is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the temporal coherence mode.
* \return true if temporal coherence is on
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a first contact has already been found.
* \return true if a first contact has been found and we can stop a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND)==OPC_CONTACT_FOUND; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks there's been an early exit due to temporal coherence;
* \return true if a temporal hit has occured
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks primitive tests are enabled;
* \return true if primitive tests must be skipped
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; }
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Reports all contacts (false) or first contact only (true)
* \param flag [in] true for first contact, false for all contacts
* \see SetTemporalCoherence(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFirstContact(bool flag)
{
if(flag) mFlags |= OPC_FIRST_CONTACT;
else mFlags &= ~OPC_FIRST_CONTACT;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable temporal coherence.
* \param flag [in] true to enable temporal coherence, false to discard it
* \see SetFirstContact(bool flag)
* \see ValidateSettings()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetTemporalCoherence(bool flag)
{
if(flag) mFlags |= OPC_TEMPORAL_COHERENCE;
else mFlags &= ~OPC_TEMPORAL_COHERENCE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Enable/disable primitive tests.
* \param flag [in] true to enable primitive tests, false to discard them
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetPrimitiveTests(bool flag)
{
if(!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS;
else mFlags &= ~OPC_NO_PRIMITIVE_TESTS;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual const char* ValidateSettings() = 0;
protected:
udword mFlags; //!< Bit flags
const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces)
// User mesh interface
const MeshInterface* mIMesh; //!< User-defined mesh interface
// Internal methods
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups current collision model
* \param model [in] current collision model
* \return TRUE if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL Setup(const BaseModel* model)
{
// Keep track of current model
mCurrentModel = model;
if(!mCurrentModel) return FALSE;
mIMesh = model->GetMeshInterface();
return mIMesh!=null;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; }
};
#endif // __OPC_COLLIDER_H__

View File

@@ -1,57 +1,57 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains common classes & defs used in OPCODE.
* \file OPC_Common.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An AABB dedicated to collision detection.
* We don't use the generic AABB class included in ICE, since it can be a Min/Max or a Center/Extents one (depends
* on compilation flags). Since the Center/Extents model is more efficient in collision detection, it was worth
* using an extra special class.
*
* \class CollisionAABB
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A quantized AABB.
* Center/Extent model, using 16-bits integers.
*
* \class QuantizedAABB
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains common classes & defs used in OPCODE.
* \file OPC_Common.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An AABB dedicated to collision detection.
* We don't use the generic AABB class included in ICE, since it can be a Min/Max or a Center/Extents one (depends
* on compilation flags). Since the Center/Extents model is more efficient in collision detection, it was worth
* using an extra special class.
*
* \class CollisionAABB
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* A quantized AABB.
* Center/Extent model, using 16-bits integers.
*
* \class QuantizedAABB
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;

View File

@@ -1,110 +1,110 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains common classes & defs used in OPCODE.
* \file OPC_Common.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_COMMON_H__
#define __OPC_COMMON_H__
// [GOTTFRIED]: Just a small change for readability.
#ifdef OPC_CPU_COMPARE
#define GREATER(x, y) AIR(x) > IR(y)
#else
#define GREATER(x, y) fabsf(x) > (y)
#endif
class OPCODE_API CollisionAABB
{
public:
//! Constructor
inline_ CollisionAABB() {}
//! Constructor
inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); }
//! Destructor
inline_ ~CollisionAABB() {}
//! Get min point of the box
inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
//! Get max point of the box
inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
//! Get component of the box's min point along a given axis
inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
//! Get component of the box's max point along a given axis
inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an AABB from min & max vectors.
* \param min [in] the min point
* \param max [in] the max point
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other box
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsInside(const CollisionAABB& box) const
{
if(box.GetMin(0)>GetMin(0)) return FALSE;
if(box.GetMin(1)>GetMin(1)) return FALSE;
if(box.GetMin(2)>GetMin(2)) return FALSE;
if(box.GetMax(0)<GetMax(0)) return FALSE;
if(box.GetMax(1)<GetMax(1)) return FALSE;
if(box.GetMax(2)<GetMax(2)) return FALSE;
return TRUE;
}
Point mCenter; //!< Box center
Point mExtents; //!< Box extents
};
class OPCODE_API QuantizedAABB
{
public:
//! Constructor
inline_ QuantizedAABB() {}
//! Destructor
inline_ ~QuantizedAABB() {}
sword mCenter[3]; //!< Quantized center
uword mExtents[3]; //!< Quantized extents
};
//! Quickly rotates & translates a vector
inline_ void TransformPoint(Point& dest, const Point& source, const Matrix3x3& rot, const Point& trans)
{
dest.x = trans.x + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = trans.y + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = trans.z + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains common classes & defs used in OPCODE.
* \file OPC_Common.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_COMMON_H__
#define __OPC_COMMON_H__
// [GOTTFRIED]: Just a small change for readability.
#ifdef OPC_CPU_COMPARE
#define GREATER(x, y) AIR(x) > IR(y)
#else
#define GREATER(x, y) fabsf(x) > (y)
#endif
class OPCODE_API CollisionAABB
{
public:
//! Constructor
inline_ CollisionAABB() {}
//! Constructor
inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); }
//! Destructor
inline_ ~CollisionAABB() {}
//! Get min point of the box
inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
//! Get max point of the box
inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
//! Get component of the box's min point along a given axis
inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
//! Get component of the box's max point along a given axis
inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Setups an AABB from min & max vectors.
* \param min [in] the min point
* \param max [in] the max point
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks a box is inside another box.
* \param box [in] the other box
* \return true if current box is inside input box
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL IsInside(const CollisionAABB& box) const
{
if(box.GetMin(0)>GetMin(0)) return FALSE;
if(box.GetMin(1)>GetMin(1)) return FALSE;
if(box.GetMin(2)>GetMin(2)) return FALSE;
if(box.GetMax(0)<GetMax(0)) return FALSE;
if(box.GetMax(1)<GetMax(1)) return FALSE;
if(box.GetMax(2)<GetMax(2)) return FALSE;
return TRUE;
}
Point mCenter; //!< Box center
Point mExtents; //!< Box extents
};
class OPCODE_API QuantizedAABB
{
public:
//! Constructor
inline_ QuantizedAABB() {}
//! Destructor
inline_ ~QuantizedAABB() {}
sword mCenter[3]; //!< Quantized center
uword mExtents[3]; //!< Quantized extents
};
//! Quickly rotates & translates a vector
inline_ void TransformPoint(Point& dest, const Point& source, const Matrix3x3& rot, const Point& trans)
{
dest.x = trans.x + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0];
dest.y = trans.y + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1];
dest.z = trans.z + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2];
}
#endif //__OPC_COMMON_H__

View File

@@ -1,475 +1,475 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for hybrid models.
* \file OPC_HybridModel.cpp
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An hybrid collision model.
*
* The problem :
*
* Opcode really shines for mesh-mesh collision, especially when meshes are deeply overlapping
* (it typically outperforms RAPID in those cases).
*
* Unfortunately this is not the typical scenario in games.
*
* For close-proximity cases, especially for volume-mesh queries, it's relatively easy to run faster
* than Opcode, that suffers from a relatively high setup time.
*
* In particular, Opcode's "vanilla" trees in those cases -can- run faster. They can also use -less-
* memory than the optimized ones, when you let the system stop at ~10 triangles / leaf for example
* (i.e. when you don't use "complete" trees). However, those trees tend to fragment memory quite a
* lot, increasing cache misses : since they're not "complete", we can't predict the final number of
* nodes and we have to allocate nodes on-the-fly. For the same reasons we can't use Opcode's "optimized"
* trees here, since they rely on a known layout to perform the "optimization".
*
* Hybrid trees :
*
* Hybrid trees try to combine best of both worlds :
*
* - they use a maximum limit of 16 triangles/leaf. "16" is used so that we'll be able to save the
* number of triangles using 4 bits only.
*
* - they're still "complete" trees thanks to a two-passes building phase. First we create a "vanilla"
* AABB-tree with Opcode, limited to 16 triangles/leaf. Then we create a *second* vanilla tree, this
* time using the leaves of the first one. The trick is : this second tree is now "complete"... so we
* can further transform it into an Opcode's optimized tree.
*
* - then we run the collision queries on that standard Opcode tree. The only difference is that leaf
* nodes contain indices to leaf nodes of another tree. Also, we have to skip all primitive tests in
* Opcode optimized trees, since our leaves don't contain triangles anymore.
*
* - finally, for each collided leaf, we simply loop through 16 triangles max, and collide them with
* the bounding volume used in the query (we only support volume-vs-mesh queries here, not mesh-vs-mesh)
*
* All of that is wrapped in this "hybrid model" that contains the minimal data required for this to work.
* It's a mix between old "vanilla" trees, and old "optimized" trees.
*
* Extra advantages:
*
* - If we use them for dynamic models, we're left with a very small number of leaf nodes to refit. It
* might be a bit faster since we have less nodes to write back.
*
* - In rigid body simulation, using temporal coherence and sleeping objects greatly reduce the actual
* influence of one tree over another (i.e. the speed difference is often invisible). So memory is really
* the key element to consider, and in this regard hybrid trees are just better.
*
* Information to take home:
* - they use less ram
* - they're not slower (they're faster or slower depending on cases, overall there's no significant
* difference *as long as objects don't interpenetrate too much* - in which case Opcode's optimized trees
* are still notably faster)
*
* \class HybridModel
* \author Pierre Terdiman
* \version 1.3
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HybridModel::HybridModel() :
mNbLeaves (0),
mNbPrimitives (0),
mTriangles (null),
mIndices (null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HybridModel::~HybridModel()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases everything.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void HybridModel::Release()
{
ReleaseBase();
DELETEARRAY(mIndices);
DELETEARRAY(mTriangles);
mNbLeaves = 0;
mNbPrimitives = 0;
}
struct Internal
{
Internal()
{
mNbLeaves = 0;
mLeaves = null;
mTriangles = null;
mBase = null;
}
~Internal()
{
DELETEARRAY(mLeaves);
}
udword mNbLeaves;
AABB* mLeaves;
LeafTriangles* mTriangles;
const udword* mBase;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool HybridModel::Build(const OPCODECREATE& create)
{
// 1) Checkings
if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
// Look for degenerate faces.
udword NbDegenerate = create.mIMesh->CheckTopology();
if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
// We continue nonetheless....
Release(); // Make sure previous tree has been discarded
// 1-1) Setup mesh interface automatically
SetMeshInterface(create.mIMesh);
bool Status = false;
AABBTree* LeafTree = null;
Internal Data;
// 2) Build a generic AABB Tree.
mSource = new AABBTree;
CHECKALLOC(mSource);
// 2-1) Setup a builder. Our primitives here are triangles from input mesh,
// so we use an AABBTreeOfTrianglesBuilder.....
{
AABBTreeOfTrianglesBuilder TB;
TB.mIMesh = create.mIMesh;
TB.mNbPrimitives = create.mIMesh->GetNbTriangles();
TB.mSettings = create.mSettings;
TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
if(!mSource->Build(&TB)) goto FreeAndExit;
}
// 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
struct Local
{
// A callback to count leaf nodes
static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
{
if(current->IsLeaf())
{
Internal* Data = (Internal*)user_data;
Data->mNbLeaves++;
}
return true;
}
// A callback to setup leaf nodes in our internal structures
static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
{
if(current->IsLeaf())
{
Internal* Data = (Internal*)user_data;
// Get current leaf's box
Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();
// Setup leaf data
udword Index = (udword(current->GetPrimitives()) - udword(Data->mBase))/sizeof(udword);
Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);
Data->mNbLeaves++;
}
return true;
}
};
// Walk the tree & count number of leaves
Data.mNbLeaves = 0;
mSource->Walk(Local::CountLeaves, &Data);
mNbLeaves = Data.mNbLeaves; // Keep track of it
// Special case for 1-leaf meshes
if(mNbLeaves==1)
{
mModelCode |= OPC_SINGLE_NODE;
Status = true;
goto FreeAndExit;
}
// Allocate our structures
Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves);
mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles);
// Walk the tree again & setup leaf data
Data.mTriangles = mTriangles;
Data.mBase = mSource->GetIndices();
Data.mNbLeaves = 0; // Reset for incoming walk
mSource->Walk(Local::SetupLeafData, &Data);
// Handle source indices
{
bool MustKeepIndices = true;
if(create.mCanRemap)
{
// We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
// Remap can fail when we use callbacks => keep track of indices in that case (it still
// works, only using more memory)
if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
{
MustKeepIndices = false;
}
}
if(MustKeepIndices)
{
// Keep track of source indices (from vanilla tree)
mNbPrimitives = mSource->GetNbPrimitives();
mIndices = new udword[mNbPrimitives];
CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
}
}
// Now, create our optimized tree using previous leaf nodes
LeafTree = new AABBTree;
CHECKALLOC(LeafTree);
{
AABBTreeOfAABBsBuilder TB; // Now using boxes !
TB.mSettings = create.mSettings;
TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it
TB.mNbPrimitives = Data.mNbLeaves;
TB.mAABBArray = Data.mLeaves;
if(!LeafTree->Build(&TB)) goto FreeAndExit;
}
// 3) Create an optimized tree according to user-settings
if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit;
// 3-2) Create optimized tree
if(!mTree->Build(LeafTree)) goto FreeAndExit;
// Finally ok...
Status = true;
FreeAndExit: // Allow me this one...
DELETESINGLE(LeafTree);
// 3-3) Delete generic tree if needed
if(!create.mKeepOriginal) DELETESINGLE(mSource);
return Status;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword HybridModel::GetUsedBytes() const
{
udword UsedBytes = 0;
if(mTree) UsedBytes += mTree->GetUsedBytes();
if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices
if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles
return UsedBytes;
}
inline_ void ComputeMinMax_HM(Point& min, Point& max, const VertexPointers& vp)
{
// Compute triangle's AABB = a leaf box
#ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much
min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
#else
min = *vp.Vertex[0];
max = *vp.Vertex[0];
min.Min(*vp.Vertex[1]);
max.Max(*vp.Vertex[1]);
min.Min(*vp.Vertex[2]);
max.Max(*vp.Vertex[2]);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool HybridModel::Refit()
{
if(!mIMesh) return false;
if(!mTree) return false;
if(IsQuantized()) return false;
if(HasLeafNodes()) return false;
const LeafTriangles* LT = GetLeafTriangles();
const udword* Indices = GetIndices();
// Bottom-up update
VertexPointers VP;
Point Min,Max;
Point Min_,Max_;
udword Index = mTree->GetNbNodes();
AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes();
while(Index--)
{
AABBNoLeafNode& Current = Nodes[Index];
if(Current.HasPosLeaf())
{
const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()];
Min.SetPlusInfinity();
Max.SetMinusInfinity();
Point TmpMin, TmpMax;
// Each leaf box has a set of triangles
udword NbTris = CurrentLeaf.GetNbTriangles();
if(Indices)
{
const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, *T++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min.Min(TmpMin);
Max.Max(TmpMax);
}
}
else
{
udword BaseIndex = CurrentLeaf.GetTriangleIndex();
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, BaseIndex++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min.Min(TmpMin);
Max.Max(TmpMax);
}
}
}
else
{
const CollisionAABB& CurrentBox = Current.GetPos()->mAABB;
CurrentBox.GetMin(Min);
CurrentBox.GetMax(Max);
}
if(Current.HasNegLeaf())
{
const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()];
Min_.SetPlusInfinity();
Max_.SetMinusInfinity();
Point TmpMin, TmpMax;
// Each leaf box has a set of triangles
udword NbTris = CurrentLeaf.GetNbTriangles();
if(Indices)
{
const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, *T++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min_.Min(TmpMin);
Max_.Max(TmpMax);
}
}
else
{
udword BaseIndex = CurrentLeaf.GetTriangleIndex();
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, BaseIndex++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min_.Min(TmpMin);
Max_.Max(TmpMax);
}
}
}
else
{
const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB;
CurrentBox.GetMin(Min_);
CurrentBox.GetMax(Max_);
}
#ifdef OPC_USE_FCOMI
Min.x = FCMin2(Min.x, Min_.x);
Max.x = FCMax2(Max.x, Max_.x);
Min.y = FCMin2(Min.y, Min_.y);
Max.y = FCMax2(Max.y, Max_.y);
Min.z = FCMin2(Min.z, Min_.z);
Max.z = FCMax2(Max.z, Max_.z);
#else
Min.Min(Min_);
Max.Max(Max_);
#endif
Current.mAABB.SetMinMax(Min, Max);
}
return true;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for hybrid models.
* \file OPC_HybridModel.cpp
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An hybrid collision model.
*
* The problem :
*
* Opcode really shines for mesh-mesh collision, especially when meshes are deeply overlapping
* (it typically outperforms RAPID in those cases).
*
* Unfortunately this is not the typical scenario in games.
*
* For close-proximity cases, especially for volume-mesh queries, it's relatively easy to run faster
* than Opcode, that suffers from a relatively high setup time.
*
* In particular, Opcode's "vanilla" trees in those cases -can- run faster. They can also use -less-
* memory than the optimized ones, when you let the system stop at ~10 triangles / leaf for example
* (i.e. when you don't use "complete" trees). However, those trees tend to fragment memory quite a
* lot, increasing cache misses : since they're not "complete", we can't predict the final number of
* nodes and we have to allocate nodes on-the-fly. For the same reasons we can't use Opcode's "optimized"
* trees here, since they rely on a known layout to perform the "optimization".
*
* Hybrid trees :
*
* Hybrid trees try to combine best of both worlds :
*
* - they use a maximum limit of 16 triangles/leaf. "16" is used so that we'll be able to save the
* number of triangles using 4 bits only.
*
* - they're still "complete" trees thanks to a two-passes building phase. First we create a "vanilla"
* AABB-tree with Opcode, limited to 16 triangles/leaf. Then we create a *second* vanilla tree, this
* time using the leaves of the first one. The trick is : this second tree is now "complete"... so we
* can further transform it into an Opcode's optimized tree.
*
* - then we run the collision queries on that standard Opcode tree. The only difference is that leaf
* nodes contain indices to leaf nodes of another tree. Also, we have to skip all primitive tests in
* Opcode optimized trees, since our leaves don't contain triangles anymore.
*
* - finally, for each collided leaf, we simply loop through 16 triangles max, and collide them with
* the bounding volume used in the query (we only support volume-vs-mesh queries here, not mesh-vs-mesh)
*
* All of that is wrapped in this "hybrid model" that contains the minimal data required for this to work.
* It's a mix between old "vanilla" trees, and old "optimized" trees.
*
* Extra advantages:
*
* - If we use them for dynamic models, we're left with a very small number of leaf nodes to refit. It
* might be a bit faster since we have less nodes to write back.
*
* - In rigid body simulation, using temporal coherence and sleeping objects greatly reduce the actual
* influence of one tree over another (i.e. the speed difference is often invisible). So memory is really
* the key element to consider, and in this regard hybrid trees are just better.
*
* Information to take home:
* - they use less ram
* - they're not slower (they're faster or slower depending on cases, overall there's no significant
* difference *as long as objects don't interpenetrate too much* - in which case Opcode's optimized trees
* are still notably faster)
*
* \class HybridModel
* \author Pierre Terdiman
* \version 1.3
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HybridModel::HybridModel() :
mNbLeaves (0),
mNbPrimitives (0),
mTriangles (null),
mIndices (null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HybridModel::~HybridModel()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases everything.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void HybridModel::Release()
{
ReleaseBase();
DELETEARRAY(mIndices);
DELETEARRAY(mTriangles);
mNbLeaves = 0;
mNbPrimitives = 0;
}
struct Internal
{
Internal()
{
mNbLeaves = 0;
mLeaves = null;
mTriangles = null;
mBase = null;
}
~Internal()
{
DELETEARRAY(mLeaves);
}
udword mNbLeaves;
AABB* mLeaves;
LeafTriangles* mTriangles;
const udword* mBase;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool HybridModel::Build(const OPCODECREATE& create)
{
// 1) Checkings
if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
// Look for degenerate faces.
udword NbDegenerate = create.mIMesh->CheckTopology();
if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
// We continue nonetheless....
Release(); // Make sure previous tree has been discarded
// 1-1) Setup mesh interface automatically
SetMeshInterface(create.mIMesh);
bool Status = false;
AABBTree* LeafTree = null;
Internal Data;
// 2) Build a generic AABB Tree.
mSource = new AABBTree;
CHECKALLOC(mSource);
// 2-1) Setup a builder. Our primitives here are triangles from input mesh,
// so we use an AABBTreeOfTrianglesBuilder.....
{
AABBTreeOfTrianglesBuilder TB;
TB.mIMesh = create.mIMesh;
TB.mNbPrimitives = create.mIMesh->GetNbTriangles();
TB.mSettings = create.mSettings;
TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
if(!mSource->Build(&TB)) goto FreeAndExit;
}
// 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
struct Local
{
// A callback to count leaf nodes
static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
{
if(current->IsLeaf())
{
Internal* Data = (Internal*)user_data;
Data->mNbLeaves++;
}
return true;
}
// A callback to setup leaf nodes in our internal structures
static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
{
if(current->IsLeaf())
{
Internal* Data = (Internal*)user_data;
// Get current leaf's box
Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();
// Setup leaf data
udword Index = (udword(current->GetPrimitives()) - udword(Data->mBase))/sizeof(udword);
Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);
Data->mNbLeaves++;
}
return true;
}
};
// Walk the tree & count number of leaves
Data.mNbLeaves = 0;
mSource->Walk(Local::CountLeaves, &Data);
mNbLeaves = Data.mNbLeaves; // Keep track of it
// Special case for 1-leaf meshes
if(mNbLeaves==1)
{
mModelCode |= OPC_SINGLE_NODE;
Status = true;
goto FreeAndExit;
}
// Allocate our structures
Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves);
mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles);
// Walk the tree again & setup leaf data
Data.mTriangles = mTriangles;
Data.mBase = mSource->GetIndices();
Data.mNbLeaves = 0; // Reset for incoming walk
mSource->Walk(Local::SetupLeafData, &Data);
// Handle source indices
{
bool MustKeepIndices = true;
if(create.mCanRemap)
{
// We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
// Remap can fail when we use callbacks => keep track of indices in that case (it still
// works, only using more memory)
if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
{
MustKeepIndices = false;
}
}
if(MustKeepIndices)
{
// Keep track of source indices (from vanilla tree)
mNbPrimitives = mSource->GetNbPrimitives();
mIndices = new udword[mNbPrimitives];
CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
}
}
// Now, create our optimized tree using previous leaf nodes
LeafTree = new AABBTree;
CHECKALLOC(LeafTree);
{
AABBTreeOfAABBsBuilder TB; // Now using boxes !
TB.mSettings = create.mSettings;
TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it
TB.mNbPrimitives = Data.mNbLeaves;
TB.mAABBArray = Data.mLeaves;
if(!LeafTree->Build(&TB)) goto FreeAndExit;
}
// 3) Create an optimized tree according to user-settings
if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit;
// 3-2) Create optimized tree
if(!mTree->Build(LeafTree)) goto FreeAndExit;
// Finally ok...
Status = true;
FreeAndExit: // Allow me this one...
DELETESINGLE(LeafTree);
// 3-3) Delete generic tree if needed
if(!create.mKeepOriginal) DELETESINGLE(mSource);
return Status;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword HybridModel::GetUsedBytes() const
{
udword UsedBytes = 0;
if(mTree) UsedBytes += mTree->GetUsedBytes();
if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices
if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles
return UsedBytes;
}
inline_ void ComputeMinMax_HM(Point& min, Point& max, const VertexPointers& vp)
{
// Compute triangle's AABB = a leaf box
#ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much
min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
#else
min = *vp.Vertex[0];
max = *vp.Vertex[0];
min.Min(*vp.Vertex[1]);
max.Max(*vp.Vertex[1]);
min.Min(*vp.Vertex[2]);
max.Max(*vp.Vertex[2]);
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool HybridModel::Refit()
{
if(!mIMesh) return false;
if(!mTree) return false;
if(IsQuantized()) return false;
if(HasLeafNodes()) return false;
const LeafTriangles* LT = GetLeafTriangles();
const udword* Indices = GetIndices();
// Bottom-up update
VertexPointers VP;
Point Min,Max;
Point Min_,Max_;
udword Index = mTree->GetNbNodes();
AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes();
while(Index--)
{
AABBNoLeafNode& Current = Nodes[Index];
if(Current.HasPosLeaf())
{
const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()];
Min.SetPlusInfinity();
Max.SetMinusInfinity();
Point TmpMin, TmpMax;
// Each leaf box has a set of triangles
udword NbTris = CurrentLeaf.GetNbTriangles();
if(Indices)
{
const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, *T++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min.Min(TmpMin);
Max.Max(TmpMax);
}
}
else
{
udword BaseIndex = CurrentLeaf.GetTriangleIndex();
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, BaseIndex++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min.Min(TmpMin);
Max.Max(TmpMax);
}
}
}
else
{
const CollisionAABB& CurrentBox = Current.GetPos()->mAABB;
CurrentBox.GetMin(Min);
CurrentBox.GetMax(Max);
}
if(Current.HasNegLeaf())
{
const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()];
Min_.SetPlusInfinity();
Max_.SetMinusInfinity();
Point TmpMin, TmpMax;
// Each leaf box has a set of triangles
udword NbTris = CurrentLeaf.GetNbTriangles();
if(Indices)
{
const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, *T++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min_.Min(TmpMin);
Max_.Max(TmpMax);
}
}
else
{
udword BaseIndex = CurrentLeaf.GetTriangleIndex();
// Loop through triangles and test each of them
while(NbTris--)
{
mIMesh->GetTriangle(VP, BaseIndex++);
ComputeMinMax_HM(TmpMin, TmpMax, VP);
Min_.Min(TmpMin);
Max_.Max(TmpMax);
}
}
}
else
{
const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB;
CurrentBox.GetMin(Min_);
CurrentBox.GetMax(Max_);
}
#ifdef OPC_USE_FCOMI
Min.x = FCMin2(Min.x, Min_.x);
Max.x = FCMax2(Max.x, Max_.x);
Min.y = FCMin2(Min.y, Min_.y);
Max.y = FCMax2(Max.y, Max_.y);
Min.z = FCMin2(Min.z, Min_.z);
Max.z = FCMax2(Max.z, Max_.z);
#else
Min.Min(Min_);
Max.Max(Max_);
#endif
Current.mAABB.SetMinMax(Min, Max);
}
return true;
}

View File

@@ -1,115 +1,115 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for hybrid models.
* \file OPC_HybridModel.h
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_HYBRIDMODEL_H__
#define __OPC_HYBRIDMODEL_H__
//! Leaf descriptor
struct LeafTriangles
{
udword Data; //!< Packed data
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets number of triangles in the leaf.
* \return number of triangles N, with 0 < N <= 16
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbTriangles() const { return (Data & 15)+1; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets triangle index for this leaf. Indexed model's array of indices retrieved with HybridModel::GetIndices()
* \return triangle index
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetTriangleIndex() const { return Data>>4; }
inline_ void SetData(udword nb, udword index) { ASSERT(nb>0 && nb<=16); nb--; Data = (index<<4)|(nb&15); }
};
class OPCODE_API HybridModel : public BaseModel
{
public:
// Constructor/Destructor
HybridModel();
virtual ~HybridModel();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Build(const OPCODECREATE& create);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) udword GetUsedBytes() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets array of triangles.
* \return array of triangles
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const LeafTriangles* GetLeafTriangles() const { return mTriangles; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets array of indices.
* \return array of indices
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const udword* GetIndices() const { return mIndices; }
private:
udword mNbLeaves; //!< Number of leaf nodes in the model
LeafTriangles* mTriangles; //!< Array of mNbLeaves leaf descriptors
udword mNbPrimitives; //!< Number of primitives in the model
udword* mIndices; //!< Array of primitive indices
// Internal methods
void Release();
};
#endif // __OPC_HYBRIDMODEL_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for hybrid models.
* \file OPC_HybridModel.h
* \author Pierre Terdiman
* \date May, 18, 2003
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_HYBRIDMODEL_H__
#define __OPC_HYBRIDMODEL_H__
//! Leaf descriptor
struct LeafTriangles
{
udword Data; //!< Packed data
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets number of triangles in the leaf.
* \return number of triangles N, with 0 < N <= 16
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbTriangles() const { return (Data & 15)+1; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets triangle index for this leaf. Indexed model's array of indices retrieved with HybridModel::GetIndices()
* \return triangle index
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetTriangleIndex() const { return Data>>4; }
inline_ void SetData(udword nb, udword index) { ASSERT(nb>0 && nb<=16); nb--; Data = (index<<4)|(nb&15); }
};
class OPCODE_API HybridModel : public BaseModel
{
public:
// Constructor/Destructor
HybridModel();
virtual ~HybridModel();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Build(const OPCODECREATE& create);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) udword GetUsedBytes() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision model. This can be used to handle dynamic meshes. Usage is:
* 1. modify your mesh vertices (keep the topology constant!)
* 2. refit the tree (call this method)
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Refit();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets array of triangles.
* \return array of triangles
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const LeafTriangles* GetLeafTriangles() const { return mTriangles; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets array of indices.
* \return array of indices
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const udword* GetIndices() const { return mIndices; }
private:
udword mNbLeaves; //!< Number of leaf nodes in the model
LeafTriangles* mTriangles; //!< Array of mNbLeaves leaf descriptors
udword mNbPrimitives; //!< Number of primitives in the model
udword* mIndices; //!< Array of primitive indices
// Internal methods
void Release();
};
#endif // __OPC_HYBRIDMODEL_H__

View File

@@ -1,92 +1,92 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Should be included by Opcode.h if needed
#define ICE_DONT_CHECK_COMPILER_OPTIONS
// From Windows...
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <float.h>
#include <Math.h>
#ifndef ASSERT
#define ASSERT(exp) {}
#endif
#define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ]
#define Log {}
#define SetIceError false
#define EC_OUTOFMEMORY "Out of memory"
#include ".\Ice\IcePreprocessor.h"
#undef ICECORE_API
#define ICECORE_API OPCODE_API
#include ".\Ice\IceTypes.h"
#include ".\Ice\IceFPU.h"
#include ".\Ice\IceMemoryMacros.h"
namespace Opcode
{
namespace IceCore
{
#include ".\Ice\IceAllocator.h"
#include ".\Ice\IceUtils.h"
#include ".\Ice\IceBitArray.h"
#include ".\Ice\IceContainer.h"
#include ".\Ice\IcePairs.h"
#include ".\Ice\IceRevisitedRadix.h"
#include ".\Ice\IceRandom.h"
#include ".\Ice\IceHashing.h"
}
using namespace IceCore;
#define ICEMATHS_API OPCODE_API
namespace IceMaths
{
#include ".\Ice\IceAxes.h"
#include ".\Ice\IcePoint.h"
#include ".\Ice\IceHPoint.h"
#include ".\Ice\IceMatrix3x3.h"
#include ".\Ice\IceMatrix4x4.h"
#include ".\Ice\IcePlane.h"
#include ".\Ice\IceRay.h"
#include ".\Ice\IceIndexedTriangle.h"
#include ".\Ice\IceTriangle.h"
#include ".\Ice\IceTriList.h"
#include ".\Ice\IceAABB.h"
#include ".\Ice\IceOBB.h"
#include ".\Ice\IceBoundingSphere.h"
#include ".\Ice\IceSegment.h"
#include ".\Ice\IceLSS.h"
}
using namespace IceMaths;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Should be included by Opcode.h if needed
#define ICE_DONT_CHECK_COMPILER_OPTIONS
// From Windows...
typedef int BOOL;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <float.h>
#include <Math.h>
#ifndef ASSERT
#define ASSERT(exp) {}
#endif
#define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ]
#define Log {}
#define SetIceError false
#define EC_OUTOFMEMORY "Out of memory"
#include ".\Ice\IcePreprocessor.h"
#undef ICECORE_API
#define ICECORE_API OPCODE_API
#include ".\Ice\IceTypes.h"
#include ".\Ice\IceFPU.h"
#include ".\Ice\IceMemoryMacros.h"
namespace Opcode
{
namespace IceCore
{
#include ".\Ice\IceAllocator.h"
#include ".\Ice\IceUtils.h"
#include ".\Ice\IceBitArray.h"
#include ".\Ice\IceContainer.h"
#include ".\Ice\IcePairs.h"
#include ".\Ice\IceRevisitedRadix.h"
#include ".\Ice\IceRandom.h"
#include ".\Ice\IceHashing.h"
}
using namespace IceCore;
#define ICEMATHS_API OPCODE_API
namespace IceMaths
{
#include ".\Ice\IceAxes.h"
#include ".\Ice\IcePoint.h"
#include ".\Ice\IceHPoint.h"
#include ".\Ice\IceMatrix3x3.h"
#include ".\Ice\IceMatrix4x4.h"
#include ".\Ice\IcePlane.h"
#include ".\Ice\IceRay.h"
#include ".\Ice\IceIndexedTriangle.h"
#include ".\Ice\IceTriangle.h"
#include ".\Ice\IceTriList.h"
#include ".\Ice\IceAABB.h"
#include ".\Ice\IceOBB.h"
#include ".\Ice\IceBoundingSphere.h"
#include ".\Ice\IceSegment.h"
#include ".\Ice\IceLSS.h"
}
using namespace IceMaths;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +1,108 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an LSS collider.
* \file OPC_LSSCollider.h
* \author Pierre Terdiman
* \date December, 28, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_LSSCOLLIDER_H__
#define __OPC_LSSCOLLIDER_H__
struct OPCODE_API LSSCache : VolumeCache
{
LSSCache()
{
Previous.mP0 = Point(0.0f, 0.0f, 0.0f);
Previous.mP1 = Point(0.0f, 0.0f, 0.0f);
Previous.mRadius = 0.0f;
FatCoeff = 1.1f;
}
// Cached faces signature
LSS Previous; //!< LSS used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat LSS
};
class OPCODE_API LSSCollider : public VolumeCollider
{
public:
// Constructor / Destructor
LSSCollider();
virtual ~LSSCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] an lss cache
* \param lss [in] collision lss in local space
* \param model [in] Opcode model to collide with
* \param worldl [in] lss world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
//
bool Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree);
protected:
// LSS in model space
Segment mSeg; //!< Segment
float mRadius2; //!< LSS radius squared
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL LSSContainsBox(const Point& bc, const Point& be);
inline_ BOOL LSSAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL LSSTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridLSSCollider : public LSSCollider
{
public:
// Constructor / Destructor
HybridLSSCollider();
virtual ~HybridLSSCollider();
bool Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_LSSCOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an LSS collider.
* \file OPC_LSSCollider.h
* \author Pierre Terdiman
* \date December, 28, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_LSSCOLLIDER_H__
#define __OPC_LSSCOLLIDER_H__
struct OPCODE_API LSSCache : VolumeCache
{
LSSCache()
{
Previous.mP0 = Point(0.0f, 0.0f, 0.0f);
Previous.mP1 = Point(0.0f, 0.0f, 0.0f);
Previous.mRadius = 0.0f;
FatCoeff = 1.1f;
}
// Cached faces signature
LSS Previous; //!< LSS used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat LSS
};
class OPCODE_API LSSCollider : public VolumeCollider
{
public:
// Constructor / Destructor
LSSCollider();
virtual ~LSSCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] an lss cache
* \param lss [in] collision lss in local space
* \param model [in] Opcode model to collide with
* \param worldl [in] lss world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
//
bool Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree);
protected:
// LSS in model space
Segment mSeg; //!< Segment
float mRadius2; //!< LSS radius squared
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL LSSContainsBox(const Point& bc, const Point& be);
inline_ BOOL LSSAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL LSSTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridLSSCollider : public LSSCollider
{
public:
// Constructor / Destructor
HybridLSSCollider();
virtual ~HybridLSSCollider();
bool Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_LSSCOLLIDER_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,308 +1,308 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a mesh interface.
* \file OPC_MeshInterface.cpp
* \author Pierre Terdiman
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This structure holds 3 vertex-pointers. It's mainly used by collision callbacks so that the app doesn't have
* to return 3 vertices to OPCODE (36 bytes) but only 3 pointers (12 bytes). It seems better but I never profiled
* the alternative.
*
* \class VertexPointers
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This class is an interface between us and user-defined meshes. Meshes can be defined in a lot of ways, and here we
* try to support most of them.
*
* Basically you have two options:
* - callbacks, if OPC_USE_CALLBACKS is defined in OPC_Settings.h.
* - else pointers.
*
* If using pointers, you can also use strides or not. Strides are used when OPC_USE_STRIDE is defined.
*
*
* CALLBACKS:
*
* Using callbacks is the most generic way to feed OPCODE with your meshes. Indeed, you just have to give
* access to three vertices at the end of the day. It's up to you to fetch them from your database, using
* whatever method you want. Hence your meshes can lie in system memory or AGP, be indexed or not, use 16
* or 32-bits indices, you can decompress them on-the-fly if needed, etc. On the other hand, a callback is
* called each time OPCODE needs access to a particular triangle, so there might be a slight overhead.
*
* To make things clear: geometry & topology are NOT stored in the collision system,
* in order to save some ram. So, when the system needs them to perform accurate intersection
* tests, you're requested to provide the triangle-vertices corresponding to a given face index.
*
* Ex:
*
* \code
* static void ColCallback(udword triangle_index, VertexPointers& triangle, udword user_data)
* {
* // Get back Mesh0 or Mesh1 (you also can use 2 different callbacks)
* Mesh* MyMesh = (Mesh*)user_data;
* // Get correct triangle in the app-controlled database
* const Triangle* Tri = MyMesh->GetTriangle(triangle_index);
* // Setup pointers to vertices for the collision system
* triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]);
* triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]);
* triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]);
* }
*
* // Setup callbacks
* MeshInterface0->SetCallback(ColCallback, udword(Mesh0));
* MeshInterface1->SetCallback(ColCallback, udword(Mesh1));
* \endcode
*
* Of course, you should make this callback as fast as possible. And you're also not supposed
* to modify the geometry *after* the collision trees have been built. The alternative was to
* store the geometry & topology in the collision system as well (as in RAPID) but we have found
* this approach to waste a lot of ram in many cases.
*
*
* POINTERS:
*
* If you're internally using the following canonical structures:
* - a vertex made of three 32-bits floating point values
* - a triangle made of three 32-bits integer vertex references
* ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly
* use provided pointers to access the topology and geometry, without using a callback. It might be faster,
* but probably not as safe. Pointers have been introduced in OPCODE 1.2.
*
* Ex:
*
* \code
* // Setup pointers
* MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts());
* MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts());
* \endcode
*
*
* STRIDES:
*
* If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates
* (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE
* doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase
* cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers !
*
*
* In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so
* choose what's best for your application. All of this has been wrapped into this MeshInterface.
*
* \class MeshInterface
* \author Pierre Terdiman
* \version 1.3
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MeshInterface::MeshInterface() :
#ifdef OPC_USE_CALLBACKS
mUserData (null),
mObjCallback (null),
#else
mTris (null),
mVerts (null),
#ifdef OPC_USE_STRIDE
mTriStride (sizeof(IndexedTriangle)),
mVertexStride (sizeof(Point)),
#endif
#endif
mNbTris (0),
mNbVerts (0)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MeshInterface::~MeshInterface()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh interface is valid, i.e. things have been setup correctly.
* \return true if valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::IsValid() const
{
if(!mNbTris || !mNbVerts) return false;
#ifdef OPC_USE_CALLBACKS
if(!mObjCallback) return false;
#else
if(!mTris || !mVerts) return false;
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh itself is valid.
* Currently we only look for degenerate faces.
* \return number of degenerate faces
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword MeshInterface::CheckTopology() const
{
// Check topology. If the model contains degenerate faces, collision report can be wrong in some cases.
// e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner
// you can try this: www.codercorner.com/Consolidation.zip
udword NbDegenerate = 0;
VertexPointers VP;
// Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for
// redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides).
for(udword i=0;i<mNbTris;i++)
{
GetTriangle(VP, i);
if( (VP.Vertex[0]==VP.Vertex[1])
|| (VP.Vertex[1]==VP.Vertex[2])
|| (VP.Vertex[2]==VP.Vertex[0])) NbDegenerate++;
}
return NbDegenerate;
}
#ifdef OPC_USE_CALLBACKS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
* \param callback [in] user-defined callback
* \param user_data [in] user-defined data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetCallback(RequestCallback callback, void* user_data)
{
if(!callback) return SetIceError("MeshInterface::SetCallback: callback pointer is null");
mObjCallback = callback;
mUserData = user_data;
return true;
}
#else
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
* \param tris [in] pointer to triangles
* \param verts [in] pointer to vertices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetPointers(const IndexedTriangle* tris, const Point* verts)
{
if(!tris || !verts) return SetIceError("MeshInterface::SetPointers: pointer is null", null);
mTris = tris;
mVerts = verts;
return true;
}
#ifdef OPC_USE_STRIDE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Strides control
* \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
* \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetStrides(udword tri_stride, udword vertex_stride)
{
if(tri_stride<sizeof(IndexedTriangle)) return SetIceError("MeshInterface::SetStrides: invalid triangle stride", null);
if(vertex_stride<sizeof(Point)) return SetIceError("MeshInterface::SetStrides: invalid vertex stride", null);
mTriStride = tri_stride;
mVertexStride = vertex_stride;
return true;
}
#endif
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Remaps client's mesh according to a permutation.
* \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles)
* \param permutation [in] list of triangle indices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::RemapClient(udword nb_indices, const udword* permutation) const
{
// Checkings
if(!nb_indices || !permutation) return false;
if(nb_indices!=mNbTris) return false;
#ifdef OPC_USE_CALLBACKS
// We can't really do that using callbacks
return false;
#else
IndexedTriangle* Tmp = new IndexedTriangle[mNbTris];
CHECKALLOC(Tmp);
#ifdef OPC_USE_STRIDE
udword Stride = mTriStride;
#else
udword Stride = sizeof(IndexedTriangle);
#endif
for(udword i=0;i<mNbTris;i++)
{
const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + i * Stride);
Tmp[i] = *T;
}
for(udword i=0;i<mNbTris;i++)
{
IndexedTriangle* T = (IndexedTriangle*)(((ubyte*)mTris) + i * Stride);
*T = Tmp[permutation[i]];
}
DELETEARRAY(Tmp);
#endif
return true;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a mesh interface.
* \file OPC_MeshInterface.cpp
* \author Pierre Terdiman
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This structure holds 3 vertex-pointers. It's mainly used by collision callbacks so that the app doesn't have
* to return 3 vertices to OPCODE (36 bytes) but only 3 pointers (12 bytes). It seems better but I never profiled
* the alternative.
*
* \class VertexPointers
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* This class is an interface between us and user-defined meshes. Meshes can be defined in a lot of ways, and here we
* try to support most of them.
*
* Basically you have two options:
* - callbacks, if OPC_USE_CALLBACKS is defined in OPC_Settings.h.
* - else pointers.
*
* If using pointers, you can also use strides or not. Strides are used when OPC_USE_STRIDE is defined.
*
*
* CALLBACKS:
*
* Using callbacks is the most generic way to feed OPCODE with your meshes. Indeed, you just have to give
* access to three vertices at the end of the day. It's up to you to fetch them from your database, using
* whatever method you want. Hence your meshes can lie in system memory or AGP, be indexed or not, use 16
* or 32-bits indices, you can decompress them on-the-fly if needed, etc. On the other hand, a callback is
* called each time OPCODE needs access to a particular triangle, so there might be a slight overhead.
*
* To make things clear: geometry & topology are NOT stored in the collision system,
* in order to save some ram. So, when the system needs them to perform accurate intersection
* tests, you're requested to provide the triangle-vertices corresponding to a given face index.
*
* Ex:
*
* \code
* static void ColCallback(udword triangle_index, VertexPointers& triangle, udword user_data)
* {
* // Get back Mesh0 or Mesh1 (you also can use 2 different callbacks)
* Mesh* MyMesh = (Mesh*)user_data;
* // Get correct triangle in the app-controlled database
* const Triangle* Tri = MyMesh->GetTriangle(triangle_index);
* // Setup pointers to vertices for the collision system
* triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]);
* triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]);
* triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]);
* }
*
* // Setup callbacks
* MeshInterface0->SetCallback(ColCallback, udword(Mesh0));
* MeshInterface1->SetCallback(ColCallback, udword(Mesh1));
* \endcode
*
* Of course, you should make this callback as fast as possible. And you're also not supposed
* to modify the geometry *after* the collision trees have been built. The alternative was to
* store the geometry & topology in the collision system as well (as in RAPID) but we have found
* this approach to waste a lot of ram in many cases.
*
*
* POINTERS:
*
* If you're internally using the following canonical structures:
* - a vertex made of three 32-bits floating point values
* - a triangle made of three 32-bits integer vertex references
* ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly
* use provided pointers to access the topology and geometry, without using a callback. It might be faster,
* but probably not as safe. Pointers have been introduced in OPCODE 1.2.
*
* Ex:
*
* \code
* // Setup pointers
* MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts());
* MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts());
* \endcode
*
*
* STRIDES:
*
* If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates
* (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE
* doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase
* cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers !
*
*
* In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so
* choose what's best for your application. All of this has been wrapped into this MeshInterface.
*
* \class MeshInterface
* \author Pierre Terdiman
* \version 1.3
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MeshInterface::MeshInterface() :
#ifdef OPC_USE_CALLBACKS
mUserData (null),
mObjCallback (null),
#else
mTris (null),
mVerts (null),
#ifdef OPC_USE_STRIDE
mTriStride (sizeof(IndexedTriangle)),
mVertexStride (sizeof(Point)),
#endif
#endif
mNbTris (0),
mNbVerts (0)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MeshInterface::~MeshInterface()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh interface is valid, i.e. things have been setup correctly.
* \return true if valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::IsValid() const
{
if(!mNbTris || !mNbVerts) return false;
#ifdef OPC_USE_CALLBACKS
if(!mObjCallback) return false;
#else
if(!mTris || !mVerts) return false;
#endif
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh itself is valid.
* Currently we only look for degenerate faces.
* \return number of degenerate faces
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword MeshInterface::CheckTopology() const
{
// Check topology. If the model contains degenerate faces, collision report can be wrong in some cases.
// e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner
// you can try this: www.codercorner.com/Consolidation.zip
udword NbDegenerate = 0;
VertexPointers VP;
// Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for
// redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides).
for(udword i=0;i<mNbTris;i++)
{
GetTriangle(VP, i);
if( (VP.Vertex[0]==VP.Vertex[1])
|| (VP.Vertex[1]==VP.Vertex[2])
|| (VP.Vertex[2]==VP.Vertex[0])) NbDegenerate++;
}
return NbDegenerate;
}
#ifdef OPC_USE_CALLBACKS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
* \param callback [in] user-defined callback
* \param user_data [in] user-defined data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetCallback(RequestCallback callback, void* user_data)
{
if(!callback) return SetIceError("MeshInterface::SetCallback: callback pointer is null");
mObjCallback = callback;
mUserData = user_data;
return true;
}
#else
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
* \param tris [in] pointer to triangles
* \param verts [in] pointer to vertices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetPointers(const IndexedTriangle* tris, const Point* verts)
{
if(!tris || !verts) return SetIceError("MeshInterface::SetPointers: pointer is null", null);
mTris = tris;
mVerts = verts;
return true;
}
#ifdef OPC_USE_STRIDE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Strides control
* \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
* \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::SetStrides(udword tri_stride, udword vertex_stride)
{
if(tri_stride<sizeof(IndexedTriangle)) return SetIceError("MeshInterface::SetStrides: invalid triangle stride", null);
if(vertex_stride<sizeof(Point)) return SetIceError("MeshInterface::SetStrides: invalid vertex stride", null);
mTriStride = tri_stride;
mVertexStride = vertex_stride;
return true;
}
#endif
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Remaps client's mesh according to a permutation.
* \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles)
* \param permutation [in] list of triangle indices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool MeshInterface::RemapClient(udword nb_indices, const udword* permutation) const
{
// Checkings
if(!nb_indices || !permutation) return false;
if(nb_indices!=mNbTris) return false;
#ifdef OPC_USE_CALLBACKS
// We can't really do that using callbacks
return false;
#else
IndexedTriangle* Tmp = new IndexedTriangle[mNbTris];
CHECKALLOC(Tmp);
#ifdef OPC_USE_STRIDE
udword Stride = mTriStride;
#else
udword Stride = sizeof(IndexedTriangle);
#endif
for(udword i=0;i<mNbTris;i++)
{
const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + i * Stride);
Tmp[i] = *T;
}
for(udword i=0;i<mNbTris;i++)
{
IndexedTriangle* T = (IndexedTriangle*)(((ubyte*)mTris) + i * Stride);
*T = Tmp[permutation[i]];
}
DELETEARRAY(Tmp);
#endif
return true;
}

View File

@@ -1,191 +1,191 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a mesh interface.
* \file OPC_MeshInterface.h
* \author Pierre Terdiman
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_MESHINTERFACE_H__
#define __OPC_MESHINTERFACE_H__
struct VertexPointers
{
const Point* Vertex[3];
bool BackfaceCulling(const Point& source)
{
const Point& p0 = *Vertex[0];
const Point& p1 = *Vertex[1];
const Point& p2 = *Vertex[2];
// Compute normal direction
Point Normal = (p2 - p1)^(p0 - p1);
// Backface culling
return (Normal | (source - p0)) >= 0.0f;
}
};
#ifdef OPC_USE_CALLBACKS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called by OPCODE to request vertices from the app.
* \param triangle_index [in] face index for which the system is requesting the vertices
* \param triangle [out] triangle's vertices (must be provided by the user)
* \param user_data [in] user-defined data from SetCallback()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef void (*RequestCallback) (udword triangle_index, VertexPointers& triangle, void* user_data);
#endif
class OPCODE_API MeshInterface
{
public:
// Constructor / Destructor
MeshInterface();
~MeshInterface();
// Common settings
inline_ udword GetNbTriangles() const { return mNbTris; }
inline_ udword GetNbVertices() const { return mNbVerts; }
inline_ void SetNbTriangles(udword nb) { mNbTris = nb; }
inline_ void SetNbVertices(udword nb) { mNbVerts = nb; }
#ifdef OPC_USE_CALLBACKS
// Callback settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
* \param callback [in] user-defined callback
* \param user_data [in] user-defined data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetCallback(RequestCallback callback, void* user_data);
inline_ void* GetUserData() const { return mUserData; }
inline_ RequestCallback GetCallback() const { return mObjCallback; }
#else
// Pointers settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
* \param tris [in] pointer to triangles
* \param verts [in] pointer to vertices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetPointers(const IndexedTriangle* tris, const Point* verts);
inline_ const IndexedTriangle* GetTris() const { return mTris; }
inline_ const Point* GetVerts() const { return mVerts; }
#ifdef OPC_USE_STRIDE
// Strides settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Strides control
* \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
* \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point));
inline_ udword GetTriStride() const { return mTriStride; }
inline_ udword GetVertexStride() const { return mVertexStride; }
#endif
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Fetches a triangle given a triangle index.
* \param vp [out] required triangle's vertex pointers
* \param index [in] triangle index
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void GetTriangle(VertexPointers& vp, udword index) const
{
#ifdef OPC_USE_CALLBACKS
(mObjCallback)(index, vp, mUserData);
#else
#ifdef OPC_USE_STRIDE
const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride);
vp.Vertex[0] = (const Point*)(((ubyte*)mVerts) + T->mVRef[0] * mVertexStride);
vp.Vertex[1] = (const Point*)(((ubyte*)mVerts) + T->mVRef[1] * mVertexStride);
vp.Vertex[2] = (const Point*)(((ubyte*)mVerts) + T->mVRef[2] * mVertexStride);
#else
const IndexedTriangle* T = &mTris[index];
vp.Vertex[0] = &mVerts[T->mVRef[0]];
vp.Vertex[1] = &mVerts[T->mVRef[1]];
vp.Vertex[2] = &mVerts[T->mVRef[2]];
#endif
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Remaps client's mesh according to a permutation.
* \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles)
* \param permutation [in] list of triangle indices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool RemapClient(udword nb_indices, const udword* permutation) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh interface is valid, i.e. things have been setup correctly.
* \return true if valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IsValid() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh itself is valid.
* Currently we only look for degenerate faces.
* \return number of degenerate faces
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword CheckTopology() const;
private:
udword mNbTris; //!< Number of triangles in the input model
udword mNbVerts; //!< Number of vertices in the input model
#ifdef OPC_USE_CALLBACKS
// User callback
void* mUserData; //!< User-defined data sent to callback
RequestCallback mObjCallback; //!< Object callback
#else
// User pointers
const IndexedTriangle* mTris; //!< Array of indexed triangles
const Point* mVerts; //!< Array of vertices
#ifdef OPC_USE_STRIDE
udword mTriStride; //!< Possible triangle stride in bytes [Opcode 1.3]
udword mVertexStride; //!< Possible vertex stride in bytes [Opcode 1.3]
#endif
#endif
};
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains a mesh interface.
* \file OPC_MeshInterface.h
* \author Pierre Terdiman
* \date November, 27, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_MESHINTERFACE_H__
#define __OPC_MESHINTERFACE_H__
struct VertexPointers
{
const Point* Vertex[3];
bool BackfaceCulling(const Point& source)
{
const Point& p0 = *Vertex[0];
const Point& p1 = *Vertex[1];
const Point& p2 = *Vertex[2];
// Compute normal direction
Point Normal = (p2 - p1)^(p0 - p1);
// Backface culling
return (Normal | (source - p0)) >= 0.0f;
}
};
#ifdef OPC_USE_CALLBACKS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called by OPCODE to request vertices from the app.
* \param triangle_index [in] face index for which the system is requesting the vertices
* \param triangle [out] triangle's vertices (must be provided by the user)
* \param user_data [in] user-defined data from SetCallback()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef void (*RequestCallback) (udword triangle_index, VertexPointers& triangle, void* user_data);
#endif
class OPCODE_API MeshInterface
{
public:
// Constructor / Destructor
MeshInterface();
~MeshInterface();
// Common settings
inline_ udword GetNbTriangles() const { return mNbTris; }
inline_ udword GetNbVertices() const { return mNbVerts; }
inline_ void SetNbTriangles(udword nb) { mNbTris = nb; }
inline_ void SetNbVertices(udword nb) { mNbVerts = nb; }
#ifdef OPC_USE_CALLBACKS
// Callback settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
* \param callback [in] user-defined callback
* \param user_data [in] user-defined data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetCallback(RequestCallback callback, void* user_data);
inline_ void* GetUserData() const { return mUserData; }
inline_ RequestCallback GetCallback() const { return mObjCallback; }
#else
// Pointers settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
* \param tris [in] pointer to triangles
* \param verts [in] pointer to vertices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetPointers(const IndexedTriangle* tris, const Point* verts);
inline_ const IndexedTriangle* GetTris() const { return mTris; }
inline_ const Point* GetVerts() const { return mVerts; }
#ifdef OPC_USE_STRIDE
// Strides settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Strides control
* \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
* \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point));
inline_ udword GetTriStride() const { return mTriStride; }
inline_ udword GetVertexStride() const { return mVertexStride; }
#endif
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Fetches a triangle given a triangle index.
* \param vp [out] required triangle's vertex pointers
* \param index [in] triangle index
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void GetTriangle(VertexPointers& vp, udword index) const
{
#ifdef OPC_USE_CALLBACKS
(mObjCallback)(index, vp, mUserData);
#else
#ifdef OPC_USE_STRIDE
const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride);
vp.Vertex[0] = (const Point*)(((ubyte*)mVerts) + T->mVRef[0] * mVertexStride);
vp.Vertex[1] = (const Point*)(((ubyte*)mVerts) + T->mVRef[1] * mVertexStride);
vp.Vertex[2] = (const Point*)(((ubyte*)mVerts) + T->mVRef[2] * mVertexStride);
#else
const IndexedTriangle* T = &mTris[index];
vp.Vertex[0] = &mVerts[T->mVRef[0]];
vp.Vertex[1] = &mVerts[T->mVRef[1]];
vp.Vertex[2] = &mVerts[T->mVRef[2]];
#endif
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Remaps client's mesh according to a permutation.
* \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles)
* \param permutation [in] list of triangle indices
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ bool RemapClient(udword nb_indices, const udword* permutation) const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh interface is valid, i.e. things have been setup correctly.
* \return true if valid
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IsValid() const;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Checks the mesh itself is valid.
* Currently we only look for degenerate faces.
* \return number of degenerate faces
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword CheckTopology() const;
private:
udword mNbTris; //!< Number of triangles in the input model
udword mNbVerts; //!< Number of vertices in the input model
#ifdef OPC_USE_CALLBACKS
// User callback
void* mUserData; //!< User-defined data sent to callback
RequestCallback mObjCallback; //!< Object callback
#else
// User pointers
const IndexedTriangle* mTris; //!< Array of indexed triangles
const Point* mVerts; //!< Array of vertices
#ifdef OPC_USE_STRIDE
udword mTriStride; //!< Possible triangle stride in bytes [Opcode 1.3]
udword mVertexStride; //!< Possible vertex stride in bytes [Opcode 1.3]
#endif
#endif
};
#endif //__OPC_MESHINTERFACE_H__

View File

@@ -1,231 +1,231 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for OPCODE models.
* \file OPC_Model.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The main collision wrapper, for all trees. Supported trees are:
* - Normal trees (2*N-1 nodes, full size)
* - No-leaf trees (N-1 nodes, full size)
* - Quantized trees (2*N-1 nodes, half size)
* - Quantized no-leaf trees (N-1 nodes, half size)
*
* Usage:
*
* 1) Create a static mesh interface using callbacks or pointers. (see OPC_MeshInterface.cpp).
* Keep it around in your app, since a pointer to this interface is saved internally and
* used until you release the collision structures.
*
* 2) Build a Model using a creation structure:
*
* \code
* Model Sample;
*
* OPCODECREATE OPCC;
* OPCC.IMesh = ...;
* OPCC.Rules = ...;
* OPCC.NoLeaf = ...;
* OPCC.Quantized = ...;
* OPCC.KeepOriginal = ...;
* bool Status = Sample.Build(OPCC);
* \endcode
*
* 3) Create a tree collider and set it up:
*
* \code
* AABBTreeCollider TC;
* TC.SetFirstContact(...);
* TC.SetFullBoxBoxTest(...);
* TC.SetFullPrimBoxTest(...);
* TC.SetTemporalCoherence(...);
* \endcode
*
* 4) Perform a collision query
*
* \code
* // Setup cache
* static BVTCache ColCache;
* ColCache.Model0 = &Model0;
* ColCache.Model1 = &Model1;
*
* // Collision query
* bool IsOk = TC.Collide(ColCache, World0, World1);
*
* // Get collision status => if true, objects overlap
* BOOL Status = TC.GetContactStatus();
*
* // Number of colliding pairs and list of pairs
* udword NbPairs = TC.GetNbPairs();
* const Pair* p = TC.GetPairs()
* \endcode
*
* 5) Stats
*
* \code
* Model0.GetUsedBytes() = number of bytes used for this collision tree
* TC.GetNbBVBVTests() = number of BV-BV overlap tests performed during last query
* TC.GetNbPrimPrimTests() = number of Triangle-Triangle overlap tests performed during last query
* TC.GetNbBVPrimTests() = number of Triangle-BV overlap tests performed during last query
* \endcode
*
* \class Model
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::Model()
{
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
mHull = null;
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::~Model()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases the model.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Model::Release()
{
ReleaseBase();
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
DELETESINGLE(mHull);
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Model::Build(const OPCODECREATE& create)
{
// 1) Checkings
if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
// For this model, we only support complete trees
if(create.mSettings.mLimit!=1) return SetIceError("OPCODE WARNING: supports complete trees only! Use mLimit = 1.\n", null);
// Look for degenerate faces.
udword NbDegenerate = create.mIMesh->CheckTopology();
if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
// We continue nonetheless....
Release(); // Make sure previous tree has been discarded [Opcode 1.3, thanks Adam]
// 1-1) Setup mesh interface automatically [Opcode 1.3]
SetMeshInterface(create.mIMesh);
// Special case for 1-triangle meshes [Opcode 1.3]
udword NbTris = create.mIMesh->GetNbTriangles();
if(NbTris==1)
{
// We don't need to actually create a tree here, since we'll only have a single triangle to deal with anyway.
// It's a waste to use a "model" for this but at least it will work.
mModelCode |= OPC_SINGLE_NODE;
return true;
}
// 2) Build a generic AABB Tree.
mSource = new AABBTree;
CHECKALLOC(mSource);
// 2-1) Setup a builder. Our primitives here are triangles from input mesh,
// so we use an AABBTreeOfTrianglesBuilder.....
{
AABBTreeOfTrianglesBuilder TB;
TB.mIMesh = create.mIMesh;
TB.mSettings = create.mSettings;
TB.mNbPrimitives = NbTris;
if(!mSource->Build(&TB)) return false;
}
// 3) Create an optimized tree according to user-settings
if(!CreateTree(create.mNoLeaf, create.mQuantized)) return false;
// 3-2) Create optimized tree
if(!mTree->Build(mSource)) return false;
// 3-3) Delete generic tree if needed
if(!create.mKeepOriginal) DELETESINGLE(mSource);
#ifdef __MESHMERIZER_H__
// 4) Convex hull
if(create.mCollisionHull)
{
// Create hull
mHull = new CollisionHull;
CHECKALLOC(mHull);
CONVEXHULLCREATE CHC;
// ### doesn't work with strides
CHC.NbVerts = create.mIMesh->GetNbVertices();
CHC.Vertices = create.mIMesh->GetVerts();
CHC.UnifyNormals = true;
CHC.ReduceVertices = true;
CHC.WordFaces = false;
mHull->Compute(CHC);
}
#endif // __MESHMERIZER_H__
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Model::GetUsedBytes() const
{
if(!mTree) return 0;
return mTree->GetUsedBytes();
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for OPCODE models.
* \file OPC_Model.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The main collision wrapper, for all trees. Supported trees are:
* - Normal trees (2*N-1 nodes, full size)
* - No-leaf trees (N-1 nodes, full size)
* - Quantized trees (2*N-1 nodes, half size)
* - Quantized no-leaf trees (N-1 nodes, half size)
*
* Usage:
*
* 1) Create a static mesh interface using callbacks or pointers. (see OPC_MeshInterface.cpp).
* Keep it around in your app, since a pointer to this interface is saved internally and
* used until you release the collision structures.
*
* 2) Build a Model using a creation structure:
*
* \code
* Model Sample;
*
* OPCODECREATE OPCC;
* OPCC.IMesh = ...;
* OPCC.Rules = ...;
* OPCC.NoLeaf = ...;
* OPCC.Quantized = ...;
* OPCC.KeepOriginal = ...;
* bool Status = Sample.Build(OPCC);
* \endcode
*
* 3) Create a tree collider and set it up:
*
* \code
* AABBTreeCollider TC;
* TC.SetFirstContact(...);
* TC.SetFullBoxBoxTest(...);
* TC.SetFullPrimBoxTest(...);
* TC.SetTemporalCoherence(...);
* \endcode
*
* 4) Perform a collision query
*
* \code
* // Setup cache
* static BVTCache ColCache;
* ColCache.Model0 = &Model0;
* ColCache.Model1 = &Model1;
*
* // Collision query
* bool IsOk = TC.Collide(ColCache, World0, World1);
*
* // Get collision status => if true, objects overlap
* BOOL Status = TC.GetContactStatus();
*
* // Number of colliding pairs and list of pairs
* udword NbPairs = TC.GetNbPairs();
* const Pair* p = TC.GetPairs()
* \endcode
*
* 5) Stats
*
* \code
* Model0.GetUsedBytes() = number of bytes used for this collision tree
* TC.GetNbBVBVTests() = number of BV-BV overlap tests performed during last query
* TC.GetNbPrimPrimTests() = number of Triangle-Triangle overlap tests performed during last query
* TC.GetNbBVPrimTests() = number of Triangle-BV overlap tests performed during last query
* \endcode
*
* \class Model
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::Model()
{
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
mHull = null;
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::~Model()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases the model.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Model::Release()
{
ReleaseBase();
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
DELETESINGLE(mHull);
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Model::Build(const OPCODECREATE& create)
{
// 1) Checkings
if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
// For this model, we only support complete trees
if(create.mSettings.mLimit!=1) return SetIceError("OPCODE WARNING: supports complete trees only! Use mLimit = 1.\n", null);
// Look for degenerate faces.
udword NbDegenerate = create.mIMesh->CheckTopology();
if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
// We continue nonetheless....
Release(); // Make sure previous tree has been discarded [Opcode 1.3, thanks Adam]
// 1-1) Setup mesh interface automatically [Opcode 1.3]
SetMeshInterface(create.mIMesh);
// Special case for 1-triangle meshes [Opcode 1.3]
udword NbTris = create.mIMesh->GetNbTriangles();
if(NbTris==1)
{
// We don't need to actually create a tree here, since we'll only have a single triangle to deal with anyway.
// It's a waste to use a "model" for this but at least it will work.
mModelCode |= OPC_SINGLE_NODE;
return true;
}
// 2) Build a generic AABB Tree.
mSource = new AABBTree;
CHECKALLOC(mSource);
// 2-1) Setup a builder. Our primitives here are triangles from input mesh,
// so we use an AABBTreeOfTrianglesBuilder.....
{
AABBTreeOfTrianglesBuilder TB;
TB.mIMesh = create.mIMesh;
TB.mSettings = create.mSettings;
TB.mNbPrimitives = NbTris;
if(!mSource->Build(&TB)) return false;
}
// 3) Create an optimized tree according to user-settings
if(!CreateTree(create.mNoLeaf, create.mQuantized)) return false;
// 3-2) Create optimized tree
if(!mTree->Build(mSource)) return false;
// 3-3) Delete generic tree if needed
if(!create.mKeepOriginal) DELETESINGLE(mSource);
#ifdef __MESHMERIZER_H__
// 4) Convex hull
if(create.mCollisionHull)
{
// Create hull
mHull = new CollisionHull;
CHECKALLOC(mHull);
CONVEXHULLCREATE CHC;
// ### doesn't work with strides
CHC.NbVerts = create.mIMesh->GetNbVertices();
CHC.Vertices = create.mIMesh->GetVerts();
CHC.UnifyNormals = true;
CHC.ReduceVertices = true;
CHC.WordFaces = false;
mHull->Compute(CHC);
}
#endif // __MESHMERIZER_H__
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Model::GetUsedBytes() const
{
if(!mTree) return 0;
return mTree->GetUsedBytes();
}

View File

@@ -1,74 +1,74 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for OPCODE models.
* \file OPC_Model.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_MODEL_H__
#define __OPC_MODEL_H__
class OPCODE_API Model : public BaseModel
{
public:
// Constructor/Destructor
Model();
virtual ~Model();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Build(const OPCODECREATE& create);
#ifdef __MESHMERIZER_H__
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the collision hull.
* \return the collision hull if it exists
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const CollisionHull* GetHull() const { return mHull; }
#endif // __MESHMERIZER_H__
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) udword GetUsedBytes() const;
private:
#ifdef __MESHMERIZER_H__
CollisionHull* mHull; //!< Possible convex hull
#endif // __MESHMERIZER_H__
// Internal methods
void Release();
};
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for OPCODE models.
* \file OPC_Model.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_MODEL_H__
#define __OPC_MODEL_H__
class OPCODE_API Model : public BaseModel
{
public:
// Constructor/Destructor
Model();
virtual ~Model();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) bool Build(const OPCODECREATE& create);
#ifdef __MESHMERIZER_H__
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the collision hull.
* \return the collision hull if it exists
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ const CollisionHull* GetHull() const { return mHull; }
#endif // __MESHMERIZER_H__
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(BaseModel) udword GetUsedBytes() const;
private:
#ifdef __MESHMERIZER_H__
CollisionHull* mHull; //!< Possible convex hull
#endif // __MESHMERIZER_H__
// Internal methods
void Release();
};
#endif //__OPC_MODEL_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,151 +1,151 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an OBB collider.
* \file OPC_OBBCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_OBBCOLLIDER_H__
#define __OPC_OBBCOLLIDER_H__
struct OPCODE_API OBBCache : VolumeCache
{
OBBCache() : FatCoeff(1.1f)
{
FatBox.mCenter.Zero();
FatBox.mExtents.Zero();
FatBox.mRot.Identity();
}
// Cached faces signature
OBB FatBox; //!< Box used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< extents multiplier used to create a fat box
};
class OPCODE_API OBBCollider : public VolumeCollider
{
public:
// Constructor / Destructor
OBBCollider();
virtual ~OBBCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a box cache
* \param box [in] collision OBB in local space
* \param model [in] Opcode model to collide with
* \param worldb [in] OBB's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: select between full box-box tests or "SAT-lite" tests (where Class III axes are discarded)
* \param flag [in] true for full tests, false for coarse tests
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; }
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Precomputed data
Matrix3x3 mAR; //!< Absolute rotation matrix
Matrix3x3 mRModelToBox; //!< Rotation from model space to obb space
Matrix3x3 mRBoxToModel; //!< Rotation from obb space to model space
Point mTModelToBox; //!< Translation from model space to obb space
Point mTBoxToModel; //!< Translation from obb space to model space
Point mBoxExtents;
Point mB0; //!< - mTModelToBox + mBoxExtents
Point mB1; //!< - mTModelToBox - mBoxExtents
float mBBx1;
float mBBy1;
float mBBz1;
float mBB_1;
float mBB_2;
float mBB_3;
float mBB_4;
float mBB_5;
float mBB_6;
float mBB_7;
float mBB_8;
float mBB_9;
// Leaf description
Point mLeafVerts[3]; //!< Triangle vertices
// Settings
bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false)
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL OBBContainsBox(const Point& bc, const Point& be);
inline_ BOOL BoxBoxOverlap(const Point& extents, const Point& center);
inline_ BOOL TriBoxOverlap();
// Init methods
BOOL InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridOBBCollider : public OBBCollider
{
public:
// Constructor / Destructor
HybridOBBCollider();
virtual ~HybridOBBCollider();
bool Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_OBBCOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for an OBB collider.
* \file OPC_OBBCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_OBBCOLLIDER_H__
#define __OPC_OBBCOLLIDER_H__
struct OPCODE_API OBBCache : VolumeCache
{
OBBCache() : FatCoeff(1.1f)
{
FatBox.mCenter.Zero();
FatBox.mExtents.Zero();
FatBox.mRot.Identity();
}
// Cached faces signature
OBB FatBox; //!< Box used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< extents multiplier used to create a fat box
};
class OPCODE_API OBBCollider : public VolumeCollider
{
public:
// Constructor / Destructor
OBBCollider();
virtual ~OBBCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a box cache
* \param box [in] collision OBB in local space
* \param model [in] Opcode model to collide with
* \param worldb [in] OBB's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: select between full box-box tests or "SAT-lite" tests (where Class III axes are discarded)
* \param flag [in] true for full tests, false for coarse tests
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; }
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Precomputed data
Matrix3x3 mAR; //!< Absolute rotation matrix
Matrix3x3 mRModelToBox; //!< Rotation from model space to obb space
Matrix3x3 mRBoxToModel; //!< Rotation from obb space to model space
Point mTModelToBox; //!< Translation from model space to obb space
Point mTBoxToModel; //!< Translation from obb space to model space
Point mBoxExtents;
Point mB0; //!< - mTModelToBox + mBoxExtents
Point mB1; //!< - mTModelToBox - mBoxExtents
float mBBx1;
float mBBy1;
float mBBz1;
float mBB_1;
float mBB_2;
float mBB_3;
float mBB_4;
float mBB_5;
float mBB_6;
float mBB_7;
float mBB_8;
float mBB_9;
// Leaf description
Point mLeafVerts[3]; //!< Triangle vertices
// Settings
bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false)
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL OBBContainsBox(const Point& bc, const Point& be);
inline_ BOOL BoxBoxOverlap(const Point& extents, const Point& center);
inline_ BOOL TriBoxOverlap();
// Init methods
BOOL InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridOBBCollider : public OBBCollider
{
public:
// Constructor / Destructor
HybridOBBCollider();
virtual ~HybridOBBCollider();
bool Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_OBBCOLLIDER_H__

File diff suppressed because it is too large Load Diff

View File

@@ -1,215 +1,215 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for optimized trees.
* \file OPC_OptimizedTree.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_OPTIMIZEDTREE_H__
#define __OPC_OPTIMIZEDTREE_H__
//! Common interface for a node of an implicit tree
#define IMPLEMENT_IMPLICIT_NODE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
inline_ base_class() : mData(0) {} \
inline_ ~base_class() {} \
/* Leaf test */ \
inline_ BOOL IsLeaf() const { return mData&1; } \
/* Data access */ \
inline_ const base_class* GetPos() const { return (base_class*)mData; } \
inline_ const base_class* GetNeg() const { return ((base_class*)mData)+1; } \
inline_ udword GetPrimitive() const { return (mData>>1); } \
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
\
volume mAABB; \
udword mData;
//! Common interface for a node of a no-leaf tree
#define IMPLEMENT_NOLEAF_NODE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
inline_ base_class() : mPosData(0), mNegData(0) {} \
inline_ ~base_class() {} \
/* Leaf tests */ \
inline_ BOOL HasPosLeaf() const { return mPosData&1; } \
inline_ BOOL HasNegLeaf() const { return mNegData&1; } \
/* Data access */ \
inline_ const base_class* GetPos() const { return (base_class*)mPosData; } \
inline_ const base_class* GetNeg() const { return (base_class*)mNegData; } \
inline_ udword GetPosPrimitive() const { return (mPosData>>1); } \
inline_ udword GetNegPrimitive() const { return (mNegData>>1); } \
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
\
volume mAABB; \
udword mPosData; \
udword mNegData;
class OPCODE_API AABBCollisionNode
{
IMPLEMENT_IMPLICIT_NODE(AABBCollisionNode, CollisionAABB)
inline_ float GetVolume() const { return mAABB.mExtents.x * mAABB.mExtents.y * mAABB.mExtents.z; }
inline_ float GetSize() const { return mAABB.mExtents.SquareMagnitude(); }
inline_ udword GetRadius() const
{
udword* Bits = (udword*)&mAABB.mExtents.x;
udword Max = Bits[0];
if(Bits[1]>Max) Max = Bits[1];
if(Bits[2]>Max) Max = Bits[2];
return Max;
}
// NB: using the square-magnitude or the true volume of the box, seems to yield better results
// (assuming UNC-like informed traversal methods). I borrowed this idea from PQP. The usual "size"
// otherwise, is the largest box extent. In SOLID that extent is computed on-the-fly each time it's
// needed (the best approach IMHO). In RAPID the rotation matrix is permuted so that Extent[0] is
// always the greatest, which saves looking for it at runtime. On the other hand, it yields matrices
// whose determinant is not 1, i.e. you can't encode them anymore as unit quaternions. Not a very
// good strategy.
};
class OPCODE_API AABBQuantizedNode
{
IMPLEMENT_IMPLICIT_NODE(AABBQuantizedNode, QuantizedAABB)
inline_ uword GetSize() const
{
const uword* Bits = mAABB.mExtents;
uword Max = Bits[0];
if(Bits[1]>Max) Max = Bits[1];
if(Bits[2]>Max) Max = Bits[2];
return Max;
}
// NB: for quantized nodes I don't feel like computing a square-magnitude with integers all
// over the place.......!
};
class OPCODE_API AABBNoLeafNode
{
IMPLEMENT_NOLEAF_NODE(AABBNoLeafNode, CollisionAABB)
};
class OPCODE_API AABBQuantizedNoLeafNode
{
IMPLEMENT_NOLEAF_NODE(AABBQuantizedNoLeafNode, QuantizedAABB)
};
//! Common interface for a collision tree
#define IMPLEMENT_COLLISION_TREE(base_class, node) \
public: \
/* Constructor / Destructor */ \
base_class(); \
virtual ~base_class(); \
/* Builds from a standard tree */ \
override(AABBOptimizedTree) bool Build(AABBTree* tree); \
/* Refits the tree */ \
override(AABBOptimizedTree) bool Refit(const MeshInterface* mesh_interface); \
/* Walks the tree */ \
override(AABBOptimizedTree) bool Walk(GenericWalkingCallback callback, void* user_data) const; \
/* Data access */ \
inline_ const node* GetNodes() const { return mNodes; } \
/* Stats */ \
override(AABBOptimizedTree) udword GetUsedBytes() const { return mNbNodes*sizeof(node); } \
private: \
node* mNodes;
typedef bool (*GenericWalkingCallback) (const void* current, void* user_data);
class OPCODE_API AABBOptimizedTree
{
public:
// Constructor / Destructor
AABBOptimizedTree() :
mNbNodes (0)
{}
virtual ~AABBOptimizedTree() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds the collision tree from a generic AABB tree.
* \param tree [in] generic AABB tree
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(AABBTree* tree) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision tree after vertices have been modified.
* \param mesh_interface [in] mesh interface for current model
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit(const MeshInterface* mesh_interface) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Walks the tree and call the user back for each node.
* \param callback [in] walking callback
* \param user_data [in] callback's user data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Walk(GenericWalkingCallback callback, void* user_data) const = 0;
// Data access
virtual udword GetUsedBytes() const = 0;
inline_ udword GetNbNodes() const { return mNbNodes; }
protected:
udword mNbNodes;
};
class OPCODE_API AABBCollisionTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBCollisionTree, AABBCollisionNode)
};
class OPCODE_API AABBNoLeafTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBNoLeafTree, AABBNoLeafNode)
};
class OPCODE_API AABBQuantizedTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBQuantizedTree, AABBQuantizedNode)
public:
Point mCenterCoeff;
Point mExtentsCoeff;
};
class OPCODE_API AABBQuantizedNoLeafTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBQuantizedNoLeafTree, AABBQuantizedNoLeafNode)
public:
Point mCenterCoeff;
Point mExtentsCoeff;
};
#endif // __OPC_OPTIMIZEDTREE_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for optimized trees.
* \file OPC_OptimizedTree.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_OPTIMIZEDTREE_H__
#define __OPC_OPTIMIZEDTREE_H__
//! Common interface for a node of an implicit tree
#define IMPLEMENT_IMPLICIT_NODE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
inline_ base_class() : mData(0) {} \
inline_ ~base_class() {} \
/* Leaf test */ \
inline_ BOOL IsLeaf() const { return mData&1; } \
/* Data access */ \
inline_ const base_class* GetPos() const { return (base_class*)mData; } \
inline_ const base_class* GetNeg() const { return ((base_class*)mData)+1; } \
inline_ udword GetPrimitive() const { return (mData>>1); } \
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
\
volume mAABB; \
udword mData;
//! Common interface for a node of a no-leaf tree
#define IMPLEMENT_NOLEAF_NODE(base_class, volume) \
public: \
/* Constructor / Destructor */ \
inline_ base_class() : mPosData(0), mNegData(0) {} \
inline_ ~base_class() {} \
/* Leaf tests */ \
inline_ BOOL HasPosLeaf() const { return mPosData&1; } \
inline_ BOOL HasNegLeaf() const { return mNegData&1; } \
/* Data access */ \
inline_ const base_class* GetPos() const { return (base_class*)mPosData; } \
inline_ const base_class* GetNeg() const { return (base_class*)mNegData; } \
inline_ udword GetPosPrimitive() const { return (mPosData>>1); } \
inline_ udword GetNegPrimitive() const { return (mNegData>>1); } \
/* Stats */ \
inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \
\
volume mAABB; \
udword mPosData; \
udword mNegData;
class OPCODE_API AABBCollisionNode
{
IMPLEMENT_IMPLICIT_NODE(AABBCollisionNode, CollisionAABB)
inline_ float GetVolume() const { return mAABB.mExtents.x * mAABB.mExtents.y * mAABB.mExtents.z; }
inline_ float GetSize() const { return mAABB.mExtents.SquareMagnitude(); }
inline_ udword GetRadius() const
{
udword* Bits = (udword*)&mAABB.mExtents.x;
udword Max = Bits[0];
if(Bits[1]>Max) Max = Bits[1];
if(Bits[2]>Max) Max = Bits[2];
return Max;
}
// NB: using the square-magnitude or the true volume of the box, seems to yield better results
// (assuming UNC-like informed traversal methods). I borrowed this idea from PQP. The usual "size"
// otherwise, is the largest box extent. In SOLID that extent is computed on-the-fly each time it's
// needed (the best approach IMHO). In RAPID the rotation matrix is permuted so that Extent[0] is
// always the greatest, which saves looking for it at runtime. On the other hand, it yields matrices
// whose determinant is not 1, i.e. you can't encode them anymore as unit quaternions. Not a very
// good strategy.
};
class OPCODE_API AABBQuantizedNode
{
IMPLEMENT_IMPLICIT_NODE(AABBQuantizedNode, QuantizedAABB)
inline_ uword GetSize() const
{
const uword* Bits = mAABB.mExtents;
uword Max = Bits[0];
if(Bits[1]>Max) Max = Bits[1];
if(Bits[2]>Max) Max = Bits[2];
return Max;
}
// NB: for quantized nodes I don't feel like computing a square-magnitude with integers all
// over the place.......!
};
class OPCODE_API AABBNoLeafNode
{
IMPLEMENT_NOLEAF_NODE(AABBNoLeafNode, CollisionAABB)
};
class OPCODE_API AABBQuantizedNoLeafNode
{
IMPLEMENT_NOLEAF_NODE(AABBQuantizedNoLeafNode, QuantizedAABB)
};
//! Common interface for a collision tree
#define IMPLEMENT_COLLISION_TREE(base_class, node) \
public: \
/* Constructor / Destructor */ \
base_class(); \
virtual ~base_class(); \
/* Builds from a standard tree */ \
override(AABBOptimizedTree) bool Build(AABBTree* tree); \
/* Refits the tree */ \
override(AABBOptimizedTree) bool Refit(const MeshInterface* mesh_interface); \
/* Walks the tree */ \
override(AABBOptimizedTree) bool Walk(GenericWalkingCallback callback, void* user_data) const; \
/* Data access */ \
inline_ const node* GetNodes() const { return mNodes; } \
/* Stats */ \
override(AABBOptimizedTree) udword GetUsedBytes() const { return mNbNodes*sizeof(node); } \
private: \
node* mNodes;
typedef bool (*GenericWalkingCallback) (const void* current, void* user_data);
class OPCODE_API AABBOptimizedTree
{
public:
// Constructor / Destructor
AABBOptimizedTree() :
mNbNodes (0)
{}
virtual ~AABBOptimizedTree() {}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds the collision tree from a generic AABB tree.
* \param tree [in] generic AABB tree
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Build(AABBTree* tree) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Refits the collision tree after vertices have been modified.
* \param mesh_interface [in] mesh interface for current model
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Refit(const MeshInterface* mesh_interface) = 0;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Walks the tree and call the user back for each node.
* \param callback [in] walking callback
* \param user_data [in] callback's user data
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual bool Walk(GenericWalkingCallback callback, void* user_data) const = 0;
// Data access
virtual udword GetUsedBytes() const = 0;
inline_ udword GetNbNodes() const { return mNbNodes; }
protected:
udword mNbNodes;
};
class OPCODE_API AABBCollisionTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBCollisionTree, AABBCollisionNode)
};
class OPCODE_API AABBNoLeafTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBNoLeafTree, AABBNoLeafNode)
};
class OPCODE_API AABBQuantizedTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBQuantizedTree, AABBQuantizedNode)
public:
Point mCenterCoeff;
Point mExtentsCoeff;
};
class OPCODE_API AABBQuantizedNoLeafTree : public AABBOptimizedTree
{
IMPLEMENT_COLLISION_TREE(AABBQuantizedNoLeafTree, AABBQuantizedNoLeafNode)
public:
Point mCenterCoeff;
Point mExtentsCoeff;
};
#endif // __OPC_OPTIMIZEDTREE_H__

View File

@@ -1,191 +1,191 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
#ifdef OPC_RAYHIT_CALLBACK
/*
Possible RayCollider usages:
- boolean query (shadow feeler)
- closest hit
- all hits
- number of intersection (boolean)
*/
bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts)
{
struct Local
{
static void AllContacts(const CollisionFace& hit, void* user_data)
{
CollisionFaces* CF = (CollisionFaces*)user_data;
CF->AddFace(hit);
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::AllContacts);
collider.SetUserData(&contacts);
return true;
}
bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact)
{
struct Local
{
static void ClosestContact(const CollisionFace& hit, void* user_data)
{
CollisionFace* CF = (CollisionFace*)user_data;
if(hit.mDistance<CF->mDistance) *CF = hit;
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::ClosestContact);
collider.SetUserData(&closest_contact);
closest_contact.mDistance = MAX_FLOAT;
return true;
}
bool Opcode::SetupShadowFeeler(RayCollider& collider)
{
collider.SetFirstContact(true);
collider.SetHitCallback(null);
return true;
}
bool Opcode::SetupInOutTest(RayCollider& collider)
{
collider.SetFirstContact(false);
collider.SetHitCallback(null);
// Results with collider.GetNbIntersections()
return true;
}
bool Opcode::Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data)
{
struct Local
{
struct CullData
{
CollisionFace* Closest;
float MinLimit;
CullModeCallback Callback;
void* UserData;
Point ViewPoint;
const MeshInterface* IMesh;
};
// Called for each stabbed face
static void RenderCullingCallback(const CollisionFace& hit, void* user_data)
{
CullData* Data = (CullData*)user_data;
// Discard face if we already have a closer hit
if(hit.mDistance>=Data->Closest->mDistance) return;
// Discard face if hit point is smaller than min limit. This mainly happens when the face is in front
// of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an
// object that he may not even be able to see, which is very annoying.
if(hit.mDistance<=Data->MinLimit) return;
// This is the index of currently stabbed triangle.
udword StabbedFaceIndex = hit.mFaceID;
// We may keep it or not, depending on backface culling
bool KeepIt = true;
// Catch *render* cull mode for this face
CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData);
if(CM!=CULLMODE_NONE) // Don't even compute culling for double-sided triangles
{
// Compute backface culling for current face
VertexPointers VP;
Data->IMesh->GetTriangle(VP, StabbedFaceIndex);
if(VP.BackfaceCulling(Data->ViewPoint))
{
if(CM==CULLMODE_CW) KeepIt = false;
}
else
{
if(CM==CULLMODE_CCW) KeepIt = false;
}
}
if(KeepIt) *Data->Closest = hit;
}
};
RayCollider RC;
RC.SetMaxDist(max_dist);
RC.SetTemporalCoherence(false);
RC.SetCulling(false); // We need all faces since some of them can be double-sided
RC.SetFirstContact(false);
RC.SetHitCallback(Local::RenderCullingCallback);
picked_face.mFaceID = INVALID_ID;
picked_face.mDistance = MAX_FLOAT;
picked_face.mU = 0.0f;
picked_face.mV = 0.0f;
Local::CullData Data;
Data.Closest = &picked_face;
Data.MinLimit = min_dist;
Data.Callback = callback;
Data.UserData = user_data;
Data.ViewPoint = view_point;
Data.IMesh = model.GetMeshInterface();
if(world)
{
// Get matrices
Matrix4x4 InvWorld;
InvertPRMatrix(InvWorld, *world);
// Compute camera position in mesh space
Data.ViewPoint *= InvWorld;
}
RC.SetUserData(&Data);
if(RC.Collide(world_ray, model, world))
{
return picked_face.mFaceID!=INVALID_ID;
}
return false;
}
#endif
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
#ifdef OPC_RAYHIT_CALLBACK
/*
Possible RayCollider usages:
- boolean query (shadow feeler)
- closest hit
- all hits
- number of intersection (boolean)
*/
bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts)
{
struct Local
{
static void AllContacts(const CollisionFace& hit, void* user_data)
{
CollisionFaces* CF = (CollisionFaces*)user_data;
CF->AddFace(hit);
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::AllContacts);
collider.SetUserData(&contacts);
return true;
}
bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact)
{
struct Local
{
static void ClosestContact(const CollisionFace& hit, void* user_data)
{
CollisionFace* CF = (CollisionFace*)user_data;
if(hit.mDistance<CF->mDistance) *CF = hit;
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::ClosestContact);
collider.SetUserData(&closest_contact);
closest_contact.mDistance = MAX_FLOAT;
return true;
}
bool Opcode::SetupShadowFeeler(RayCollider& collider)
{
collider.SetFirstContact(true);
collider.SetHitCallback(null);
return true;
}
bool Opcode::SetupInOutTest(RayCollider& collider)
{
collider.SetFirstContact(false);
collider.SetHitCallback(null);
// Results with collider.GetNbIntersections()
return true;
}
bool Opcode::Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data)
{
struct Local
{
struct CullData
{
CollisionFace* Closest;
float MinLimit;
CullModeCallback Callback;
void* UserData;
Point ViewPoint;
const MeshInterface* IMesh;
};
// Called for each stabbed face
static void RenderCullingCallback(const CollisionFace& hit, void* user_data)
{
CullData* Data = (CullData*)user_data;
// Discard face if we already have a closer hit
if(hit.mDistance>=Data->Closest->mDistance) return;
// Discard face if hit point is smaller than min limit. This mainly happens when the face is in front
// of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an
// object that he may not even be able to see, which is very annoying.
if(hit.mDistance<=Data->MinLimit) return;
// This is the index of currently stabbed triangle.
udword StabbedFaceIndex = hit.mFaceID;
// We may keep it or not, depending on backface culling
bool KeepIt = true;
// Catch *render* cull mode for this face
CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData);
if(CM!=CULLMODE_NONE) // Don't even compute culling for double-sided triangles
{
// Compute backface culling for current face
VertexPointers VP;
Data->IMesh->GetTriangle(VP, StabbedFaceIndex);
if(VP.BackfaceCulling(Data->ViewPoint))
{
if(CM==CULLMODE_CW) KeepIt = false;
}
else
{
if(CM==CULLMODE_CCW) KeepIt = false;
}
}
if(KeepIt) *Data->Closest = hit;
}
};
RayCollider RC;
RC.SetMaxDist(max_dist);
RC.SetTemporalCoherence(false);
RC.SetCulling(false); // We need all faces since some of them can be double-sided
RC.SetFirstContact(false);
RC.SetHitCallback(Local::RenderCullingCallback);
picked_face.mFaceID = INVALID_ID;
picked_face.mDistance = MAX_FLOAT;
picked_face.mU = 0.0f;
picked_face.mV = 0.0f;
Local::CullData Data;
Data.Closest = &picked_face;
Data.MinLimit = min_dist;
Data.Callback = callback;
Data.UserData = user_data;
Data.ViewPoint = view_point;
Data.IMesh = model.GetMeshInterface();
if(world)
{
// Get matrices
Matrix4x4 InvWorld;
InvertPRMatrix(InvWorld, *world);
// Compute camera position in mesh space
Data.ViewPoint *= InvWorld;
}
RC.SetUserData(&Data);
if(RC.Collide(world_ray, model, world))
{
return picked_face.mFaceID!=INVALID_ID;
}
return false;
}
#endif

View File

@@ -1,54 +1,54 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_PICKING_H__
#define __OPC_PICKING_H__
#ifdef OPC_RAYHIT_CALLBACK
enum CullMode
{
CULLMODE_NONE = 0,
CULLMODE_CW = 1,
CULLMODE_CCW = 2
};
typedef CullMode (*CullModeCallback)(udword triangle_index, void* user_data);
OPCODE_API bool SetupAllHits (RayCollider& collider, CollisionFaces& contacts);
OPCODE_API bool SetupClosestHit (RayCollider& collider, CollisionFace& closest_contact);
OPCODE_API bool SetupShadowFeeler (RayCollider& collider);
OPCODE_API bool SetupInOutTest (RayCollider& collider);
OPCODE_API bool Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data);
#endif
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_PICKING_H__
#define __OPC_PICKING_H__
#ifdef OPC_RAYHIT_CALLBACK
enum CullMode
{
CULLMODE_NONE = 0,
CULLMODE_CW = 1,
CULLMODE_CCW = 2
};
typedef CullMode (*CullModeCallback)(udword triangle_index, void* user_data);
OPCODE_API bool SetupAllHits (RayCollider& collider, CollisionFaces& contacts);
OPCODE_API bool SetupClosestHit (RayCollider& collider, CollisionFace& closest_contact);
OPCODE_API bool SetupShadowFeeler (RayCollider& collider);
OPCODE_API bool SetupInOutTest (RayCollider& collider);
OPCODE_API bool Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data);
#endif
#endif //__OPC_PICKING_H__

View File

@@ -1,67 +1,67 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Planes-AABB overlap test.
* - original code by Ville Miettinen, from Umbra/dPVS (released on the GD-Algorithms mailing list)
* - almost used "as-is", I even left the comments (hence the frustum-related notes)
*
* \param center [in] box center
* \param extents [in] box extents
* \param out_clip_mask [out] bitmask for active planes
* \param in_clip_mask [in] bitmask for active planes
* \return TRUE if boxes overlap planes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL PlanesCollider::PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask)
{
// Stats
mNbVolumeBVTests++;
const Plane* p = mPlanes;
// Evaluate through all active frustum planes. We determine the relation
// between the AABB and a plane by using the concept of "near" and "far"
// vertices originally described by Zhang (and later by M<>ller). Our
// variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point
// comparisons per plane. The routine early-exits if the AABB is found
// to be outside any of the planes. The loop also constructs a new output
// clip mask. Most FPUs have a native single-cycle fabsf() operation.
udword Mask = 1; // current mask index (1,2,4,8,..)
udword TmpOutClipMask = 0; // initialize output clip mask into empty.
while(Mask<=in_clip_mask) // keep looping while we have active planes left...
{
if(in_clip_mask & Mask) // if clip plane is active, process it..
{
float NP = extents.x*fabsf(p->n.x) + extents.y*fabsf(p->n.y) + extents.z*fabsf(p->n.z); // ### fabsf could be precomputed
float MP = center.x*p->n.x + center.y*p->n.y + center.z*p->n.z + p->d;
if(NP < MP) // near vertex behind the clip plane...
return FALSE; // .. so there is no intersection..
if((-NP) < MP) // near and far vertices on different sides of plane..
TmpOutClipMask |= Mask; // .. so update the clip mask...
}
Mask+=Mask; // mk = (1<<plane)
p++; // advance to next plane
}
out_clip_mask = TmpOutClipMask; // copy output value (temp used to resolve aliasing!)
return TRUE; // indicate that AABB intersects frustum
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Planes-AABB overlap test.
* - original code by Ville Miettinen, from Umbra/dPVS (released on the GD-Algorithms mailing list)
* - almost used "as-is", I even left the comments (hence the frustum-related notes)
*
* \param center [in] box center
* \param extents [in] box extents
* \param out_clip_mask [out] bitmask for active planes
* \param in_clip_mask [in] bitmask for active planes
* \return TRUE if boxes overlap planes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL PlanesCollider::PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask)
{
// Stats
mNbVolumeBVTests++;
const Plane* p = mPlanes;
// Evaluate through all active frustum planes. We determine the relation
// between the AABB and a plane by using the concept of "near" and "far"
// vertices originally described by Zhang (and later by M<>ller). Our
// variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point
// comparisons per plane. The routine early-exits if the AABB is found
// to be outside any of the planes. The loop also constructs a new output
// clip mask. Most FPUs have a native single-cycle fabsf() operation.
udword Mask = 1; // current mask index (1,2,4,8,..)
udword TmpOutClipMask = 0; // initialize output clip mask into empty.
while(Mask<=in_clip_mask) // keep looping while we have active planes left...
{
if(in_clip_mask & Mask) // if clip plane is active, process it..
{
float NP = extents.x*fabsf(p->n.x) + extents.y*fabsf(p->n.y) + extents.z*fabsf(p->n.z); // ### fabsf could be precomputed
float MP = center.x*p->n.x + center.y*p->n.y + center.z*p->n.z + p->d;
if(NP < MP) // near vertex behind the clip plane...
return FALSE; // .. so there is no intersection..
if((-NP) < MP) // near and far vertices on different sides of plane..
TmpOutClipMask |= Mask; // .. so update the clip mask...
}
Mask+=Mask; // mk = (1<<plane)
p++; // advance to next plane
}
out_clip_mask = TmpOutClipMask; // copy output value (temp used to resolve aliasing!)
return TRUE; // indicate that AABB intersects frustum
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +1,130 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a planes collider.
* \file OPC_PlanesCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_PLANESCOLLIDER_H__
#define __OPC_PLANESCOLLIDER_H__
struct OPCODE_API PlanesCache : VolumeCache
{
PlanesCache()
{
}
};
class OPCODE_API PlanesCollider : public VolumeCollider
{
public:
// Constructor / Destructor
PlanesCollider();
virtual ~PlanesCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a planes cache
* \param planes [in] list of planes in world space
* \param nb_planes [in] number of planes
* \param model [in] Opcode model to collide with
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm=null);
// Mutant box-with-planes collision queries
inline_ bool Collide(PlanesCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null)
{
Plane PL[6];
if(worldb)
{
// Create a new OBB in world space
OBB WorldBox;
box.Rotate(*worldb, WorldBox);
// Compute planes from the sides of the box
WorldBox.ComputePlanes(PL);
}
else
{
// Compute planes from the sides of the box
box.ComputePlanes(PL);
}
// Collide with box planes
return Collide(cache, PL, 6, model, worldm);
}
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Planes in model space
udword mNbPlanes;
Plane* mPlanes;
// Leaf description
VertexPointers mVP;
// Internal methods
void _Collide(const AABBCollisionNode* node, udword clip_mask);
void _Collide(const AABBNoLeafNode* node, udword clip_mask);
void _Collide(const AABBQuantizedNode* node, udword clip_mask);
void _Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask);
// Overlap tests
inline_ BOOL PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask);
inline_ BOOL PlanesTriOverlap(udword in_clip_mask);
// Init methods
BOOL InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridPlanesCollider : public PlanesCollider
{
public:
// Constructor / Destructor
HybridPlanesCollider();
virtual ~HybridPlanesCollider();
bool Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_PLANESCOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a planes collider.
* \file OPC_PlanesCollider.h
* \author Pierre Terdiman
* \date January, 1st, 2002
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_PLANESCOLLIDER_H__
#define __OPC_PLANESCOLLIDER_H__
struct OPCODE_API PlanesCache : VolumeCache
{
PlanesCache()
{
}
};
class OPCODE_API PlanesCollider : public VolumeCollider
{
public:
// Constructor / Destructor
PlanesCollider();
virtual ~PlanesCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a planes cache
* \param planes [in] list of planes in world space
* \param nb_planes [in] number of planes
* \param model [in] Opcode model to collide with
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm=null);
// Mutant box-with-planes collision queries
inline_ bool Collide(PlanesCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null)
{
Plane PL[6];
if(worldb)
{
// Create a new OBB in world space
OBB WorldBox;
box.Rotate(*worldb, WorldBox);
// Compute planes from the sides of the box
WorldBox.ComputePlanes(PL);
}
else
{
// Compute planes from the sides of the box
box.ComputePlanes(PL);
}
// Collide with box planes
return Collide(cache, PL, 6, model, worldm);
}
// Settings
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Planes in model space
udword mNbPlanes;
Plane* mPlanes;
// Leaf description
VertexPointers mVP;
// Internal methods
void _Collide(const AABBCollisionNode* node, udword clip_mask);
void _Collide(const AABBNoLeafNode* node, udword clip_mask);
void _Collide(const AABBQuantizedNode* node, udword clip_mask);
void _Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask);
// Overlap tests
inline_ BOOL PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask);
inline_ BOOL PlanesTriOverlap(udword in_clip_mask);
// Init methods
BOOL InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridPlanesCollider : public PlanesCollider
{
public:
// Constructor / Destructor
HybridPlanesCollider();
virtual ~HybridPlanesCollider();
bool Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_PLANESCOLLIDER_H__

View File

@@ -1,57 +1,57 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Planes-triangle overlap test.
* \param in_clip_mask [in] bitmask for active planes
* \return TRUE if triangle overlap planes
* \warning THIS IS A CONSERVATIVE TEST !! Some triangles will be returned as intersecting, while they're not!
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL PlanesCollider::PlanesTriOverlap(udword in_clip_mask)
{
// Stats
mNbVolumePrimTests++;
const Plane* p = mPlanes;
udword Mask = 1;
while(Mask<=in_clip_mask)
{
if(in_clip_mask & Mask)
{
float d0 = p->Distance(*mVP.Vertex[0]);
float d1 = p->Distance(*mVP.Vertex[1]);
float d2 = p->Distance(*mVP.Vertex[2]);
if(d0>0.0f && d1>0.0f && d2>0.0f) return FALSE;
// if(!(IR(d0)&SIGN_BITMASK) && !(IR(d1)&SIGN_BITMASK) && !(IR(d2)&SIGN_BITMASK)) return FALSE;
}
Mask+=Mask;
p++;
}
/*
for(udword i=0;i<6;i++)
{
float d0 = p[i].Distance(mLeafVerts[0]);
float d1 = p[i].Distance(mLeafVerts[1]);
float d2 = p[i].Distance(mLeafVerts[2]);
if(d0>0.0f && d1>0.0f && d2>0.0f) return false;
}
*/
return TRUE;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Planes-triangle overlap test.
* \param in_clip_mask [in] bitmask for active planes
* \return TRUE if triangle overlap planes
* \warning THIS IS A CONSERVATIVE TEST !! Some triangles will be returned as intersecting, while they're not!
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL PlanesCollider::PlanesTriOverlap(udword in_clip_mask)
{
// Stats
mNbVolumePrimTests++;
const Plane* p = mPlanes;
udword Mask = 1;
while(Mask<=in_clip_mask)
{
if(in_clip_mask & Mask)
{
float d0 = p->Distance(*mVP.Vertex[0]);
float d1 = p->Distance(*mVP.Vertex[1]);
float d2 = p->Distance(*mVP.Vertex[2]);
if(d0>0.0f && d1>0.0f && d2>0.0f) return FALSE;
// if(!(IR(d0)&SIGN_BITMASK) && !(IR(d1)&SIGN_BITMASK) && !(IR(d2)&SIGN_BITMASK)) return FALSE;
}
Mask+=Mask;
p++;
}
/*
for(udword i=0;i<6;i++)
{
float d0 = p[i].Distance(mLeafVerts[0]);
float d1 = p[i].Distance(mLeafVerts[1]);
float d2 = p[i].Distance(mLeafVerts[2]);
if(d0>0.0f && d1>0.0f && d2>0.0f) return false;
}
*/
return TRUE;
}

View File

@@ -1,81 +1,81 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Opcode 1.1: ray-AABB overlap tests based on Woo's code
// Opcode 1.2: ray-AABB overlap tests based on the separating axis theorem
//
// The point of intersection is not computed anymore. The distance to impact is not needed anymore
// since we now have two different queries for segments or rays.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a segment-AABB overlap test using the separating axis theorem. Segment is cached within the class.
* \param center [in] AABB center
* \param extents [in] AABB extents
* \return true on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::SegmentAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbRayBVTests++;
float Dx = mData2.x - center.x; if(fabsf(Dx) > extents.x + mFDir.x) return FALSE;
float Dy = mData2.y - center.y; if(fabsf(Dy) > extents.y + mFDir.y) return FALSE;
float Dz = mData2.z - center.z; if(fabsf(Dz) > extents.z + mFDir.z) return FALSE;
float f;
f = mData.y * Dz - mData.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE;
f = mData.z * Dx - mData.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE;
f = mData.x * Dy - mData.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a ray-AABB overlap test using the separating axis theorem. Ray is cached within the class.
* \param center [in] AABB center
* \param extents [in] AABB extents
* \return true on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::RayAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbRayBVTests++;
// float Dx = mOrigin.x - center.x; if(fabsf(Dx) > extents.x && Dx*mDir.x>=0.0f) return FALSE;
// float Dy = mOrigin.y - center.y; if(fabsf(Dy) > extents.y && Dy*mDir.y>=0.0f) return FALSE;
// float Dz = mOrigin.z - center.z; if(fabsf(Dz) > extents.z && Dz*mDir.z>=0.0f) return FALSE;
float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && Dx*mDir.x>=0.0f) return FALSE;
float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && Dy*mDir.y>=0.0f) return FALSE;
float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && Dz*mDir.z>=0.0f) return FALSE;
// float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && ((SIR(Dx)-1)^SIR(mDir.x))>=0.0f) return FALSE;
// float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && ((SIR(Dy)-1)^SIR(mDir.y))>=0.0f) return FALSE;
// float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && ((SIR(Dz)-1)^SIR(mDir.z))>=0.0f) return FALSE;
float f;
f = mDir.y * Dz - mDir.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE;
f = mDir.z * Dx - mDir.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE;
f = mDir.x * Dy - mDir.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE;
return TRUE;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// Opcode 1.1: ray-AABB overlap tests based on Woo's code
// Opcode 1.2: ray-AABB overlap tests based on the separating axis theorem
//
// The point of intersection is not computed anymore. The distance to impact is not needed anymore
// since we now have two different queries for segments or rays.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a segment-AABB overlap test using the separating axis theorem. Segment is cached within the class.
* \param center [in] AABB center
* \param extents [in] AABB extents
* \return true on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::SegmentAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbRayBVTests++;
float Dx = mData2.x - center.x; if(fabsf(Dx) > extents.x + mFDir.x) return FALSE;
float Dy = mData2.y - center.y; if(fabsf(Dy) > extents.y + mFDir.y) return FALSE;
float Dz = mData2.z - center.z; if(fabsf(Dz) > extents.z + mFDir.z) return FALSE;
float f;
f = mData.y * Dz - mData.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE;
f = mData.z * Dx - mData.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE;
f = mData.x * Dy - mData.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a ray-AABB overlap test using the separating axis theorem. Ray is cached within the class.
* \param center [in] AABB center
* \param extents [in] AABB extents
* \return true on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::RayAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbRayBVTests++;
// float Dx = mOrigin.x - center.x; if(fabsf(Dx) > extents.x && Dx*mDir.x>=0.0f) return FALSE;
// float Dy = mOrigin.y - center.y; if(fabsf(Dy) > extents.y && Dy*mDir.y>=0.0f) return FALSE;
// float Dz = mOrigin.z - center.z; if(fabsf(Dz) > extents.z && Dz*mDir.z>=0.0f) return FALSE;
float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && Dx*mDir.x>=0.0f) return FALSE;
float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && Dy*mDir.y>=0.0f) return FALSE;
float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && Dz*mDir.z>=0.0f) return FALSE;
// float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && ((SIR(Dx)-1)^SIR(mDir.x))>=0.0f) return FALSE;
// float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && ((SIR(Dy)-1)^SIR(mDir.y))>=0.0f) return FALSE;
// float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && ((SIR(Dz)-1)^SIR(mDir.z))>=0.0f) return FALSE;
float f;
f = mDir.y * Dz - mDir.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE;
f = mDir.z * Dx - mDir.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE;
f = mDir.x * Dy - mDir.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE;
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,234 +1,234 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a ray collider.
* \file OPC_RayCollider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_RAYCOLLIDER_H__
#define __OPC_RAYCOLLIDER_H__
class OPCODE_API CollisionFace
{
public:
//! Constructor
inline_ CollisionFace() {}
//! Destructor
inline_ ~CollisionFace() {}
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
};
class OPCODE_API CollisionFaces : private Container
{
public:
//! Constructor
CollisionFaces() {}
//! Destructor
~CollisionFaces() {}
inline_ udword GetNbFaces() const { return GetNbEntries()>>2; }
inline_ const CollisionFace* GetFaces() const { return (const CollisionFace*)GetEntries(); }
inline_ void Reset() { Container::Reset(); }
inline_ void AddFace(const CollisionFace& face) { Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV); }
};
#ifdef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called by OPCODE to record a hit.
* \param hit [in] current hit
* \param user_data [in] user-defined data from SetCallback()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef void (*HitCallback) (const CollisionFace& hit, void* user_data);
#endif
class OPCODE_API RayCollider : public Collider
{
public:
// Constructor / Destructor
RayCollider();
virtual ~RayCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic stabbing query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - in the user-provided destination array
*
* \param world_ray [in] stabbing ray in world space
* \param model [in] Opcode model to collide with
* \param world [in] model's world matrix, or null
* \param cache [in] a possibly cached face index, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null);
//
bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices);
// Settings
#ifndef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable "closest hit" mode.
* \param flag [in] true to report closest hit only
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetClosestHit(bool flag) { mClosestHit = flag; }
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable backface culling.
* \param flag [in] true to enable backface culling
* \see SetClosestHit(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetCulling(bool flag) { mCulling = flag; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the higher distance bound.
* \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment)
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMaxDist(float max_dist=MAX_FLOAT) { mMaxDist = max_dist; }
#ifdef OPC_RAYHIT_CALLBACK
inline_ void SetHitCallback(HitCallback cb) { mHitCallback = cb; }
inline_ void SetUserData(void* user_data) { mUserData = user_data; }
#else
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the destination array for stabbed faces.
* \param cf [in] destination array, filled during queries
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetDestination(CollisionFaces* cf) { mStabbedFaces = cf; }
#endif
// Stats
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-BV overlap tests after a collision query.
* \see GetNbRayPrimTests()
* \see GetNbIntersections()
* \return the number of Ray-BV tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayBVTests() const { return mNbRayBVTests; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-Triangle overlap tests after a collision query.
* \see GetNbRayBVTests()
* \see GetNbIntersections()
* \return the number of Ray-Triangle tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayPrimTests() const { return mNbRayPrimTests; }
// In-out test
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of intersection found after a collision query. Can be used for in/out tests.
* \see GetNbRayBVTests()
* \see GetNbRayPrimTests()
* \return the number of valid intersections during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbIntersections() const { return mNbIntersections; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Ray in local space
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
// Stabbed faces
CollisionFace mStabbedFace; //!< Current stabbed face
#ifdef OPC_RAYHIT_CALLBACK
HitCallback mHitCallback; //!< Callback used to record a hit
void* mUserData; //!< User-defined data
#else
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
#endif
// Stats
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
// In-out test
udword mNbIntersections; //!< Number of valid intersections
// Dequantization coeffs
Point mCenterCoeff;
Point mExtentsCoeff;
// Settings
float mMaxDist; //!< Valid segment on the ray
#ifndef OPC_RAYHIT_CALLBACK
bool mClosestHit; //!< Report closest hit only
#endif
bool mCulling; //!< Stab culled faces or not
// Internal methods
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBQuantizedNode* node);
void _SegmentStab(const AABBQuantizedNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBQuantizedNode* node);
void _RayStab(const AABBQuantizedNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null);
};
#endif // __OPC_RAYCOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a ray collider.
* \file OPC_RayCollider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_RAYCOLLIDER_H__
#define __OPC_RAYCOLLIDER_H__
class OPCODE_API CollisionFace
{
public:
//! Constructor
inline_ CollisionFace() {}
//! Destructor
inline_ ~CollisionFace() {}
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
};
class OPCODE_API CollisionFaces : private Container
{
public:
//! Constructor
CollisionFaces() {}
//! Destructor
~CollisionFaces() {}
inline_ udword GetNbFaces() const { return GetNbEntries()>>2; }
inline_ const CollisionFace* GetFaces() const { return (const CollisionFace*)GetEntries(); }
inline_ void Reset() { Container::Reset(); }
inline_ void AddFace(const CollisionFace& face) { Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV); }
};
#ifdef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called by OPCODE to record a hit.
* \param hit [in] current hit
* \param user_data [in] user-defined data from SetCallback()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef void (*HitCallback) (const CollisionFace& hit, void* user_data);
#endif
class OPCODE_API RayCollider : public Collider
{
public:
// Constructor / Destructor
RayCollider();
virtual ~RayCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic stabbing query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - in the user-provided destination array
*
* \param world_ray [in] stabbing ray in world space
* \param model [in] Opcode model to collide with
* \param world [in] model's world matrix, or null
* \param cache [in] a possibly cached face index, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null);
//
bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices);
// Settings
#ifndef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable "closest hit" mode.
* \param flag [in] true to report closest hit only
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetClosestHit(bool flag) { mClosestHit = flag; }
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable backface culling.
* \param flag [in] true to enable backface culling
* \see SetClosestHit(bool flag)
* \see SetMaxDist(float max_dist)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetCulling(bool flag) { mCulling = flag; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the higher distance bound.
* \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment)
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMaxDist(float max_dist=MAX_FLOAT) { mMaxDist = max_dist; }
#ifdef OPC_RAYHIT_CALLBACK
inline_ void SetHitCallback(HitCallback cb) { mHitCallback = cb; }
inline_ void SetUserData(void* user_data) { mUserData = user_data; }
#else
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the destination array for stabbed faces.
* \param cf [in] destination array, filled during queries
* \see SetClosestHit(bool flag)
* \see SetCulling(bool flag)
* \see SetMaxDist(float max_dist)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetDestination(CollisionFaces* cf) { mStabbedFaces = cf; }
#endif
// Stats
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-BV overlap tests after a collision query.
* \see GetNbRayPrimTests()
* \see GetNbIntersections()
* \return the number of Ray-BV tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayBVTests() const { return mNbRayBVTests; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of Ray-Triangle overlap tests after a collision query.
* \see GetNbRayBVTests()
* \see GetNbIntersections()
* \return the number of Ray-Triangle tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayPrimTests() const { return mNbRayPrimTests; }
// In-out test
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Stats: gets the number of intersection found after a collision query. Can be used for in/out tests.
* \see GetNbRayBVTests()
* \see GetNbRayPrimTests()
* \return the number of valid intersections during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbIntersections() const { return mNbIntersections; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider.
* \return null if everything is ok, else a string describing the problem
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override(Collider) const char* ValidateSettings();
protected:
// Ray in local space
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
// Stabbed faces
CollisionFace mStabbedFace; //!< Current stabbed face
#ifdef OPC_RAYHIT_CALLBACK
HitCallback mHitCallback; //!< Callback used to record a hit
void* mUserData; //!< User-defined data
#else
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
#endif
// Stats
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
// In-out test
udword mNbIntersections; //!< Number of valid intersections
// Dequantization coeffs
Point mCenterCoeff;
Point mExtentsCoeff;
// Settings
float mMaxDist; //!< Valid segment on the ray
#ifndef OPC_RAYHIT_CALLBACK
bool mClosestHit; //!< Report closest hit only
#endif
bool mCulling; //!< Stab culled faces or not
// Internal methods
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBQuantizedNode* node);
void _SegmentStab(const AABBQuantizedNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBQuantizedNode* node);
void _RayStab(const AABBQuantizedNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null);
};
#endif // __OPC_RAYCOLLIDER_H__

View File

@@ -1,106 +1,106 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#define LOCAL_EPSILON 0.000001f
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a ray-triangle intersection test.
* Original code from Tomas M<>ller's "Fast Minimum Storage Ray-Triangle Intersection".
* It's been optimized a bit with integer code, and modified to return a non-intersection if distance from
* ray origin to triangle is negative.
*
* \param vert0 [in] triangle vertex
* \param vert1 [in] triangle vertex
* \param vert2 [in] triangle vertex
* \return true on overlap. mStabbedFace is filled with relevant info.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2)
{
// Stats
mNbRayPrimTests++;
// Find vectors for two edges sharing vert0
Point edge1 = vert1 - vert0;
Point edge2 = vert2 - vert0;
// Begin calculating determinant - also used to calculate U parameter
Point pvec = mDir^edge2;
// If determinant is near zero, ray lies in plane of triangle
float det = edge1|pvec;
if(mCulling)
{
if(det<LOCAL_EPSILON) return FALSE;
// From here, det is > 0. So we can use integer cmp.
// Calculate distance from vert0 to ray origin
Point tvec = mOrigin - vert0;
// Calculate U parameter and test bounds
mStabbedFace.mU = tvec|pvec;
// if(IR(u)&0x80000000 || u>det) return FALSE;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IR(det)) return FALSE;
// Prepare to test V parameter
Point qvec = tvec^edge1;
// Calculate V parameter and test bounds
mStabbedFace.mV = mDir|qvec;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>det) return FALSE;
// Calculate t, scale parameters, ray intersects triangle
mStabbedFace.mDistance = edge2|qvec;
// Det > 0 so we can early exit here
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE;
// Else go on
float OneOverDet = 1.0f / det;
mStabbedFace.mDistance *= OneOverDet;
mStabbedFace.mU *= OneOverDet;
mStabbedFace.mV *= OneOverDet;
}
else
{
// the non-culling branch
if(det>-LOCAL_EPSILON && det<LOCAL_EPSILON) return FALSE;
float OneOverDet = 1.0f / det;
// Calculate distance from vert0 to ray origin
Point tvec = mOrigin - vert0;
// Calculate U parameter and test bounds
mStabbedFace.mU = (tvec|pvec) * OneOverDet;
// if(IR(u)&0x80000000 || u>1.0f) return FALSE;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IEEE_1_0) return FALSE;
// prepare to test V parameter
Point qvec = tvec^edge1;
// Calculate V parameter and test bounds
mStabbedFace.mV = (mDir|qvec) * OneOverDet;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>1.0f) return FALSE;
// Calculate t, ray intersects triangle
mStabbedFace.mDistance = (edge2|qvec) * OneOverDet;
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE;
}
return TRUE;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#define LOCAL_EPSILON 0.000001f
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Computes a ray-triangle intersection test.
* Original code from Tomas M<>ller's "Fast Minimum Storage Ray-Triangle Intersection".
* It's been optimized a bit with integer code, and modified to return a non-intersection if distance from
* ray origin to triangle is negative.
*
* \param vert0 [in] triangle vertex
* \param vert1 [in] triangle vertex
* \param vert2 [in] triangle vertex
* \return true on overlap. mStabbedFace is filled with relevant info.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2)
{
// Stats
mNbRayPrimTests++;
// Find vectors for two edges sharing vert0
Point edge1 = vert1 - vert0;
Point edge2 = vert2 - vert0;
// Begin calculating determinant - also used to calculate U parameter
Point pvec = mDir^edge2;
// If determinant is near zero, ray lies in plane of triangle
float det = edge1|pvec;
if(mCulling)
{
if(det<LOCAL_EPSILON) return FALSE;
// From here, det is > 0. So we can use integer cmp.
// Calculate distance from vert0 to ray origin
Point tvec = mOrigin - vert0;
// Calculate U parameter and test bounds
mStabbedFace.mU = tvec|pvec;
// if(IR(u)&0x80000000 || u>det) return FALSE;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IR(det)) return FALSE;
// Prepare to test V parameter
Point qvec = tvec^edge1;
// Calculate V parameter and test bounds
mStabbedFace.mV = mDir|qvec;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>det) return FALSE;
// Calculate t, scale parameters, ray intersects triangle
mStabbedFace.mDistance = edge2|qvec;
// Det > 0 so we can early exit here
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE;
// Else go on
float OneOverDet = 1.0f / det;
mStabbedFace.mDistance *= OneOverDet;
mStabbedFace.mU *= OneOverDet;
mStabbedFace.mV *= OneOverDet;
}
else
{
// the non-culling branch
if(det>-LOCAL_EPSILON && det<LOCAL_EPSILON) return FALSE;
float OneOverDet = 1.0f / det;
// Calculate distance from vert0 to ray origin
Point tvec = mOrigin - vert0;
// Calculate U parameter and test bounds
mStabbedFace.mU = (tvec|pvec) * OneOverDet;
// if(IR(u)&0x80000000 || u>1.0f) return FALSE;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IEEE_1_0) return FALSE;
// prepare to test V parameter
Point qvec = tvec^edge1;
// Calculate V parameter and test bounds
mStabbedFace.mV = (mDir|qvec) * OneOverDet;
if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>1.0f) return FALSE;
// Calculate t, ray intersects triangle
mStabbedFace.mDistance = (edge2|qvec) * OneOverDet;
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE;
}
return TRUE;
}

View File

@@ -1,58 +1,58 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains compilation flags.
* \file OPC_Settings.h
* \author Pierre Terdiman
* \date May, 12, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_SETTINGS_H__
#define __OPC_SETTINGS_H__
//! Use CPU comparisons (comment that line to use standard FPU compares)
#define OPC_CPU_COMPARE
//! Use FCOMI / FCMOV on Pentium-Pro based processors (comment that line to use plain C++)
#define OPC_USE_FCOMI
//! Use epsilon value in tri-tri overlap test
#define OPC_TRITRI_EPSILON_TEST
//! Use tree-coherence or not [not implemented yet]
// #define OPC_USE_TREE_COHERENCE
//! Use callbacks or direct pointers. Using callbacks might be a bit slower (but probably not much)
// #define OPC_USE_CALLBACKS
//! Support triangle and vertex strides or not. Using strides might be a bit slower (but probably not much)
// #define OPC_USE_STRIDE
//! Discard negative pointer in vanilla trees
#define OPC_NO_NEG_VANILLA_TREE
//! Use a callback in the ray collider
#define OPC_RAYHIT_CALLBACK
// NB: no compilation flag to enable/disable stats since they're actually needed in the box/box overlap test
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains compilation flags.
* \file OPC_Settings.h
* \author Pierre Terdiman
* \date May, 12, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_SETTINGS_H__
#define __OPC_SETTINGS_H__
//! Use CPU comparisons (comment that line to use standard FPU compares)
#define OPC_CPU_COMPARE
//! Use FCOMI / FCMOV on Pentium-Pro based processors (comment that line to use plain C++)
#define OPC_USE_FCOMI
//! Use epsilon value in tri-tri overlap test
#define OPC_TRITRI_EPSILON_TEST
//! Use tree-coherence or not [not implemented yet]
// #define OPC_USE_TREE_COHERENCE
//! Use callbacks or direct pointers. Using callbacks might be a bit slower (but probably not much)
// #define OPC_USE_CALLBACKS
//! Support triangle and vertex strides or not. Using strides might be a bit slower (but probably not much)
// #define OPC_USE_STRIDE
//! Discard negative pointer in vanilla trees
#define OPC_NO_NEG_VANILLA_TREE
//! Use a callback in the ray collider
#define OPC_RAYHIT_CALLBACK
// NB: no compilation flag to enable/disable stats since they're actually needed in the box/box overlap test
#endif //__OPC_SETTINGS_H__

View File

@@ -1,145 +1,145 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sphere-AABB overlap test, based on Jim Arvo's code.
* \param center [in] box center
* \param extents [in] box extents
* \return TRUE on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SphereCollider::SphereAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbVolumeBVTests++;
float d = 0.0f;
//find the square of the distance
//from the sphere to the box
#ifdef OLDIES
for(udword i=0;i<3;i++)
{
float tmp = mCenter[i] - center[i];
float s = tmp + extents[i];
if(s<0.0f) d += s*s;
else
{
s = tmp - extents[i];
if(s>0.0f) d += s*s;
}
}
#endif
//#ifdef NEW_TEST
// float tmp = mCenter.x - center.x;
// float s = tmp + extents.x;
float tmp,s;
tmp = mCenter.x - center.x;
s = tmp + extents.x;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.x;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
tmp = mCenter.y - center.y;
s = tmp + extents.y;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.y;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
tmp = mCenter.z - center.z;
s = tmp + extents.z;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.z;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
//#endif
#ifdef OLDIES
// Point Min = center - extents;
// Point Max = center + extents;
float d = 0.0f;
//find the square of the distance
//from the sphere to the box
for(udword i=0;i<3;i++)
{
float Min = center[i] - extents[i];
// if(mCenter[i]<Min[i])
if(mCenter[i]<Min)
{
// float s = mCenter[i] - Min[i];
float s = mCenter[i] - Min;
d += s*s;
}
else
{
float Max = center[i] + extents[i];
// if(mCenter[i]>Max[i])
if(mCenter[i]>Max)
{
float s = mCenter[i] - Max;
d += s*s;
}
}
}
#endif
return d <= mRadius2;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Sphere-AABB overlap test, based on Jim Arvo's code.
* \param center [in] box center
* \param extents [in] box extents
* \return TRUE on overlap
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ BOOL SphereCollider::SphereAABBOverlap(const Point& center, const Point& extents)
{
// Stats
mNbVolumeBVTests++;
float d = 0.0f;
//find the square of the distance
//from the sphere to the box
#ifdef OLDIES
for(udword i=0;i<3;i++)
{
float tmp = mCenter[i] - center[i];
float s = tmp + extents[i];
if(s<0.0f) d += s*s;
else
{
s = tmp - extents[i];
if(s>0.0f) d += s*s;
}
}
#endif
//#ifdef NEW_TEST
// float tmp = mCenter.x - center.x;
// float s = tmp + extents.x;
float tmp,s;
tmp = mCenter.x - center.x;
s = tmp + extents.x;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.x;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
tmp = mCenter.y - center.y;
s = tmp + extents.y;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.y;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
tmp = mCenter.z - center.z;
s = tmp + extents.z;
if(s<0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
else
{
s = tmp - extents.z;
if(s>0.0f)
{
d += s*s;
if(d>mRadius2) return FALSE;
}
}
//#endif
#ifdef OLDIES
// Point Min = center - extents;
// Point Max = center + extents;
float d = 0.0f;
//find the square of the distance
//from the sphere to the box
for(udword i=0;i<3;i++)
{
float Min = center[i] - extents[i];
// if(mCenter[i]<Min[i])
if(mCenter[i]<Min)
{
// float s = mCenter[i] - Min[i];
float s = mCenter[i] - Min;
d += s*s;
}
else
{
float Max = center[i] + extents[i];
// if(mCenter[i]>Max[i])
if(mCenter[i]>Max)
{
float s = mCenter[i] - Max;
d += s*s;
}
}
}
#endif
return d <= mRadius2;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,105 +1,105 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a sphere collider.
* \file OPC_SphereCollider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_SPHERECOLLIDER_H__
#define __OPC_SPHERECOLLIDER_H__
struct OPCODE_API SphereCache : VolumeCache
{
SphereCache() : Center(0.0f,0.0f,0.0f), FatRadius2(0.0f), FatCoeff(1.1f) {}
~SphereCache() {}
// Cached faces signature
Point Center; //!< Sphere used when performing the query resulting in cached faces
float FatRadius2; //!< Sphere used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere
};
class OPCODE_API SphereCollider : public VolumeCollider
{
public:
// Constructor / Destructor
SphereCollider();
virtual ~SphereCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a sphere cache
* \param sphere [in] collision sphere in local space
* \param model [in] Opcode model to collide with
* \param worlds [in] sphere's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
//
bool Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree);
protected:
// Sphere in model space
Point mCenter; //!< Sphere center
float mRadius2; //!< Sphere radius squared
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL SphereContainsBox(const Point& bc, const Point& be);
inline_ BOOL SphereAABBOverlap(const Point& center, const Point& extents);
BOOL SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridSphereCollider : public SphereCollider
{
public:
// Constructor / Destructor
HybridSphereCollider();
virtual ~HybridSphereCollider();
bool Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_SPHERECOLLIDER_H__
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for a sphere collider.
* \file OPC_SphereCollider.h
* \author Pierre Terdiman
* \date June, 2, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_SPHERECOLLIDER_H__
#define __OPC_SPHERECOLLIDER_H__
struct OPCODE_API SphereCache : VolumeCache
{
SphereCache() : Center(0.0f,0.0f,0.0f), FatRadius2(0.0f), FatCoeff(1.1f) {}
~SphereCache() {}
// Cached faces signature
Point Center; //!< Sphere used when performing the query resulting in cached faces
float FatRadius2; //!< Sphere used when performing the query resulting in cached faces
// User settings
float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere
};
class OPCODE_API SphereCollider : public VolumeCollider
{
public:
// Constructor / Destructor
SphereCollider();
virtual ~SphereCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Generic collision query for generic OPCODE models. After the call, access the results:
* - with GetContactStatus()
* - with GetNbTouchedPrimitives()
* - with GetTouchedPrimitives()
*
* \param cache [in/out] a sphere cache
* \param sphere [in] collision sphere in local space
* \param model [in] Opcode model to collide with
* \param worlds [in] sphere's world matrix, or null
* \param worldm [in] model's world matrix, or null
* \return true if success
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
//
bool Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree);
protected:
// Sphere in model space
Point mCenter; //!< Sphere center
float mRadius2; //!< Sphere radius squared
// Internal methods
void _Collide(const AABBCollisionNode* node);
void _Collide(const AABBNoLeafNode* node);
void _Collide(const AABBQuantizedNode* node);
void _Collide(const AABBQuantizedNoLeafNode* node);
void _Collide(const AABBTreeNode* node);
void _CollideNoPrimitiveTest(const AABBCollisionNode* node);
void _CollideNoPrimitiveTest(const AABBNoLeafNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNode* node);
void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node);
// Overlap tests
inline_ BOOL SphereContainsBox(const Point& bc, const Point& be);
inline_ BOOL SphereAABBOverlap(const Point& center, const Point& extents);
BOOL SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
};
class OPCODE_API HybridSphereCollider : public SphereCollider
{
public:
// Constructor / Destructor
HybridSphereCollider();
virtual ~HybridSphereCollider();
bool Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null);
protected:
Container mTouchedBoxes;
};
#endif // __OPC_SPHERECOLLIDER_H__

View File

@@ -1,203 +1,203 @@
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// This is collision detection. If you do another distance test for collision *response*,
// if might be useful to simply *skip* the test below completely, and report a collision.
// - if sphere-triangle overlap, result is ok
// - if they don't, we'll discard them during collision response with a similar test anyway
// Overall this approach should run faster.
// Original code by David Eberly in Magic.
BOOL SphereCollider::SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2)
{
// Stats
mNbVolumePrimTests++;
// Early exit if one of the vertices is inside the sphere
Point kDiff = vert2 - mCenter;
float fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
kDiff = vert1 - mCenter;
fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
kDiff = vert0 - mCenter;
fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
// Else do the full distance test
Point TriEdge0 = vert1 - vert0;
Point TriEdge1 = vert2 - vert0;
//Point kDiff = vert0 - mCenter;
float fA00 = TriEdge0.SquareMagnitude();
float fA01 = TriEdge0 | TriEdge1;
float fA11 = TriEdge1.SquareMagnitude();
float fB0 = kDiff | TriEdge0;
float fB1 = kDiff | TriEdge1;
//float fC = kDiff.SquareMagnitude();
float fDet = fabsf(fA00*fA11 - fA01*fA01);
float u = fA01*fB1-fA11*fB0;
float v = fA01*fB0-fA00*fB1;
float SqrDist;
if(u + v <= fDet)
{
if(u < 0.0f)
{
if(v < 0.0f) // region 4
{
if(fB0 < 0.0f)
{
// v = 0.0f;
if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
else
{
// u = 0.0f;
if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else // region 3
{
// u = 0.0f;
if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else if(v < 0.0f) // region 5
{
// v = 0.0f;
if(fB0>=0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
else if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
else // region 0
{
// minimum at interior point
if(fDet==0.0f)
{
// u = 0.0f;
// v = 0.0f;
SqrDist = MAX_FLOAT;
}
else
{
float fInvDet = 1.0f/fDet;
u *= fInvDet;
v *= fInvDet;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
}
else
{
float fTmp0, fTmp1, fNumer, fDenom;
if(u < 0.0f) // region 2
{
fTmp0 = fA01 + fB0;
fTmp1 = fA11 + fB1;
if(fTmp1 > fTmp0)
{
fNumer = fTmp1 - fTmp0;
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// u = 1.0f;
// v = 0.0f;
SqrDist = fA00+2.0f*fB0+fC;
}
else
{
u = fNumer/fDenom;
v = 1.0f - u;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
else
{
// u = 0.0f;
if(fTmp1 <= 0.0f) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else if(fB1 >= 0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else if(v < 0.0f) // region 6
{
fTmp0 = fA01 + fB1;
fTmp1 = fA00 + fB0;
if(fTmp1 > fTmp0)
{
fNumer = fTmp1 - fTmp0;
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// v = 1.0f;
// u = 0.0f;
SqrDist = fA11+2.0f*fB1+fC;
}
else
{
v = fNumer/fDenom;
u = 1.0f - v;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
else
{
// v = 0.0f;
if(fTmp1 <= 0.0f) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else if(fB0 >= 0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
}
else // region 1
{
fNumer = fA11 + fB1 - fA01 - fB0;
if(fNumer <= 0.0f)
{
// u = 0.0f;
// v = 1.0f;
SqrDist = fA11+2.0f*fB1+fC;
}
else
{
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// u = 1.0f;
// v = 0.0f;
SqrDist = fA00+2.0f*fB0+fC;
}
else
{
u = fNumer/fDenom;
v = 1.0f - u;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
}
}
return fabsf(SqrDist) < mRadius2;
}
/*
* OPCODE - Optimized Collision Detection
* http://www.codercorner.com/Opcode.htm
*
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// This is collision detection. If you do another distance test for collision *response*,
// if might be useful to simply *skip* the test below completely, and report a collision.
// - if sphere-triangle overlap, result is ok
// - if they don't, we'll discard them during collision response with a similar test anyway
// Overall this approach should run faster.
// Original code by David Eberly in Magic.
BOOL SphereCollider::SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2)
{
// Stats
mNbVolumePrimTests++;
// Early exit if one of the vertices is inside the sphere
Point kDiff = vert2 - mCenter;
float fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
kDiff = vert1 - mCenter;
fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
kDiff = vert0 - mCenter;
fC = kDiff.SquareMagnitude();
if(fC <= mRadius2) return TRUE;
// Else do the full distance test
Point TriEdge0 = vert1 - vert0;
Point TriEdge1 = vert2 - vert0;
//Point kDiff = vert0 - mCenter;
float fA00 = TriEdge0.SquareMagnitude();
float fA01 = TriEdge0 | TriEdge1;
float fA11 = TriEdge1.SquareMagnitude();
float fB0 = kDiff | TriEdge0;
float fB1 = kDiff | TriEdge1;
//float fC = kDiff.SquareMagnitude();
float fDet = fabsf(fA00*fA11 - fA01*fA01);
float u = fA01*fB1-fA11*fB0;
float v = fA01*fB0-fA00*fB1;
float SqrDist;
if(u + v <= fDet)
{
if(u < 0.0f)
{
if(v < 0.0f) // region 4
{
if(fB0 < 0.0f)
{
// v = 0.0f;
if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
else
{
// u = 0.0f;
if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else // region 3
{
// u = 0.0f;
if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else if(v < 0.0f) // region 5
{
// v = 0.0f;
if(fB0>=0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
else if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
else // region 0
{
// minimum at interior point
if(fDet==0.0f)
{
// u = 0.0f;
// v = 0.0f;
SqrDist = MAX_FLOAT;
}
else
{
float fInvDet = 1.0f/fDet;
u *= fInvDet;
v *= fInvDet;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
}
else
{
float fTmp0, fTmp1, fNumer, fDenom;
if(u < 0.0f) // region 2
{
fTmp0 = fA01 + fB0;
fTmp1 = fA11 + fB1;
if(fTmp1 > fTmp0)
{
fNumer = fTmp1 - fTmp0;
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// u = 1.0f;
// v = 0.0f;
SqrDist = fA00+2.0f*fB0+fC;
}
else
{
u = fNumer/fDenom;
v = 1.0f - u;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
else
{
// u = 0.0f;
if(fTmp1 <= 0.0f) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; }
else if(fB1 >= 0.0f) { /*v = 0.0f;*/ SqrDist = fC; }
else { v = -fB1/fA11; SqrDist = fB1*v+fC; }
}
}
else if(v < 0.0f) // region 6
{
fTmp0 = fA01 + fB1;
fTmp1 = fA00 + fB0;
if(fTmp1 > fTmp0)
{
fNumer = fTmp1 - fTmp0;
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// v = 1.0f;
// u = 0.0f;
SqrDist = fA11+2.0f*fB1+fC;
}
else
{
v = fNumer/fDenom;
u = 1.0f - v;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
else
{
// v = 0.0f;
if(fTmp1 <= 0.0f) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; }
else if(fB0 >= 0.0f) { /*u = 0.0f;*/ SqrDist = fC; }
else { u = -fB0/fA00; SqrDist = fB0*u+fC; }
}
}
else // region 1
{
fNumer = fA11 + fB1 - fA01 - fB0;
if(fNumer <= 0.0f)
{
// u = 0.0f;
// v = 1.0f;
SqrDist = fA11+2.0f*fB1+fC;
}
else
{
fDenom = fA00-2.0f*fA01+fA11;
if(fNumer >= fDenom)
{
// u = 1.0f;
// v = 0.0f;
SqrDist = fA00+2.0f*fB0+fC;
}
else
{
u = fNumer/fDenom;
v = 1.0f - u;
SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC;
}
}
}
}
return fabsf(SqrDist) < mRadius2;
}

Some files were not shown because too many files have changed in this diff Show More