mirror of
https://github.com/lubosz/overte.git
synced 2025-04-14 14:46:55 +02:00
ShapeManager now under unit test
This commit is contained in:
parent
50a97849bb
commit
d26540b029
8 changed files with 544 additions and 45 deletions
|
@ -4,16 +4,9 @@ set(TARGET_NAME physics)
|
|||
setup_hifi_library()
|
||||
|
||||
include_glm()
|
||||
include_bullet()
|
||||
|
||||
link_hifi_libraries(shared)
|
||||
|
||||
# Note: we rely on the default FindBullet.cmake moduld that comes with cmake
|
||||
find_package(Bullet)
|
||||
if (BULLET_FOUND)
|
||||
include_directories(SYSTEM "${BULLET_INCLUDE_DIRS}")
|
||||
list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${BULLET_LIBRARIES}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_BULLET_PHYSICS")
|
||||
endif (BULLET_FOUND)
|
||||
|
||||
# call macro to link our dependencies and bubble them up via a property on our target
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
#include "PhysicsWorld.h"
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
#include "CollisionInfo.h"
|
||||
#include "RayIntersectionInfo.h"
|
||||
|
||||
|
|
159
libraries/physics/src/ShapeInfo.cpp
Normal file
159
libraries/physics/src/ShapeInfo.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
//
|
||||
// ShapeInfo.cpp
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.10.29
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
||||
#include "ShapeInfo.h"
|
||||
|
||||
void ShapeInfo::getInfo(const btCollisionShape* shape) {
|
||||
_data.clear();
|
||||
if (shape) {
|
||||
_type = (unsigned int)(shape->getShapeType());
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||
_data.push_back(boxShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||
_data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius()));
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
||||
_data.push_back(cylinderShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
||||
_data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f));
|
||||
// NOTE: we only support capsules with axis along yAxis
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
void ShapeInfo::setBox(const btVector3& halfExtents) {
|
||||
_type = BOX_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(halfExtents);
|
||||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
_type = SPHERE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(0.0f, 0.0f, radius));
|
||||
}
|
||||
|
||||
void ShapeInfo::setCylinder(float radius, float height) {
|
||||
_type = CYLINDER_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
_data.push_back(btVector3(radius, 0.5f * height, radius));
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsule(float radius, float height) {
|
||||
_type = CAPSULE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(radius, 0.5f * height, 0.0f));
|
||||
}
|
||||
|
||||
int ShapeInfo::computeHash() const {
|
||||
// This hash algorithm works well for shapes that have dimensions less than about 256m.
|
||||
// At larger values the likelihood of hash collision goes up because of the most
|
||||
// significant bits are pushed off the top and the result could be the same as for smaller
|
||||
// dimensions (truncation).
|
||||
//
|
||||
// The algorithm may produce collisions for shapes whose dimensions differ by less than
|
||||
// ~1/256 m, however this is by design -- we don't expect collision differences smaller
|
||||
// than 1 mm to be noticable.
|
||||
unsigned int key = 0;
|
||||
btVector3 tempData;
|
||||
int numData = _data.size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
// Successively multiply components of each vec3 by primes near 512 and convert to U32
|
||||
// to spread the data across more bits. Note that all dimensions are at half-value
|
||||
// (half extents, radius, etc) which is why we multiply by primes near 512 rather
|
||||
// than 256.
|
||||
tempData = _data[i];
|
||||
key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f))
|
||||
+ 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f))
|
||||
+ (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f));
|
||||
// avalanch the bits
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
}
|
||||
// finally XOR with type
|
||||
return (int)(key ^ _type);
|
||||
}
|
||||
|
||||
btCollisionShape* ShapeInfo::createShape() const {
|
||||
btCollisionShape* shape = NULL;
|
||||
int numData = _data.size();
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
shape = new btBoxShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getZ();
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
shape = new btCylinderShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getX();
|
||||
float height = 2.0f * _data[0].getY();
|
||||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
187
libraries/physics/src/ShapeInfo.h
Normal file
187
libraries/physics/src/ShapeInfo.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
//
|
||||
// ShapeInfo.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.10.29
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ShapeInfo_h
|
||||
#define hifi_ShapeInfo_h
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <LinearMath/btHashMap.h>
|
||||
|
||||
const float DEFAULT_MARGIN = 0.04f;
|
||||
|
||||
class ShapeInfo {
|
||||
public:
|
||||
ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {}
|
||||
|
||||
ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) {
|
||||
getInfo(shape);
|
||||
}
|
||||
|
||||
// BOOKMARK -- move ShapeInfo to its own files
|
||||
void getInfo(const btCollisionShape* shape);
|
||||
/*{
|
||||
_data.clear();
|
||||
if (shape) {
|
||||
_type = (unsigned int)(shape->getShapeType());
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||
_data.push_back(boxShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||
_data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius()));
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
||||
_data.push_back(cylinderShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
||||
_data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f));
|
||||
// NOTE: we only support capsules with axis along yAxis
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
}
|
||||
}*/
|
||||
|
||||
void setBox(const btVector3& halfExtents);
|
||||
/*{
|
||||
_type = BOX_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(halfExtents);
|
||||
}*/
|
||||
|
||||
void setSphere(float radius);
|
||||
/* {
|
||||
_type = SPHERE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(0.0f, 0.0f, radius));
|
||||
}*/
|
||||
|
||||
void setCylinder(float radius, float height);
|
||||
/*{
|
||||
_type = CYLINDER_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
_data.push_back(btVector3(radius, 0.5f * height, radius));
|
||||
}*/
|
||||
|
||||
void setCapsule(float radius, float height);
|
||||
/*{
|
||||
_type = CAPSULE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(radius, 0.5f * height, 0.0f));
|
||||
}*/
|
||||
|
||||
int computeHash() const;
|
||||
/*{
|
||||
// This hash algorithm works well for shapes that have dimensions less than about 256m.
|
||||
// At larger values the likelihood of hash collision goes up because of the most
|
||||
// significant bits are pushed off the top and the result could be the same as for smaller
|
||||
// dimensions (truncation).
|
||||
//
|
||||
// The algorithm may produce collisions for shapes whose dimensions differ by less than
|
||||
// ~1/256 m, however this is by design -- we don't expect collision differences smaller
|
||||
// than 1 mm to be noticable.
|
||||
unsigned int key = 0;
|
||||
btVector3 tempData;
|
||||
int numData = _data.size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
// Successively multiply components of each vec3 by primes near 512 and convert to U32
|
||||
// to spread the data across more bits. Note that all dimensions are at half-value
|
||||
// (half extents, radius, etc) which is why we multiply by primes near 512 rather
|
||||
// than 256.
|
||||
tempData = _data[i];
|
||||
key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f))
|
||||
+ 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f))
|
||||
+ (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f));
|
||||
// avalanch the bits
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
}
|
||||
// finally XOR with type
|
||||
return (int)(key ^ _type);
|
||||
}*/
|
||||
|
||||
private:
|
||||
friend class ShapeManager;
|
||||
|
||||
btCollisionShape* createShape() const;
|
||||
/*{
|
||||
btCollisionShape* shape = NULL;
|
||||
int numData = _data.size();
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
shape = new btBoxShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getZ();
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
shape = new btCylinderShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getX();
|
||||
float height = 2.0f * _data[0].getY();
|
||||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return shape;
|
||||
}*/
|
||||
|
||||
int _type;
|
||||
btAlignedObjectArray<btVector3> _data;
|
||||
};
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
#endif // hifi_ShapeInfo_h
|
|
@ -25,7 +25,7 @@ ShapeManager::~ShapeManager() {
|
|||
|
||||
|
||||
btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||
int key = info.getHash();
|
||||
int key = info.computeHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
shapeRef->_refCount++;
|
||||
|
@ -43,7 +43,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
}
|
||||
|
||||
bool ShapeManager::releaseShape(const ShapeInfo& info) {
|
||||
int key = info.getHash();
|
||||
int key = info.computeHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
if (shapeRef->_refCount > 0) {
|
||||
|
@ -67,6 +67,35 @@ bool ShapeManager::releaseShape(const ShapeInfo& info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
bool ShapeManager::releaseShape(const btCollisionShape* shape) {
|
||||
// when the number of shapes is high it's probably cheaper to try to construct a ShapeInfo
|
||||
// and then compute the hash rather than walking the list in search of the pointer.
|
||||
int key = info.computeHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
if (shapeRef->_refCount > 0) {
|
||||
shapeRef->_refCount--;
|
||||
if (shapeRef->_refCount == 0) {
|
||||
_pendingGarbage.push_back(key);
|
||||
const int MAX_GARBAGE_CAPACITY = 127;
|
||||
if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) {
|
||||
collectGarbage();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// attempt to remove shape that has no refs
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
// attempt to remove unmanaged shape
|
||||
assert(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void ShapeManager::collectGarbage() {
|
||||
int numShapes = _pendingGarbage.size();
|
||||
for (int i = 0; i < numShapes; ++i) {
|
||||
|
@ -82,7 +111,7 @@ void ShapeManager::collectGarbage() {
|
|||
}
|
||||
|
||||
int ShapeManager::getNumReferences(const ShapeInfo& info) const {
|
||||
int key = info.getHash();
|
||||
int key = info.computeHash();
|
||||
const ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
return shapeRef->_refCount;
|
||||
|
|
|
@ -17,48 +17,166 @@
|
|||
#include <btBulletDynamicsCommon.h>
|
||||
#include <LinearMath/btHashMap.h>
|
||||
|
||||
#include "ShapeInfo.h"
|
||||
|
||||
/*
|
||||
struct ShapeInfo {
|
||||
int _type;
|
||||
btVector3 _size;
|
||||
btAlignedObjectArray<btVector3> _data;
|
||||
//btVector3 _scale;
|
||||
|
||||
ShapeInfo() : _type(BOX_SHAPE_PROXYTYPE), _size(1.0f, 1.0f, 1.0f) {}
|
||||
ShapeInfo() : _type(INVALID_SHAPE_PROXYTYPE) {}
|
||||
|
||||
virtual int getHash() const {
|
||||
// successfully multiply components of size by primes near 256 and convert to U32
|
||||
unsigned int key = (unsigned int)(241.0f * _size.getX())
|
||||
+ 241 * (unsigned int)(251.0f * _size.getY())
|
||||
+ (241 * 251) * (unsigned int)(257.0f * _size.getZ());
|
||||
// then scramble the results
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
// finally XOR with type
|
||||
key ^= _type;
|
||||
return key;
|
||||
ShapeInfo(const btCollisionShape* shape) : _type(INVALID_SHAPE_PROXYTYPE) {
|
||||
getInfo(shape);
|
||||
}
|
||||
|
||||
// BOOKMARK -- move ShapeInfo to its own files
|
||||
void getInfo(const btCollisionShape* shape) {
|
||||
_data.clear();
|
||||
if (shape) {
|
||||
_type = (unsigned int)(shape->getShapeType());
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||
_data.push_back(boxShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||
_data.push_back(btVector3(0.0f, 0.0f, sphereShape->getRadius()));
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
||||
_data.push_back(cylinderShape->getHalfExtentsWithMargin());
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
||||
_data.push_back(btVector3(capsuleShape->getRadius(), capsuleShape->getHalfHeight(), 0.0f));
|
||||
// NOTE: we only support capsules with axis along yAxis
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_type = INVALID_SHAPE_PROXYTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
void setBox(const btVector3& halfExtents) {
|
||||
_type = BOX_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(halfExtents);
|
||||
}
|
||||
|
||||
void setSphere(float radius) {
|
||||
_type = SPHERE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(0.0f, 0.0f, radius));
|
||||
}
|
||||
|
||||
void setCylinder(float radius, float height) {
|
||||
_type = CYLINDER_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
_data.push_back(btVector3(radius, 0.5f * height, radius));
|
||||
}
|
||||
|
||||
void setCapsule(float radius, float height) {
|
||||
_type = CAPSULE_SHAPE_PROXYTYPE;
|
||||
_data.clear();
|
||||
_data.push_back(btVector3(radius, 0.5f * height, 0.0f));
|
||||
}
|
||||
|
||||
virtual int computeHash() const {
|
||||
// This hash algorithm works well for shapes that have dimensions less than about 256m.
|
||||
// At larger values the likelihood of hash collision goes up because of the most
|
||||
// significant bits are pushed off the top and the result could be the same as for smaller
|
||||
// dimensions (truncation).
|
||||
//
|
||||
// The algorithm may produce collisions for shapes whose dimensions differ by less than
|
||||
// ~1/256 m, however this is by design -- we don't expect collision differences smaller
|
||||
// than 1 mm to be noticable.
|
||||
unsigned int key = 0;
|
||||
btVector3 tempData;
|
||||
int numData = _data.size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
// Successively multiply components of each vec3 by primes near 512 and convert to U32
|
||||
// to spread the data across more bits. Note that all dimensions are at half-value
|
||||
// (half extents, radius, etc) which is why we multiply by primes near 512 rather
|
||||
// than 256.
|
||||
tempData = _data[i];
|
||||
key += (unsigned int)(509.0f * (tempData.getZ() + 0.01f))
|
||||
+ 509 * (unsigned int)(521.0f * (tempData.getY() + 0.01f))
|
||||
+ (509 * 521) * (unsigned int)(523.0f * (tempData.getX() + 0.01f));
|
||||
// avalanch the bits
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
}
|
||||
// finally XOR with type
|
||||
return (int)(key ^ _type);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ShapeManager;
|
||||
|
||||
virtual btCollisionShape* createShape() const {
|
||||
const float MAX_SHAPE_DIMENSION = 100.0f;
|
||||
const float MIN_SHAPE_DIMENSION = 0.01f;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
float side = _size[i];
|
||||
if (side > MAX_SHAPE_DIMENSION || side < MIN_SHAPE_DIMENSION) {
|
||||
return NULL;
|
||||
btCollisionShape* shape = NULL;
|
||||
int numData = _data.size();
|
||||
switch(_type) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
shape = new btBoxShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getZ();
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
btVector3 halfExtents = _data[0];
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// halfExtents = btVector3(radius, halfHeight, unused)
|
||||
shape = new btCylinderShape(halfExtents);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
{
|
||||
if (numData > 0) {
|
||||
float radius = _data[0].getX();
|
||||
float height = 2.0f * _data[0].getY();
|
||||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// default behavior is to create a btBoxShape
|
||||
return new btBoxShape(0.5f * _size);
|
||||
return shape;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShapeReference {
|
||||
int _refCount;
|
||||
btCollisionShape* _shape;
|
||||
ShapeReference() : _refCount(0), _shape(NULL) {}
|
||||
};
|
||||
*/
|
||||
|
||||
class ShapeManager {
|
||||
public:
|
||||
|
@ -71,6 +189,7 @@ public:
|
|||
|
||||
/// \return true if shape was found and released
|
||||
bool releaseShape(const ShapeInfo& info);
|
||||
// bool removeReference(const btCollisionShape*);
|
||||
|
||||
/// delete shapes that have zero references
|
||||
void collectGarbage();
|
||||
|
@ -80,6 +199,12 @@ public:
|
|||
int getNumReferences(const ShapeInfo& info) const;
|
||||
|
||||
private:
|
||||
struct ShapeReference {
|
||||
int _refCount;
|
||||
btCollisionShape* _shape;
|
||||
ShapeReference() : _refCount(0), _shape(NULL) {}
|
||||
};
|
||||
|
||||
btHashMap<btHashInt, ShapeReference> _shapeMap;
|
||||
btAlignedObjectArray<int> _pendingGarbage;
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@ set(TARGET_NAME physics-tests)
|
|||
setup_hifi_project()
|
||||
|
||||
include_glm()
|
||||
include_bullet()
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared physics)
|
||||
|
||||
link_shared_dependencies()
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
|
||||
#include "ShapeColliderTests.h"
|
||||
#include "VerletShapeTests.h"
|
||||
#include "ShapeManagerTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ShapeColliderTests::runAllTests();
|
||||
VerletShapeTests::runAllTests();
|
||||
//ShapeColliderTests::runAllTests();
|
||||
//VerletShapeTests::runAllTests();
|
||||
ShapeManagerTests::runAllTests();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue