Committing height field terrain work from tomva1@yahoo.com

This commit is contained in:
john.mccutchan
2008-11-06 19:41:31 +00:00
parent 521314b9e7
commit 9b5df088de
18 changed files with 1257 additions and 130 deletions

View File

@@ -32,6 +32,7 @@ subject to the following restrictions:
#include "../ConstraintDemo/ConstraintDemo.h"
#include "../Benchmarks/BenchmarkDemo.h"
#include "../SoftDemo/SoftDemo.h"
#include "../TerrainDemo/TerrainDemo.h"
#include "GlutStuff.h"//OpenGL stuff
@@ -145,6 +146,7 @@ btDemoEntry g_demoEntries[] =
{"Raytracer Test",Raytracer::Create},
{"GjkConvexCast",LinearConvexCastDemo::Create},
{"VehicleDemo",VehicleDemo::Create},
{"TerrainDemo",btCreateTerrainDemo},
{"Benchmark 3000 FALL",BenchmarkDemo1::Create},
{"Benchmark 1000 STACK",BenchmarkDemo2::Create},
{"Benchmark 136 RAGDOLLS",BenchmarkDemo3::Create},

View File

@@ -21,4 +21,5 @@ FrameWorkDemo AllBulletDemos :
../VehicleDemo/VehicleDemo.cpp
../SoftDemo/SoftDemo.cpp
../ConstraintDemo/ConstraintDemo.cpp
../TerrainDemo/TerrainDemo.cpp
;

View File

@@ -19,6 +19,7 @@ AllBulletDemo_SOURCES=\
../GjkConvexCastDemo/LinearConvexCastDemo.cpp \
../ConcaveDemo/ConcavePhysicsDemo.cpp \
../DynamicControlDemo/MotorDemo.cpp \
../TerrainDemo/TerrainDemo.cpp \
DemoEntries.cpp \
DemoEntries.h\
Main.cpp

View File

@@ -1,5 +1,12 @@
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld CcdPhysicsDemo ConstraintDemo SliderConstraintDemo GenericJointDemo RagdollDemo ForkLiftDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo SoftDemo )
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld
CcdPhysicsDemo ConstraintDemo SliderConstraintDemo GenericJointDemo
RagdollDemo ForkLiftDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo
ColladaDemo UserCollisionAlgorithm CharacterDemo SoftDemo TerrainDemo )
else (CMAKE_SIZEOF_VOID_P MATCHES "8")
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld MultiThreadedDemo CcdPhysicsDemo ConstraintDemo SliderConstraintDemo GenericJointDemo RagdollDemo ForkLiftDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo SoftDemo )
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld
MultiThreadedDemo CcdPhysicsDemo ConstraintDemo SliderConstraintDemo
GenericJointDemo RagdollDemo ForkLiftDemo BasicDemo BspDemo MovingConcaveDemo
VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo SoftDemo
TerrainDemo )
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")

View File

@@ -101,4 +101,5 @@ SubInclude TOP Demos GjkConvexCastDemo ;
SubInclude TOP Demos Raytracer ;
SubInclude TOP Demos SimplexDemo ;
SubInclude TOP Demos DoublePrecisionDemo ;
SubInclude TOP Demos TerrainDemo ;

View File

@@ -0,0 +1,3 @@
SubDir TOP Demos TerrainDemo ;
BulletDemo TerrainDemo : [ Wildcard *.h *.cpp ] ;

View File

@@ -0,0 +1,5 @@
noinst_PROGRAMS=TerrainDemo
TerrainDemo_SOURCES=TerrainDemo.cpp TerrainDemo.h main.cpp
TerrainDemo_CXXFLAGS=-I@top_builddir@/src -I@top_builddir@/Demos/OpenGL $(CXXFLAGS)
TerrainDemo_LDADD=-L../OpenGL -lbulletopenglsupport -L../../src -lbulletdynamics -lbulletcollision -lbulletmath @opengl_LIBS@

View File

@@ -0,0 +1,926 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006,2008 Erwin Coumans http://continuousphysics.com/Bullet/
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.
*/
#include "TerrainDemo.h" // always include our own header first!
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
#include "GLDebugDrawer.h"
#include "GL_ShapeDrawer.h"
#include "GlutStuff.h"
#include "BMF_Api.h"
// constants -------------------------------------------------------------------
static const float s_gravity = 9.8; // 9.8 m/s^2
static const int s_gridSize = 64 + 1; // must be (2^N) + 1
static const float s_gridSpacing = 5.0;
static const float s_gridHeightScale = 0.2;
// the singularity at the center of the radial model means we need a lot of
// finely-spaced time steps to get the physics right.
// These numbers are probably too aggressive for a real game!
static const int s_requestedHz = 180;
static const float s_engineTimeStep = 1.0 / s_requestedHz;
// delta phase: radians per second
static const float s_deltaPhase = 0.25 * 2.0 * SIMD_PI;
// what type of terrain is generated?
enum eTerrainModel {
eRadial = 1, // deterministic
eFractal = 2 // random
};
typedef unsigned char byte_t;
////////////////////////////////////////////////////////////////////////////////
//
// static helper methods
//
// Only used within this file (helpers and terrain generation, etc)
//
////////////////////////////////////////////////////////////////////////////////
static const char *
getTerrainTypeName
(
eTerrainModel model
)
{
switch (model) {
case eRadial:
return "Radial";
case eFractal:
return "Fractal";
default:
btAssert(!"bad terrain model type");
}
return NULL;
}
static const char *
getDataTypeName
(
PHY_ScalarType type
)
{
switch (type) {
case PHY_UCHAR:
return "UnsignedChar";
case PHY_SHORT:
return "Short";
case PHY_FLOAT:
return "Float";
default:
btAssert(!"bad heightfield data type");
}
return NULL;
}
static const char *
getUpAxisName
(
int axis
)
{
switch (axis) {
case 0:
return "X";
case 1:
return "Y";
case 2:
return "Z";
default:
btAssert(!"bad up axis");
}
return NULL;
}
static btVector3
getUpVector
(
int upAxis,
btScalar regularValue,
btScalar upValue
)
{
btAssert(upAxis >= 0 && upAxis <= 2 && "bad up axis");
btVector3 v(regularValue, regularValue, regularValue);
v[upAxis] = upValue;
return v;
}
// TODO: it would probably cleaner to have a struct per data type, so
// you could lookup byte sizes, conversion functions, etc.
static int getByteSize
(
PHY_ScalarType type
)
{
int size = 0;
switch (type) {
case PHY_FLOAT:
size = sizeof(float);
break;
case PHY_UCHAR:
size = sizeof(unsigned char);
break;
case PHY_SHORT:
size = sizeof(short);
break;
default:
btAssert(!"Bad heightfield data type");
}
return size;
}
static float
convertToFloat
(
const byte_t * p,
PHY_ScalarType type
)
{
btAssert(p);
switch (type) {
case PHY_FLOAT:
{
float * pf = (float *) p;
return *pf;
}
case PHY_UCHAR:
{
unsigned char * pu = (unsigned char *) p;
return ((*pu) * s_gridHeightScale);
}
case PHY_SHORT:
{
short * ps = (short *) p;
return ((*ps) * s_gridHeightScale);
}
default:
btAssert(!"bad type");
}
return 0;
}
static float
getGridHeight
(
byte_t * grid,
int i,
int j,
PHY_ScalarType type
)
{
btAssert(grid);
btAssert(i >= 0 && i < s_gridSize);
btAssert(j >= 0 && j < s_gridSize);
int bpe = getByteSize(type);
btAssert(bpe > 0 && "bad bytes per element");
int idx = (j * s_gridSize) + i;
long offset = ((long) bpe) * idx;
byte_t * p = grid + offset;
return convertToFloat(p, type);
}
static void
convertFromFloat
(
byte_t * p,
float value,
PHY_ScalarType type
)
{
btAssert(p && "null");
switch (type) {
case PHY_FLOAT:
{
float * pf = (float *) p;
*pf = value;
}
break;
case PHY_UCHAR:
{
unsigned char * pu = (unsigned char *) p;
*pu = (unsigned char) (value / s_gridHeightScale);
}
break;
case PHY_SHORT:
{
short * ps = (short *) p;
*ps = (short) (value / s_gridHeightScale);
}
break;
default:
btAssert(!"bad type");
}
}
// creates a radially-varying heightfield
static void
setRadial
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
float phase = 0.0
)
{
btAssert(grid);
btAssert(bytesPerElement > 0);
// min/max
float period = 0.5 / s_gridSpacing;
float floor = 0.0;
float min_r = 3.0 * sqrt(s_gridSpacing);
float magnitude = 50.0 * sqrt(s_gridSpacing);
// pick a base_phase such that phase = 0 results in max height
// (this way, if you create a heightfield with phase = 0,
// you can rely on the min/max heights that result)
float base_phase = (0.5 * SIMD_PI) - (period * min_r);
phase += base_phase;
// center of grid
float cx = 0.5 * s_gridSize * s_gridSpacing;
float cy = cx; // assume square grid
byte_t * p = grid;
for (int i = 0; i < s_gridSize; ++i) {
float x = i * s_gridSpacing;
for (int j = 0; j < s_gridSize; ++j) {
float y = j * s_gridSpacing;
float dx = x - cx;
float dy = y - cy;
float r = sqrt((dx * dx) + (dy * dy));
float z = period;
if (r < min_r) {
r = min_r;
}
z = (1.0 / r) * sin(period * r + phase);
if (z > period) {
z = period;
} else if (z < -period) {
z = -period;
}
z = floor + magnitude * z;
convertFromFloat(p, z, type);
p += bytesPerElement;
}
}
}
static float
randomHeight
(
int step
)
{
return (0.33 * s_gridSpacing * s_gridSize * step * (rand() - (0.5 * RAND_MAX))) / (1.0 * RAND_MAX * s_gridSize);
}
static void
dumpGrid
(
const byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
int max
)
{
//std::cerr << "Grid:\n";
char buffer[32];
for (int j = 0; j < max; ++j) {
for (int i = 0; i < max; ++i) {
long offset = j * s_gridSize + i;
float z = convertToFloat(grid + offset * bytesPerElement, type);
sprintf(buffer, "%6.2f", z);
//std::cerr << " " << buffer;
}
//std::cerr << "\n";
}
}
static void
updateHeight
(
byte_t * p,
float new_val,
PHY_ScalarType type
)
{
float old_val = convertToFloat(p, type);
if (!old_val) {
convertFromFloat(p, new_val, type);
}
}
// creates a random, fractal heightfield
static void
setFractal
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
int step
)
{
btAssert(grid);
btAssert(bytesPerElement > 0);
btAssert(step > 0);
btAssert(step < s_gridSize);
int newStep = step / 2;
// std::cerr << "Computing grid with step = " << step << ": before\n";
// dumpGrid(grid, bytesPerElement, type, step + 1);
// special case: starting (must set four corners)
if (s_gridSize - 1 == step) {
// pick a non-zero (possibly negative) base elevation for testing
float base = randomHeight(step / 2);
convertFromFloat(grid, base, type);
convertFromFloat(grid + step * bytesPerElement, base, type);
convertFromFloat(grid + step * s_gridSize * bytesPerElement, base, type);
convertFromFloat(grid + (step * s_gridSize + step) * bytesPerElement, base, type);
}
// determine elevation of each corner
float c00 = convertToFloat(grid, type);
float c01 = convertToFloat(grid + step * bytesPerElement, type);
float c10 = convertToFloat(grid + (step * s_gridSize) * bytesPerElement, type);
float c11 = convertToFloat(grid + (step * s_gridSize + step) * bytesPerElement, type);
// set top middle
updateHeight(grid + newStep * bytesPerElement, 0.5 * (c00 + c01) + randomHeight(step), type);
// set left middle
updateHeight(grid + (newStep * s_gridSize) * bytesPerElement, 0.5 * (c00 + c10) + randomHeight(step), type);
// set right middle
updateHeight(grid + (newStep * s_gridSize + step) * bytesPerElement, 0.5 * (c01 + c11) + randomHeight(step), type);
// set bottom middle
updateHeight(grid + (step * s_gridSize + newStep) * bytesPerElement, 0.5 * (c10 + c11) + randomHeight(step), type);
// set middle
updateHeight(grid + (newStep * s_gridSize + newStep) * bytesPerElement, 0.25 * (c00 + c01 + c10 + c11) + randomHeight(step), type);
// std::cerr << "Computing grid with step = " << step << ": after\n";
// dumpGrid(grid, bytesPerElement, type, step + 1);
// terminate?
if (newStep < 2) {
return;
}
// recurse
setFractal(grid, bytesPerElement, type, newStep);
setFractal(grid + newStep * bytesPerElement, bytesPerElement, type, newStep);
setFractal(grid + (newStep * s_gridSize) * bytesPerElement, bytesPerElement, type, newStep);
setFractal(grid + ((newStep * s_gridSize) + newStep) * bytesPerElement, bytesPerElement, type, newStep);
}
static byte_t *
getRawHeightfieldData
(
eTerrainModel model,
PHY_ScalarType type,
btScalar& minHeight,
btScalar& maxHeight
)
{
// std::cerr << "\nRegenerating terrain\n";
// std::cerr << " model = " << model << "\n";
// std::cerr << " type = " << type << "\n";
long nElements = ((long) s_gridSize) * s_gridSize;
// std::cerr << " nElements = " << nElements << "\n";
int bytesPerElement = getByteSize(type);
// std::cerr << " bytesPerElement = " << bytesPerElement << "\n";
btAssert(bytesPerElement > 0 && "bad bytes per element");
long nBytes = nElements * bytesPerElement;
// std::cerr << " nBytes = " << nBytes << "\n";
byte_t * raw = new byte_t[nBytes];
btAssert(raw && "out of memory");
// reseed randomization every 30 seconds
srand(time(NULL) / 30);
// populate based on model
switch (model) {
case eRadial:
setRadial(raw, bytesPerElement, type);
break;
case eFractal:
for (int i = 0; i < nBytes; i++)
{
raw[i] = 0;
}
setFractal(raw, bytesPerElement, type, s_gridSize - 1);
break;
default:
btAssert(!"bad model type");
}
if (0) {
// inside if(0) so it keeps compiling but isn't
// exercised and doesn't cause warnings
// std::cerr << "final grid:\n";
dumpGrid(raw, bytesPerElement, type, s_gridSize - 1);
}
// find min/max
for (int i = 0; i < s_gridSize; ++i) {
for (int j = 0; j < s_gridSize; ++j) {
float z = getGridHeight(raw, i, j, type);
// std::cerr << "i=" << i << ", j=" << j << ": z=" << z << "\n";
// update min/max
if (!i && !j) {
minHeight = z;
maxHeight = z;
} else {
if (z < minHeight) {
minHeight = z;
}
if (z > maxHeight) {
maxHeight = z;
}
}
}
}
if (maxHeight < -minHeight) {
maxHeight = -minHeight;
}
if (minHeight > -maxHeight) {
minHeight = -maxHeight;
}
// std::cerr << " minHeight = " << minHeight << "\n";
// std::cerr << " maxHeight = " << maxHeight << "\n";
return raw;
}
////////////////////////////////////////////////////////////////////////////////
//
// TerrainDemo class
//
////////////////////////////////////////////////////////////////////////////////
/// class that demonstrates the btHeightfieldTerrainShape object
class TerrainDemo : public DemoApplication {
public:
// constructor, destructor ---------------------------------------------
TerrainDemo(void);
~TerrainDemo(void);
// public class methods ------------------------------------------------
void initialize(void);
// DemoApplication class interface methods -----------------------------
void clientMoveAndDisplay(void);
void keyboardCallback(unsigned char key, int x, int y);
void renderme(void);
private:
// private helper methods ----------------------------------------------
void resetPhysics(void);
void clearWorld(void);
// private data members ------------------------------------------------
btDefaultCollisionConfiguration * m_collisionConfiguration;
btCollisionDispatcher * m_dispatcher;
btAxisSweep3 * m_overlappingPairCache;
btSequentialImpulseConstraintSolver * m_constraintSolver;
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
int m_upAxis;
PHY_ScalarType m_type;
eTerrainModel m_model;
byte_t * m_rawHeightfieldData;
btScalar m_minHeight;
btScalar m_maxHeight;
float m_phase; // for dynamics
bool m_isDynamic;
};
TerrainDemo::TerrainDemo(void)
:
m_collisionConfiguration(NULL),
m_dispatcher(NULL),
m_overlappingPairCache(NULL),
m_constraintSolver(NULL),
m_upAxis(1),
m_type(PHY_FLOAT),
m_model(eFractal),
m_rawHeightfieldData(NULL),
m_phase(0.0),
m_isDynamic(true)
{
}
TerrainDemo::~TerrainDemo(void)
{
clearWorld();
//delete dynamics world
delete m_dynamicsWorld;
//delete solver
delete m_constraintSolver;
//delete broadphase
delete m_overlappingPairCache;
//delete dispatcher
delete m_dispatcher;
delete m_collisionConfiguration;
}
////////////////////////////////////////////////////////////////////////////////
//
// TerrainDemo -- public class methods
//
////////////////////////////////////////////////////////////////////////////////
/// one-time class and physics initialization
void TerrainDemo::initialize(void)
{
// std::cerr << "initializing...\n";
// set up basic state
m_upAxis = 1; // start with Y-axis as "up"
m_type = PHY_FLOAT;
m_model = eFractal;
m_isDynamic = true;
// set up the physics world
m_collisionConfiguration = new btDefaultCollisionConfiguration();
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
btVector3 worldMin(-1000,-1000,-1000);
btVector3 worldMax(1000,1000,1000);
m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
m_constraintSolver = new btSequentialImpulseConstraintSolver();
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
// initialize axis- or type-dependent physics from here
this->resetPhysics();
}
////////////////////////////////////////////////////////////////////////////////
//
// TerrainDemo -- DemoApplication class interface methods
//
////////////////////////////////////////////////////////////////////////////////
void TerrainDemo::clientMoveAndDisplay(void)
{
// elapsed time
float us = getDeltaTimeMicroseconds();
float seconds = 1.0e-6 * us;
// we'll carefully iterate through each time step so we can update
// the dynamic model if necessary
long nStepsPerIteration = 1;
while (seconds > 1.0e-6) {
float dt = nStepsPerIteration * s_engineTimeStep;
if (dt > seconds) {
dt = seconds;
}
seconds -= dt;
// std::cerr << " Stepping through " << dt << " seconds\n";
// if dynamic and radial, go ahead and update the field
if (m_rawHeightfieldData && m_isDynamic && eRadial == m_model) {
m_phase += s_deltaPhase * dt;
if (m_phase > 2.0 * SIMD_PI) {
m_phase -= 2.0 * SIMD_PI;
}
int bpe = getByteSize(m_type);
btAssert(bpe > 0 && "Bad bytes per element");
setRadial(m_rawHeightfieldData, bpe, m_type, m_phase);
}
if (m_dynamicsWorld) {
m_dynamicsWorld->stepSimulation(dt,
nStepsPerIteration + 1, s_engineTimeStep);
}
}
// okay, render
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderme();
glFlush();
glutSwapBuffers();
}
static PHY_ScalarType nextType (PHY_ScalarType type)
{
switch (type)
{
case PHY_FLOAT:
return PHY_SHORT;
break;
case PHY_SHORT:
return PHY_UCHAR;
break;
case PHY_UCHAR:
return PHY_FLOAT;
break;
}
btAssert (0);
return PHY_FLOAT;
}
void TerrainDemo::keyboardCallback(unsigned char key, int x, int y) {
if (',' == key) {
// increment model
m_model = (eFractal == m_model) ? eRadial : eFractal;
this->resetPhysics();
}
if ('/' == key) {
// increment type
m_type = nextType(m_type);
this->resetPhysics();
}
if ('\\' == key) {
// increment axis
m_upAxis++;
if (m_upAxis > 2) {
m_upAxis = 0;
}
this->resetPhysics();
}
if ('[' == key) {
// toggle dynamics
m_isDynamic = !m_isDynamic;
}
// let demo base class handle!
DemoApplication::keyboardCallback(key, x, y);
}
static void
doPrint
(
int x,
int& y,
int dy,
const char * text
)
{
glRasterPos3f(x, y, 0);
BMF_DrawString(BMF_GetFont(BMF_kHelvetica10), text);
y += dy;
}
/// override the default display just so we can overlay a bit more text
void TerrainDemo::renderme(void)
{
// give base class a shot
DemoApplication::renderme();
// overlay any debug information
if (m_dynamicsWorld)
m_dynamicsWorld->debugDrawWorld();
// switch to orthographic
setOrthographicProjection();
// we'll draw on the right top of the screen
const int lineWidth = 200;
const int lineHeight = 16;
char buffer[256];
int xStart = m_glutScreenWidth - lineWidth;
int yStart = lineHeight;
sprintf(buffer, "Terrain Type: %s", getTerrainTypeName(m_model));
doPrint(xStart, yStart, lineHeight, buffer);
doPrint(xStart, yStart, lineHeight, "Press ',' to cycle terrain types");
doPrint(xStart, yStart, lineHeight, "");
sprintf(buffer, "Data Type: %s", getDataTypeName(m_type));
doPrint(xStart, yStart, lineHeight, buffer);
doPrint(xStart, yStart, lineHeight, "Press '/' to cycle data types");
doPrint(xStart, yStart, lineHeight, "");
sprintf(buffer, "'up' axis: %s", getUpAxisName(m_upAxis));
doPrint(xStart, yStart, lineHeight, buffer);
doPrint(xStart, yStart, lineHeight, "Press '\\' to cycle 'up' axes");
doPrint(xStart, yStart, lineHeight, "");
if (eRadial == m_model) {
sprintf(buffer, "Dynamic: %s", m_isDynamic ? "yes" : "no");
doPrint(xStart, yStart, lineHeight, buffer);
doPrint(xStart, yStart, lineHeight, "Press '[' to toggle dynamics");
}
}
////////////////////////////////////////////////////////////////////////////////
//
// TerrainDemo -- private helper methods
//
////////////////////////////////////////////////////////////////////////////////
/// called whenever key terrain attribute is changed
void TerrainDemo::resetPhysics(void)
{
// remove old heightfield
clearWorld();
// reset gravity to point in appropriate direction
m_dynamicsWorld->setGravity(getUpVector(m_upAxis, 0.0, -s_gravity));
// get new heightfield of appropriate type
m_rawHeightfieldData =
getRawHeightfieldData(m_model, m_type, m_minHeight, m_maxHeight);
btAssert(m_rawHeightfieldData && "failed to create raw heightfield");
bool flipQuadEdges = false;
btHeightfieldTerrainShape * heightfieldShape =
new btHeightfieldTerrainShape(s_gridSize, s_gridSize,
m_rawHeightfieldData,
s_gridHeightScale,
m_minHeight, m_maxHeight,
m_upAxis, m_type, flipQuadEdges);
btAssert(heightfieldShape && "null heightfield");
// scale the shape
btVector3 localScaling = getUpVector(m_upAxis, s_gridSpacing, 1.0);
heightfieldShape->setLocalScaling(localScaling);
// stash this shape away
m_collisionShapes.push_back(heightfieldShape);
// set origin to middle of heightfield
btTransform tr;
tr.setIdentity();
// create ground object
float mass = 0.0;
localCreateRigidBody(mass, tr, heightfieldShape);
}
/// removes all objects and shapes from the world
void TerrainDemo::clearWorld(void)
{
//remove the rigidbodies from the dynamics world and delete them
int i;
for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
{
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject( obj );
delete obj;
}
//delete collision shapes
for (int j=0;j<m_collisionShapes.size();j++)
{
btCollisionShape* shape = m_collisionShapes[j];
delete shape;
}
m_collisionShapes.clear();
// delete raw heightfield data
delete m_rawHeightfieldData;
m_rawHeightfieldData = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// TerrainDemo -- public API (exposed in header)
//
////////////////////////////////////////////////////////////////////////////////
/// creates an object that demonstrates terrain
DemoApplication * btCreateTerrainDemo(void)
{
TerrainDemo * demo = new TerrainDemo;
btAssert(demo && "out of memory");
demo->initialize();
return demo;
}

View File

@@ -0,0 +1,27 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006,2008 Erwin Coumans http://continuousphysics.com/Bullet/
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.
*/
#ifndef TERRAIN_DEMO_H
#define TERRAIN_DEMO_H
#include "DemoApplication.h"
// all we need to expose publicly is the factory method!
DemoApplication * btCreateTerrainDemo(void);
#endif //TERRAIN_DEMO_H

View File

@@ -0,0 +1,14 @@
#include "TerrainDemo.h"
#include "GlutStuff.h"
int main(int argc,char** argv)
{
DemoApplication * demo = btCreateTerrainDemo();
btAssert(demo && "failed to create terrain demo object");
return glutmain(argc, argv, 800, 600,
"Terrain Demo. http://www.continuousphysics.com/Bullet/phpBB2/",
demo);
}

View File

@@ -1 +1 @@
SUBDIRS=src Extras Demos/OpenGL Demos/BasicDemo Demos/VehicleDemo Demos/CcdPhysicsDemo Demos/ColladaDemo Demos/MultiThreadedDemo Demos/SoftDemo Demos/AllBulletDemos
SUBDIRS=src Extras Demos/OpenGL Demos/BasicDemo Demos/TerrainDemo Demos/VehicleDemo Demos/CcdPhysicsDemo Demos/ColladaDemo Demos/MultiThreadedDemo Demos/SoftDemo Demos/AllBulletDemos

View File

@@ -154,7 +154,7 @@ CXXFLAGS="$CXXFLAGS $CFLAGS"
# Emit generated files.
#----------------------------------------------------------------------------
CS_JAMCONFIG_OUTPUT([Jamconfig])
AC_CONFIG_FILES([bullet.pc Jamfile Makefile Demos/SoftDemo/Makefile Demos/AllBulletDemos/Makefile Demos/MultiThreadedDemo/Makefile Demos/ColladaDemo/Makefile Demos/OpenGL/Makefile Demos/BasicDemo/Makefile Demos/CcdPhysicsDemo/Makefile Demos/VehicleDemo/Makefile src/Makefile Extras/Makefile])
AC_CONFIG_FILES([bullet.pc Jamfile Makefile Demos/SoftDemo/Makefile Demos/AllBulletDemos/Makefile Demos/MultiThreadedDemo/Makefile Demos/ColladaDemo/Makefile Demos/OpenGL/Makefile Demos/BasicDemo/Makefile Demos/CcdPhysicsDemo/Makefile Demos/VehicleDemo/Makefile Demos/TerrainDemo/Makefile src/Makefile Extras/Makefile])
AC_OUTPUT
AC_MSG_NOTICE([

View File

@@ -310,26 +310,7 @@ protected:
void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const;
#define USE_BANCHLESS 1
#ifdef USE_BANCHLESS
//This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360)
SIMD_FORCE_INLINE unsigned testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
return static_cast<unsigned int>(btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0])
& (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2])
& (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])),
1, 0));
}
#else
SIMD_FORCE_INLINE bool testQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) const
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
#endif //USE_BANCHLESS
void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex);

