mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 17:53:32 +02:00
ShapeInfo computs own DoubleHashKey, gets new API
This commit is contained in:
parent
13b00f3f8f
commit
12a7021bb5
7 changed files with 288 additions and 147 deletions
|
@ -9,7 +9,6 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <ShapeInfo.h>
|
||||
#include <SharedUtil.h> // for MILLIMETERS_PER_METER
|
||||
|
||||
#include "ShapeInfoUtil.h"
|
||||
|
@ -24,12 +23,9 @@ int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
|||
case SHAPE_TYPE_SPHERE:
|
||||
bulletShapeType = SPHERE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE:
|
||||
case SHAPE_TYPE_CAPSULE_Y:
|
||||
bulletShapeType = CAPSULE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER:
|
||||
bulletShapeType = CYLINDER_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
return bulletShapeType;
|
||||
}
|
||||
|
@ -44,10 +40,7 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
|||
shapeInfoType = SHAPE_TYPE_SPHERE;
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_CAPSULE;
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_CYLINDER;
|
||||
shapeInfoType = SHAPE_TYPE_CAPSULE_Y;
|
||||
break;
|
||||
}
|
||||
return shapeInfoType;
|
||||
|
@ -67,19 +60,6 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
|||
info.setSphere(sphereShape->getRadius());
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER: {
|
||||
// NOTE: we only support cylinders along yAxis
|
||||
const btCylinderShape* cylinderShape = static_cast<const btCylinderShape*>(shape);
|
||||
btVector3 halfExtents = cylinderShape->getHalfExtentsWithMargin();
|
||||
info.setCylinder(halfExtents.getX(), halfExtents.getY());
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE: {
|
||||
// NOTE: we only support capsules along yAxis
|
||||
const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
|
||||
info.setCapsule(capsuleShape->getRadius(), capsuleShape->getHalfHeight());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
info.clear();
|
||||
break;
|
||||
|
@ -91,27 +71,20 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
|||
|
||||
btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
||||
btCollisionShape* shape = NULL;
|
||||
const QVector<glm::vec3>& data = info.getData();
|
||||
switch(info.getType()) {
|
||||
case SHAPE_TYPE_BOX: {
|
||||
// data[0] is halfExtents
|
||||
shape = new btBoxShape(glmToBullet(data[0]));
|
||||
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
float radius = data[0].z;
|
||||
float radius = info.getHalfExtents().x;
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CYLINDER: {
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
// data[0] = btVector3(radius, halfHeight, unused)
|
||||
shape = new btCylinderShape(glmToBullet(data[0]));
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_CAPSULE: {
|
||||
float radius = data[0].x;
|
||||
float height = 2.0f * data[0].y;
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
glm::vec3 halfExtents = info.getHalfExtents();
|
||||
float radius = halfExtents.x;
|
||||
float height = 2.0f * halfExtents.y;
|
||||
shape = new btCapsuleShape(radius, height);
|
||||
}
|
||||
break;
|
||||
|
@ -119,49 +92,85 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
|||
return shape;
|
||||
}
|
||||
|
||||
DoubleHashKey ShapeInfoUtil::computeHash(const ShapeInfo& info) {
|
||||
DoubleHashKey key;
|
||||
// compute hash
|
||||
// scramble the bits of the type
|
||||
// TODO?: provide lookup table for hash of info._type rather than recompute?
|
||||
int primeIndex = 0;
|
||||
unsigned int hash = DoubleHashKey::hashFunction((unsigned int)info.getType(), primeIndex++);
|
||||
const QVector<glm::vec3>& data = info.getData();
|
||||
/*
|
||||
const DoubleHashKey& ShapeInfo::computeHash() {
|
||||
if (_hash.isNull()) {
|
||||
// compute hash1
|
||||
// TODO?: provide lookup table for hash/hash2 of _type rather than recompute?
|
||||
int primeIndex = 0;
|
||||
_doubleHashKey._hash = DoubleHashKey::hashFunction((uint32_t)_type, primeIndex++);
|
||||
_doubleHashKey._hash2 = DoubleHashKey::hashFunction2((uint32_t)_type());
|
||||
|
||||
if (getData()) {
|
||||
// if externalData exists we use that to continue the hash
|
||||
|
||||
glm::vec3 tmpData;
|
||||
int numData = data.size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = data[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
unsigned int floatHash =
|
||||
DoubleHashKey::hashFunction((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++);
|
||||
hash ^= floatHash;
|
||||
// compute hash
|
||||
uint32_t hash = _doubleHashKey._hash;
|
||||
const QVector<glm::vec3>& data = getData();
|
||||
|
||||
glm::vec3 tmpData;
|
||||
int numData = data.size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = data[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++);
|
||||
hash ^= floatHash;
|
||||
}
|
||||
}
|
||||
_doubleHashKey._hash = (int32_t)hash;
|
||||
|
||||
// compute hash2
|
||||
hash = _doubleHashKey._hash2;
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = data[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction2((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f));
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
}
|
||||
_doubleHashKey._hash2 = (uint32_t)hash;
|
||||
} else {
|
||||
// this shape info has no external data so we just use extents to continue hash
|
||||
// compute hash1
|
||||
uint32_t hash = _doubleHashKey._hash;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++);
|
||||
hash ^= floatHash;
|
||||
}
|
||||
_doubleHashKey._hash = (uint32_t)hash;
|
||||
|
||||
// compute hash2
|
||||
hash = _doubleHashKey._hash2;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction2((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f));
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
_doubleHashKey._hash2 = (uint32_t)hash;
|
||||
}
|
||||
}
|
||||
key._hash = (int)hash;
|
||||
|
||||
// compute hash2
|
||||
// scramble the bits of the type
|
||||
// TODO?: provide lookup table for hash2 of info._type rather than recompute?
|
||||
hash = DoubleHashKey::hashFunction2((unsigned int)info.getType());
|
||||
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = data[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
unsigned int floatHash =
|
||||
DoubleHashKey::hashFunction2((int)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f));
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
}
|
||||
key._hash2 = (int)hash;
|
||||
return key;
|
||||
|
||||
return _doubleHashKey;
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
#include <btBulletDynamicsCommon.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <DoubleHashKey.h>
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include "DoubleHashKey.h"
|
||||
|
||||
// translates between ShapeInfo and btShape
|
||||
|
||||
namespace ShapeInfoUtil {
|
||||
|
@ -26,7 +25,7 @@ namespace ShapeInfoUtil {
|
|||
|
||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
|
||||
DoubleHashKey computeHash(const ShapeInfo& info);
|
||||
//DoubleHashKey computeHash(const ShapeInfo& info);
|
||||
|
||||
// TODO? just use bullet shape types everywhere?
|
||||
int toBulletShapeType(int shapeInfoType);
|
||||
|
|
|
@ -28,13 +28,13 @@ ShapeManager::~ShapeManager() {
|
|||
|
||||
btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||
// Very small or large objects are not supported.
|
||||
float diagonal = glm::length2(info.getBoundingBoxDiagonal());
|
||||
float diagonal = 4.0f * glm::length2(info.getHalfExtents());
|
||||
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
|
||||
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
|
||||
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
|
||||
return NULL;
|
||||
}
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
shapeRef->_refCount++;
|
||||
|
@ -51,7 +51,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
}
|
||||
|
||||
bool ShapeManager::releaseShape(const ShapeInfo& info) {
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
if (shapeRef->_refCount > 0) {
|
||||
|
@ -95,7 +95,7 @@ void ShapeManager::collectGarbage() {
|
|||
}
|
||||
|
||||
int ShapeManager::getNumReferences(const ShapeInfo& info) const {
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
const ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef) {
|
||||
return shapeRef->_refCount;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// DoubleHashKey.cpp
|
||||
// libraries/physcis/src
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.11.02
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -11,8 +11,8 @@
|
|||
|
||||
#include "DoubleHashKey.h"
|
||||
|
||||
const int NUM_PRIMES = 64;
|
||||
const unsigned int PRIMES[] = {
|
||||
const uint32_t NUM_PRIMES = 64;
|
||||
const uint32_t PRIMES[] = {
|
||||
4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U,
|
||||
4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U,
|
||||
4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U,
|
||||
|
@ -23,8 +23,8 @@ const unsigned int PRIMES[] = {
|
|||
4193353U, 4193327U, 4193309U, 4193303U, 4193297U, 4193279U, 4193269U, 4193263U
|
||||
};
|
||||
|
||||
unsigned int DoubleHashKey::hashFunction(unsigned int value, int primeIndex) {
|
||||
unsigned int hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U);
|
||||
uint32_t DoubleHashKey::hashFunction(uint32_t value, uint32_t primeIndex) {
|
||||
uint32_t hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U);
|
||||
hash += ~(hash << 15);
|
||||
hash ^= (hash >> 10);
|
||||
hash += (hash << 3);
|
||||
|
@ -33,11 +33,16 @@ unsigned int DoubleHashKey::hashFunction(unsigned int value, int primeIndex) {
|
|||
return hash ^ (hash >> 16);
|
||||
}
|
||||
|
||||
unsigned int DoubleHashKey::hashFunction2(unsigned int value) {
|
||||
unsigned hash = 0x811c9dc5U;
|
||||
for (int i = 0; i < 4; i++ ) {
|
||||
unsigned int byte = (value << (i * 8)) >> (24 - i * 8);
|
||||
uint32_t DoubleHashKey::hashFunction2(uint32_t value) {
|
||||
uint32_t hash = 0x811c9dc5U;
|
||||
for (uint32_t i = 0; i < 4; i++ ) {
|
||||
uint32_t byte = (value << (i * 8)) >> (24 - i * 8);
|
||||
hash = ( hash ^ byte ) * 0x01000193U;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
void DoubleHashKey::computeHash(uint32_t value, uint32_t primeIndex) {
|
||||
_hash = DoubleHashKey::hashFunction(value, primeIndex);
|
||||
_hash2 = DoubleHashKey::hashFunction2(value);
|
||||
}
|
49
libraries/shared/src/DoubleHashKey.h
Normal file
49
libraries/shared/src/DoubleHashKey.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// DoubleHashKey.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.11.02
|
||||
// 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_DoubleHashKey_h
|
||||
#define hifi_DoubleHashKey_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// DoubleHashKey for use with btHashMap
|
||||
class DoubleHashKey {
|
||||
public:
|
||||
static uint32_t hashFunction(uint32_t value, uint32_t primeIndex);
|
||||
static uint32_t hashFunction2(uint32_t value);
|
||||
|
||||
DoubleHashKey() : _hash(0), _hash2(0) { }
|
||||
|
||||
DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) :
|
||||
_hash(hashFunction(value, primeIndex)),
|
||||
_hash2(hashFunction2(value)) {
|
||||
}
|
||||
|
||||
void clear() { _hash = 0; _hash2 = 0; }
|
||||
bool isNull() const { return _hash == 0 && _hash2 == 0; }
|
||||
|
||||
bool equals(const DoubleHashKey& other) const {
|
||||
return _hash == other._hash && _hash2 == other._hash2;
|
||||
}
|
||||
|
||||
void computeHash(uint32_t value, uint32_t primeIndex = 0);
|
||||
uint32_t getHash() const { return _hash; }
|
||||
uint32_t getHash2() const { return _hash2; }
|
||||
|
||||
void setHash(uint32_t hash) { _hash = hash; }
|
||||
void setHash2(uint32_t hash2) { _hash2 = hash2; }
|
||||
|
||||
private:
|
||||
uint32_t _hash;
|
||||
uint32_t _hash2;
|
||||
};
|
||||
|
||||
#endif // hifi_DoubleHashKey_h
|
|
@ -13,54 +13,40 @@
|
|||
|
||||
#include "SharedUtil.h" // for MILLIMETERS_PER_METER
|
||||
|
||||
//#include "DoubleHashKey.h"
|
||||
#include "ShapeInfo.h"
|
||||
|
||||
void ShapeInfo::clear() {
|
||||
_type = SHAPE_TYPE_NONE;
|
||||
_data.clear();
|
||||
_halfExtents = glm::vec3(0.0f);
|
||||
_doubleHashKey.clear();
|
||||
_externalData = NULL;
|
||||
}
|
||||
|
||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QVector<glm::vec3>* data) {
|
||||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
_data.clear();
|
||||
// _data[0] = < halfX, halfY, halfZ >
|
||||
_data.push_back(halfExtents);
|
||||
_halfExtents = halfExtents;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
_type = SHAPE_TYPE_SPHERE;
|
||||
_data.clear();
|
||||
// _data[0] = < radius, radius, radius >
|
||||
_data.push_back(glm::vec3(radius));
|
||||
_halfExtents = glm::vec3(radius, radius, radius);
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCylinder(float radius, float halfHeight) {
|
||||
_type = SHAPE_TYPE_CYLINDER;
|
||||
_data.clear();
|
||||
// _data[0] = < radius, halfHeight, radius >
|
||||
// NOTE: default cylinder has (UpAxis = 1) axis along yAxis and radius stored in X
|
||||
_data.push_back(glm::vec3(radius, halfHeight, radius));
|
||||
void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
|
||||
_type = SHAPE_TYPE_ELLIPSOID;
|
||||
_halfExtents = halfExtents;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsule(float radius, float halfHeight) {
|
||||
_type = SHAPE_TYPE_CAPSULE;
|
||||
_data.clear();
|
||||
// _data[0] = < radius, halfHeight, radius >
|
||||
_data.push_back(glm::vec3(radius, halfHeight, radius));
|
||||
}
|
||||
|
||||
glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const {
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_BOX:
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
case SHAPE_TYPE_CYLINDER:
|
||||
case SHAPE_TYPE_CAPSULE:
|
||||
return 2.0f * _data[0];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return glm::vec3(0.0f);
|
||||
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
||||
_type = SHAPE_TYPE_CAPSULE_Y;
|
||||
_halfExtents = glm::vec3(radius, halfHeight, radius);
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
float ShapeInfo::computeVolume() const {
|
||||
|
@ -68,23 +54,23 @@ float ShapeInfo::computeVolume() const {
|
|||
float volume = DEFAULT_VOLUME;
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_BOX: {
|
||||
// factor of 8.0 because the components of _data[0] are all halfExtents
|
||||
volume = 8.0f * _data[0].x * _data[0].y * _data[0].z;
|
||||
// factor of 8.0 because the components of _halfExtents are all halfExtents
|
||||
volume = 8.0f * _halfExtents.x * _halfExtents.y * _halfExtents.z;
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
float radius = _data[0].x;
|
||||
float radius = _halfExtents.x;
|
||||
volume = 4.0f * PI * radius * radius * radius / 3.0f;
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER: {
|
||||
float radius = _data[0].x;
|
||||
volume = PI * radius * radius * 2.0f * _data[0].y;
|
||||
case SHAPE_TYPE_CYLINDER_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * 2.0f * _halfExtents.y;
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE: {
|
||||
float radius = _data[0].x;
|
||||
volume = PI * radius * radius * (2.0f * _data[0].y + 4.0f * radius / 3.0f);
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * (2.0f * _halfExtents.y + 4.0f * radius / 3.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -93,3 +79,85 @@ float ShapeInfo::computeVolume() const {
|
|||
assert(volume > 0.0f);
|
||||
return volume;
|
||||
}
|
||||
|
||||
const DoubleHashKey& ShapeInfo::getHash() const {
|
||||
// NOTE: we cache the hash so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
// cast this to non-const pointer so we can do our dirty work
|
||||
ShapeInfo* thisPtr = const_cast<ShapeInfo*>(this);
|
||||
// compute hash1
|
||||
// TODO?: provide lookup table for hash/hash2 of _type rather than recompute?
|
||||
uint32_t primeIndex = 0;
|
||||
thisPtr->_doubleHashKey.computeHash((uint32_t)_type, primeIndex++);
|
||||
|
||||
const QVector<glm::vec3>* data = getData();
|
||||
if (data) {
|
||||
// if externalData exists we use it to continue the hash
|
||||
|
||||
// compute hash
|
||||
uint32_t hash = _doubleHashKey.getHash();
|
||||
|
||||
glm::vec3 tmpData;
|
||||
int numData = data->size();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = (*data)[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f), primeIndex++);
|
||||
hash ^= floatHash;
|
||||
}
|
||||
}
|
||||
thisPtr->_doubleHashKey.setHash(hash);
|
||||
|
||||
// compute hash2
|
||||
hash = _doubleHashKey.getHash2();
|
||||
for (int i = 0; i < numData; ++i) {
|
||||
tmpData = (*data)[i];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction2((uint32_t)(tmpData[j] * MILLIMETERS_PER_METER + copysignf(1.0f, tmpData[j]) * 0.49f));
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
}
|
||||
thisPtr->_doubleHashKey.setHash2(hash);
|
||||
} else {
|
||||
// this shape info has no external data so type+extents should be enough to generate a unique hash
|
||||
// compute hash1
|
||||
uint32_t hash = _doubleHashKey.getHash();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), primeIndex++);
|
||||
hash ^= floatHash;
|
||||
}
|
||||
thisPtr->_doubleHashKey.setHash(hash);
|
||||
|
||||
// compute hash2
|
||||
hash = _doubleHashKey.getHash2();
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
// NOTE: 0.49f is used to bump the float up almost half a millimeter
|
||||
// so the cast to int produces a round() effect rather than a floor()
|
||||
uint32_t floatHash =
|
||||
DoubleHashKey::hashFunction2((uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f));
|
||||
hash += ~(floatHash << 17);
|
||||
hash ^= (floatHash >> 11);
|
||||
hash += (floatHash << 4);
|
||||
hash ^= (floatHash >> 7);
|
||||
hash += ~(floatHash << 10);
|
||||
hash = (hash << 16) | (hash >> 16);
|
||||
}
|
||||
thisPtr->_doubleHashKey.setHash2(hash);
|
||||
}
|
||||
}
|
||||
return _doubleHashKey;
|
||||
}
|
||||
|
|
|
@ -15,40 +15,51 @@
|
|||
#include <QVector>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Shape.h"
|
||||
#include "DoubleHashKey.h"
|
||||
|
||||
enum ShapeType {
|
||||
SHAPE_TYPE_NONE,
|
||||
SHAPE_TYPE_BOX,
|
||||
SHAPE_TYPE_SPHERE,
|
||||
SHAPE_TYPE_ELLIPSOID,
|
||||
SHAPE_TYPE_CYLINDER,
|
||||
SHAPE_TYPE_CAPSULE,
|
||||
SHAPE_TYPE_CONVEX_HULL,
|
||||
SHAPE_TYPE_HULL,
|
||||
SHAPE_TYPE_PLANE,
|
||||
SHAPE_TYPE_COMPOUND
|
||||
SHAPE_TYPE_COMPOUND,
|
||||
SHAPE_TYPE_CAPSULE_X,
|
||||
SHAPE_TYPE_CAPSULE_Y,
|
||||
SHAPE_TYPE_CAPSULE_Z,
|
||||
SHAPE_TYPE_CYLINDER_X,
|
||||
SHAPE_TYPE_CYLINDER_Y,
|
||||
SHAPE_TYPE_CYLINDER_Z
|
||||
};
|
||||
|
||||
class ShapeInfo {
|
||||
public:
|
||||
ShapeInfo() : _type(SHAPE_TYPE_NONE) {}
|
||||
|
||||
void clear();
|
||||
|
||||
void setParams(ShapeType type, const glm::vec3& halfExtents, QVector<glm::vec3>* data = NULL);
|
||||
void setBox(const glm::vec3& halfExtents);
|
||||
void setSphere(float radius);
|
||||
void setCylinder(float radius, float halfHeight);
|
||||
void setCapsule(float radius, float halfHeight);
|
||||
void setEllipsoid(const glm::vec3& halfExtents);
|
||||
//void setHull(); // TODO: implement this
|
||||
void setCapsuleY(float radius, float halfHeight);
|
||||
|
||||
const int getType() const { return _type; }
|
||||
const QVector<glm::vec3>& getData() const { return _data; }
|
||||
|
||||
glm::vec3 getBoundingBoxDiagonal() const;
|
||||
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
||||
|
||||
void setData(const QVector<glm::vec3>* data) { _externalData = data; }
|
||||
const QVector<glm::vec3>* getData() const { return _externalData; }
|
||||
|
||||
float computeVolume() const;
|
||||
|
||||
const DoubleHashKey& getHash() const;
|
||||
|
||||
protected:
|
||||
int _type;
|
||||
QVector<glm::vec3> _data;
|
||||
ShapeType _type = SHAPE_TYPE_NONE;
|
||||
glm::vec3 _halfExtents = glm::vec3(0.0f);
|
||||
DoubleHashKey _doubleHashKey;
|
||||
const QVector<glm::vec3>* _externalData = NULL;
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeInfo_h
|
||||
|
|
Loading…
Reference in a new issue