View File

@@ -20,6 +20,16 @@ subject to the following restrictions:
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types
#include "btTriangleCallback.h"
/// PHY_ScalarType enumerates possible scalar types.
/// See the btStridingMeshInterface or btHeightfieldTerrainShape for its use
typedef enum PHY_ScalarType {
PHY_FLOAT,
PHY_DOUBLE,
PHY_INTEGER,
PHY_SHORT,
PHY_FIXEDPOINT88,
PHY_UCHAR
} PHY_ScalarType;
///The btConcaveShape class provides an interface for non-moving (static) concave shapes.
///It has been implemented by the btStaticPlaneShape, btBvhTriangleMeshShape and btHeightfieldTerrainShape.

View File

@@ -18,71 +18,107 @@ subject to the following restrictions:
#include "LinearMath/btTransformUtil.h"
btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
: btConcaveShape (), m_heightStickWidth(heightStickWidth),
m_heightStickLength(heightStickLength),
m_maxHeight(maxHeight),
m_width((btScalar)heightStickWidth-1),
m_length((btScalar)heightStickLength-1),
m_heightfieldDataUnknown(heightfieldData),
m_useFloatData(useFloatData),
m_flipQuadEdges(flipQuadEdges),
m_useDiamondSubdivision(false),
m_upAxis(upAxis),
m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
btHeightfieldTerrainShape::btHeightfieldTerrainShape
(
int heightStickWidth, int heightStickLength, void* heightfieldData,
btScalar heightScale, btScalar minHeight, btScalar maxHeight,int upAxis,
PHY_ScalarType hdt, bool flipQuadEdges
)
{
initialize(heightStickWidth, heightStickLength, heightfieldData,
heightScale, minHeight, maxHeight, upAxis, hdt,
flipQuadEdges);
}
btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges)
{
// legacy constructor: support only float or unsigned char,
// and min height is zero
PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR;
btScalar minHeight = 0.0;
// previously, height = uchar * maxHeight / 65535.
// So to preserve legacy behavior, heightScale = maxHeight / 65535
btScalar heightScale = maxHeight / 65535;
initialize(heightStickWidth, heightStickLength, heightfieldData,
heightScale, minHeight, maxHeight, upAxis, hdt,
flipQuadEdges);
}
void btHeightfieldTerrainShape::initialize
(
int heightStickWidth, int heightStickLength, void* heightfieldData,
btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis,
PHY_ScalarType hdt, bool flipQuadEdges
)
{
// validation
btAssert(heightStickWidth > 1 && "bad width");
btAssert(heightStickLength > 1 && "bad length");
btAssert(heightfieldData && "null heightfield data");
// btAssert(heightScale) -- do we care? Trust caller here
btAssert(minHeight <= maxHeight && "bad min/max height");
btAssert(upAxis >= 0 && upAxis < 3 &&
"bad upAxis--should be in range [0,2]");
btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
"Bad height data type enum");
// initialize member variables
m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
m_heightStickWidth = heightStickWidth;
m_heightStickLength = heightStickLength;
m_minHeight = minHeight;
m_maxHeight = maxHeight;
m_width = (btScalar) (heightStickWidth - 1);
m_length = (btScalar) (heightStickLength - 1);
m_heightScale = heightScale;
m_heightfieldDataUnknown = heightfieldData;
m_heightDataType = hdt;
m_flipQuadEdges = flipQuadEdges;
m_useDiamondSubdivision = false;
m_upAxis = upAxis;
m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.));
btScalar quantizationMargin = 1.f;
//enlarge the AABB to avoid division by zero when initializing the quantization values
btVector3 clampValue(quantizationMargin,quantizationMargin,quantizationMargin);
btVector3 halfExtents(0,0,0);
// determine min/max axis-aligned bounding box (aabb) values
switch (m_upAxis)
{
case 0:
{
halfExtents.setValue(
btScalar(m_maxHeight),
btScalar(m_width), //?? don't know if this should change
btScalar(m_length));
m_localAabbMin.setValue(m_minHeight, 0, 0);
m_localAabbMax.setValue(m_maxHeight, m_width, m_length);
break;
}
case 1:
{
halfExtents.setValue(
btScalar(m_width),
btScalar(m_maxHeight),
btScalar(m_length));
m_localAabbMin.setValue(0, m_minHeight, 0);
m_localAabbMax.setValue(m_width, m_maxHeight, m_length);
break;
};
case 2:
{
halfExtents.setValue(
btScalar(m_width),
btScalar(m_length),
btScalar(m_maxHeight)
);
m_localAabbMin.setValue(0, 0, m_minHeight);
m_localAabbMax.setValue(m_width, m_length, m_maxHeight);
break;
}
default:
{
//need to get valid m_upAxis
btAssert(0);
btAssert(0 && "Bad m_upAxis");
}
}
halfExtents*= btScalar(0.5);
m_localAabbMin = -halfExtents - clampValue;
m_localAabbMax = halfExtents + clampValue;
btVector3 aabbSize = m_localAabbMax - m_localAabbMin;
// remember origin (defined as exact middle of aabb)
m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax);
}
btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
{
}
@@ -92,33 +128,53 @@ btHeightfieldTerrainShape::~btHeightfieldTerrainShape()
void btHeightfieldTerrainShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const
{
btVector3 halfExtents = (m_localAabbMax-m_localAabbMin)* m_localScaling * btScalar(0.5);
halfExtents += btVector3(getMargin(),getMargin(),getMargin());
btVector3 localOrigin(0, 0, 0);
localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5);
localOrigin *= m_localScaling;
btMatrix3x3 abs_b = t.getBasis().absolute();
btVector3 center = t.getOrigin();
btVector3 extent = btVector3(abs_b[0].dot(halfExtents),
abs_b[1].dot(halfExtents),
abs_b[2].dot(halfExtents));
extent += btVector3(getMargin(),getMargin(),getMargin());
aabbMin = center - extent;
aabbMax = center + extent;
}
btScalar btHeightfieldTerrainShape::getHeightFieldValue(int x,int y) const
{
btScalar val = 0.f;
if (m_useFloatData)
switch (m_heightDataType)
{
case PHY_FLOAT:
{
val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x];
} else
{
//assume unsigned short int
unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
val = heightFieldValue* (m_maxHeight/btScalar(65535));
break;
}
case PHY_UCHAR:
{
unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x];
val = heightFieldValue * m_heightScale;
break;
}
case PHY_SHORT:
{
short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x];
val = hfValue * m_heightScale;
break;
}
default:
{
btAssert(!"Bad m_heightDataType");
}
}
return val;
}
@@ -178,41 +234,73 @@ void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const
}
static inline int
getQuantized
(
float x
)
{
if (x < 0.0) {
return (int) (x - 0.5);
}
return (int) (x + 0.5);
}
/// given input vector, return quantized version
/**
This routine is basically determining the gridpoint indices for a given
input vector, answering the question: "which gridpoint is closest to the
provided point?".
"with clamp" means that we restrict the point to be in the heightfield's
axis-aligned bounding box.
*/
void btHeightfieldTerrainShape::quantizeWithClamp(int* out, const btVector3& point,int /*isMax*/) const
{
btVector3 clampedPoint(point);
clampedPoint.setMax(m_localAabbMin);
clampedPoint.setMin(m_localAabbMax);
btVector3 v = (clampedPoint);// - m_bvhAabbMin) * m_bvhQuantization;
///@todo: optimization: check out how to removed this btFabs
out[0] = (int)(v.getX() + v.getX() / btFabs(v.getX())* btScalar(0.5) );
out[1] = (int)(v.getY() + v.getY() / btFabs(v.getY())* btScalar(0.5) );
out[2] = (int)(v.getZ() + v.getZ() / btFabs(v.getZ())* btScalar(0.5) );
out[0] = getQuantized(clampedPoint.getX());
out[1] = getQuantized(clampedPoint.getY());
out[2] = getQuantized(clampedPoint.getZ());
}
/// process all triangles within the provided axis-aligned bounding box
/**
basic algorithm:
- convert input aabb to local coordinates (scale down and shift for local origin)
- convert input aabb to a range of heightfield grid points (quantize)
- iterate over all triangles in that subset of the grid
*/
void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
{
(void)callback;
(void)aabbMax;
(void)aabbMin;
//quantize the aabbMin and aabbMax, and adjust the start/end ranges
int quantizedAabbMin[3];
int quantizedAabbMax[3];
// scale down the input aabb's so they are in local (non-scaled) coordinates
btVector3 localAabbMin = aabbMin*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
btVector3 localAabbMax = aabbMax*btVector3(1.f/m_localScaling[0],1.f/m_localScaling[1],1.f/m_localScaling[2]);
// account for local origin
localAabbMin += m_localOrigin;
localAabbMax += m_localOrigin;
//quantize the aabbMin and aabbMax, and adjust the start/end ranges
int quantizedAabbMin[3];
int quantizedAabbMax[3];
quantizeWithClamp(quantizedAabbMin, localAabbMin,0);
quantizeWithClamp(quantizedAabbMax, localAabbMax,1);
// expand the min/max quantized values
// this is to catch the case where the input aabb falls between grid points!
for (int i = 0; i < 3; ++i) {
quantizedAabbMin[i]--;
quantizedAabbMax[i]++;
}
int startX=0;
int endX=m_heightStickWidth-1;
@@ -223,11 +311,6 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
{
case 0:
{
quantizedAabbMin[1]+=m_heightStickWidth/2-1;
quantizedAabbMax[1]+=m_heightStickWidth/2+1;
quantizedAabbMin[2]+=m_heightStickLength/2-1;
quantizedAabbMax[2]+=m_heightStickLength/2+1;
if (quantizedAabbMin[1]>startX)
startX = quantizedAabbMin[1];
if (quantizedAabbMax[1]<endX)
@@ -240,11 +323,6 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
}
case 1:
{
quantizedAabbMin[0]+=m_heightStickWidth/2-1;
quantizedAabbMax[0]+=m_heightStickWidth/2+1;
quantizedAabbMin[2]+=m_heightStickLength/2-1;
quantizedAabbMax[2]+=m_heightStickLength/2+1;
if (quantizedAabbMin[0]>startX)
startX = quantizedAabbMin[0];
if (quantizedAabbMax[0]<endX)
@@ -257,11 +335,6 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
};
case 2:
{
quantizedAabbMin[0]+=m_heightStickWidth/2-1;
quantizedAabbMax[0]+=m_heightStickWidth/2+1;
quantizedAabbMin[1]+=m_heightStickLength/2-1;
quantizedAabbMax[1]+=m_heightStickLength/2+1;
if (quantizedAabbMin[0]>startX)
startX = quantizedAabbMin[0];
if (quantizedAabbMax[0]<endX)

View File

@@ -18,28 +18,69 @@ subject to the following restrictions:
#include "btConcaveShape.h"
///The btHeightfieldTerrainShape simulates a 2D heightfield terrain collision shape. You can also use the more general btBvhTriangleMeshShape instead.
///An example implementation of btHeightfieldTerrainShape is provided in Demos/VehicleDemo/VehicleDemo.cpp
///btHeightfieldTerrainShape simulates a 2D heightfield terrain
/**
The caller is responsible for maintaining the heightfield array; this
class does not make a copy.
The heightfield can be dynamic so long as the min/max height values
capture the extremes (heights must always be in that range).
The local origin of the heightfield is assumed to be the exact
center (as determined by width and length and height, with each
axis multiplied by the localScaling).
Most (but not all) rendering and heightfield libraries assume upAxis = 1
(that is, the y-axis is "up"). This class allows any of the 3 coordinates
to be "up". Make sure your choice of axis is consistent with your rendering
system.
The heightfield heights are determined from the data type used for the
heightfieldData array.
- PHY_UCHAR: height at a point is the uchar value at the
grid point, multipled by heightScale. uchar isn't recommended
because of its inability to deal with negative values, and
low resolution (8-bit).
- PHY_SHORT: height at a point is the short int value at that grid
point, multipled by heightScale.
- PHY_FLOAT: height at a point is the float value at that grid
point. heightScale is ignored when using the float heightfield
data type.
Whatever the caller specifies as minHeight and maxHeight will be honored.
The class will not inspect the heightfield to discover the actual minimum
or maximum heights. These values are used to determine the heightfield's
axis-aligned bounding box, multiplied by localScaling.
For usage and testing see the TerrainDemo.
*/
class btHeightfieldTerrainShape : public btConcaveShape
{
protected:
btVector3 m_localAabbMin;
btVector3 m_localAabbMax;
btVector3 m_localOrigin;
///terrain data
int m_heightStickWidth;
int m_heightStickLength;
btScalar m_minHeight;
btScalar m_maxHeight;
btScalar m_width;
btScalar m_length;
btScalar m_heightScale;
union
{
unsigned char* m_heightfieldDataUnsignedChar;
short* m_heightfieldDataShort;
btScalar* m_heightfieldDataFloat;
void* m_heightfieldDataUnknown;
};
bool m_useFloatData;
PHY_ScalarType m_heightDataType;
bool m_flipQuadEdges;
bool m_useDiamondSubdivision;
@@ -51,17 +92,39 @@ protected:
void quantizeWithClamp(int* out, const btVector3& point,int isMax) const;
void getVertex(int x,int y,btVector3& vertex) const;
inline bool testQuantizedAabbAgainstQuantizedAabb(int* aabbMin1, int* aabbMax1,const int* aabbMin2,const int* aabbMax2) const
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
/// protected initialization
/**
Handles the work of constructors so that public constructors can be
backwards-compatible without a lot of copy/paste.
*/
void initialize(int heightStickWidth, int heightStickLength,
void* heightfieldData, btScalar heightScale,
btScalar minHeight, btScalar maxHeight, int upAxis,
PHY_ScalarType heightDataType, bool flipQuadEdges);
public:
btHeightfieldTerrainShape(int heightStickWidth,int heightStickHeight,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges);
/// preferred constructor
/**
This constructor supports a range of heightfield
data types, and allows for a non-zero minimum height value.
heightScale is needed for any integer-based heightfield data types.
*/
btHeightfieldTerrainShape(int heightStickWidth,int heightStickLength,
void* heightfieldData, btScalar heightScale,
btScalar minHeight, btScalar maxHeight,
int upAxis, PHY_ScalarType heightDataType,
bool flipQuadEdges);
/// legacy constructor
/**
The legacy constructor assumes the heightfield has a minimum height
of zero. Only unsigned char or floats are supported. For legacy
compatibility reasons, heightScale is calculated as maxHeight / 65535
(and is only used when useFloatData = false).
*/
btHeightfieldTerrainShape(int heightStickWidth,int heightStickLength,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges);
virtual ~btHeightfieldTerrainShape();

View File

@@ -18,16 +18,9 @@ subject to the following restrictions:
#include "LinearMath/btVector3.h"
#include "btTriangleCallback.h"
#include "btConcaveShape.h"
/// PHY_ScalarType enumerates possible scalar types.
/// See the btStridingMeshInterface for its use
typedef enum PHY_ScalarType {
PHY_FLOAT,
PHY_DOUBLE,
PHY_INTEGER,
PHY_SHORT,
PHY_FIXEDPOINT88
} PHY_ScalarType;
/// The btStridingMeshInterface is the interface class for high performance generic access to triangle meshes, used in combination with btBvhTriangleMeshShape and some other collision shapes.
/// Using index striding of 3*sizeof(integer) it can use triangle arrays, using index striding of 1*sizeof(integer) it can handle triangle strips.

View File

@@ -210,6 +210,26 @@ SIMD_FORCE_INLINE void btTransformAabb(const btVector3& localAabbMin,const btVec
aabbMaxOut = center+extent;
}
#define USE_BANCHLESS 1
#ifdef USE_BANCHLESS
//This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360)
SIMD_FORCE_INLINE unsigned testQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2)
{
return static_cast<unsigned int>(btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0])
& (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2])
& (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])),
1, 0));
}
#else
SIMD_FORCE_INLINE bool testQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2)
{
bool overlap = true;
overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap;
overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap;
overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap;
return overlap;
}
#endif //USE_BANCHLESS
#endif