mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 08:14:48 +02:00
Merge pull request #14887 from AndrewMeadows/shape-garbage-collector
Case 21066: restore shape caching in ShapeManager
This commit is contained in:
commit
3b5b077a3e
8 changed files with 141 additions and 93 deletions
|
@ -6228,40 +6228,57 @@ void Application::update(float deltaTime) {
|
|||
PROFILE_RANGE(simulation_physics, "PrePhysics");
|
||||
PerformanceTimer perfTimer("prePhysics)");
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "RemoveEntities");
|
||||
const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics();
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
{
|
||||
PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
}
|
||||
_entitySimulation->deleteObjectsRemovedFromPhysics();
|
||||
}
|
||||
|
||||
VectorOfMotionStates motionStates;
|
||||
getEntities()->getTree()->withReadLock([&] {
|
||||
_entitySimulation->getObjectsToAddToPhysics(motionStates);
|
||||
_physicsEngine->addObjects(motionStates);
|
||||
|
||||
});
|
||||
getEntities()->getTree()->withReadLock([&] {
|
||||
_entitySimulation->getObjectsToChange(motionStates);
|
||||
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
|
||||
_entitySimulation->setObjectsToChange(stillNeedChange);
|
||||
});
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "AddEntities");
|
||||
VectorOfMotionStates motionStates;
|
||||
getEntities()->getTree()->withReadLock([&] {
|
||||
_entitySimulation->getObjectsToAddToPhysics(motionStates);
|
||||
PROFILE_RANGE_EX(simulation_physics, "NumObjs", 0xffff0000, (uint64_t)motionStates.size());
|
||||
_physicsEngine->addObjects(motionStates);
|
||||
});
|
||||
}
|
||||
{
|
||||
VectorOfMotionStates motionStates;
|
||||
PROFILE_RANGE(simulation_physics, "ChangeEntities");
|
||||
getEntities()->getTree()->withReadLock([&] {
|
||||
_entitySimulation->getObjectsToChange(motionStates);
|
||||
VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(motionStates);
|
||||
_entitySimulation->setObjectsToChange(stillNeedChange);
|
||||
});
|
||||
}
|
||||
|
||||
_entitySimulation->applyDynamicChanges();
|
||||
|
||||
t1 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
|
||||
myAvatar->prepareForPhysicsSimulation();
|
||||
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "Avatars");
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
myAvatar->getCharacterController()->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
myAvatar->getCharacterController()->handleProcessedPhysicsTransaction(transaction);
|
||||
myAvatar->prepareForPhysicsSimulation();
|
||||
_physicsEngine->enableGlobalContactAddedCallback(myAvatar->isFlying());
|
||||
}
|
||||
|
||||
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
|
||||
dynamic->prepareForPhysicsSimulation();
|
||||
});
|
||||
{
|
||||
PROFILE_RANGE(simulation_physics, "PrepareActions");
|
||||
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
|
||||
dynamic->prepareForPhysicsSimulation();
|
||||
});
|
||||
}
|
||||
}
|
||||
auto t2 = std::chrono::high_resolution_clock::now();
|
||||
{
|
||||
|
|
|
@ -90,7 +90,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
if (!_uiTexture) {
|
||||
_uiTexture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
|
||||
|
@ -119,7 +119,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
|||
}
|
||||
|
||||
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
@ -176,7 +176,7 @@ static const auto DEFAULT_SAMPLER = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LI
|
|||
static const auto DEPTH_FORMAT = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||
|
||||
void ApplicationOverlay::buildFramebufferObject() {
|
||||
PROFILE_RANGE(app, __FUNCTION__);
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
auto uiSize = glm::uvec2(qApp->getUiSize());
|
||||
if (!_overlayFramebuffer || uiSize != _overlayFramebuffer->getSize()) {
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
|
||||
#include "ShapeFactory.h"
|
||||
|
||||
const int MAX_RING_SIZE = 256;
|
||||
|
||||
ShapeManager::ShapeManager() {
|
||||
_garbageRing.reserve(MAX_RING_SIZE);
|
||||
}
|
||||
|
||||
ShapeManager::~ShapeManager() {
|
||||
|
@ -33,8 +36,8 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
if (info.getType() == SHAPE_TYPE_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
HashKey key = info.getHash();
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
HashKey hashKey(info.getHash());
|
||||
ShapeReference* shapeRef = _shapeMap.find(hashKey);
|
||||
if (shapeRef) {
|
||||
shapeRef->refCount++;
|
||||
return shapeRef->shape;
|
||||
|
@ -44,23 +47,43 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
ShapeReference newRef;
|
||||
newRef.refCount = 1;
|
||||
newRef.shape = shape;
|
||||
newRef.key = key;
|
||||
_shapeMap.insert(key, newRef);
|
||||
newRef.key = info.getHash();
|
||||
_shapeMap.insert(hashKey, newRef);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
// private helper method
|
||||
bool ShapeManager::releaseShapeByKey(const HashKey& key) {
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
bool ShapeManager::releaseShapeByKey(uint64_t key) {
|
||||
HashKey hashKey(key);
|
||||
ShapeReference* shapeRef = _shapeMap.find(hashKey);
|
||||
if (shapeRef) {
|
||||
if (shapeRef->refCount > 0) {
|
||||
shapeRef->refCount--;
|
||||
if (shapeRef->refCount == 0) {
|
||||
_pendingGarbage.push_back(key);
|
||||
const int MAX_SHAPE_GARBAGE_CAPACITY = 255;
|
||||
if (_pendingGarbage.size() > MAX_SHAPE_GARBAGE_CAPACITY) {
|
||||
collectGarbage();
|
||||
// look for existing entry in _garbageRing
|
||||
int32_t ringSize = (int32_t)(_garbageRing.size());
|
||||
for (int32_t i = 0; i < ringSize; ++i) {
|
||||
int32_t j = (_ringIndex + ringSize) % ringSize;
|
||||
if (_garbageRing[j] == key) {
|
||||
// already on the list, don't add it again
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (ringSize == MAX_RING_SIZE) {
|
||||
// remove one
|
||||
HashKey hashKeyToRemove(_garbageRing[_ringIndex]);
|
||||
ShapeReference* shapeRef = _shapeMap.find(hashKeyToRemove);
|
||||
if (shapeRef && shapeRef->refCount == 0) {
|
||||
ShapeFactory::deleteShape(shapeRef->shape);
|
||||
_shapeMap.remove(hashKeyToRemove);
|
||||
}
|
||||
// replace at _ringIndex and advance
|
||||
_garbageRing[_ringIndex] = key;
|
||||
_ringIndex = (_ringIndex + 1) % ringSize;
|
||||
} else {
|
||||
// add one
|
||||
_garbageRing.push_back(key);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -87,21 +110,22 @@ bool ShapeManager::releaseShape(const btCollisionShape* shape) {
|
|||
}
|
||||
|
||||
void ShapeManager::collectGarbage() {
|
||||
int numShapes = _pendingGarbage.size();
|
||||
int numShapes = (int32_t)(_garbageRing.size());
|
||||
for (int i = 0; i < numShapes; ++i) {
|
||||
HashKey& key = _pendingGarbage[i];
|
||||
HashKey key(_garbageRing[i]);
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef && shapeRef->refCount == 0) {
|
||||
ShapeFactory::deleteShape(shapeRef->shape);
|
||||
_shapeMap.remove(key);
|
||||
}
|
||||
}
|
||||
_pendingGarbage.clear();
|
||||
_ringIndex = 0;
|
||||
_garbageRing.clear();
|
||||
}
|
||||
|
||||
int ShapeManager::getNumReferences(const ShapeInfo& info) const {
|
||||
HashKey key = info.getHash();
|
||||
const ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
HashKey hashKey(info.getHash());
|
||||
const ShapeReference* shapeRef = _shapeMap.find(hashKey);
|
||||
if (shapeRef) {
|
||||
return shapeRef->refCount;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_ShapeManager_h
|
||||
#define hifi_ShapeManager_h
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <LinearMath/btHashMap.h>
|
||||
|
||||
|
@ -41,6 +43,7 @@
|
|||
// later. When that list grows big enough the ShapeManager will remove any matching
|
||||
// entries that still have zero ref-count.
|
||||
|
||||
|
||||
class ShapeManager {
|
||||
public:
|
||||
|
||||
|
@ -63,19 +66,20 @@ public:
|
|||
bool hasShape(const btCollisionShape* shape) const;
|
||||
|
||||
private:
|
||||
bool releaseShapeByKey(const HashKey& key);
|
||||
bool releaseShapeByKey(uint64_t key);
|
||||
|
||||
class ShapeReference {
|
||||
public:
|
||||
int refCount;
|
||||
const btCollisionShape* shape;
|
||||
HashKey key;
|
||||
uint64_t key { 0 };
|
||||
ShapeReference() : refCount(0), shape(nullptr) {}
|
||||
};
|
||||
|
||||
// btHashMap is required because it supports memory alignment of the btCollisionShapes
|
||||
btHashMap<HashKey, ShapeReference> _shapeMap;
|
||||
btAlignedObjectArray<HashKey> _pendingGarbage;
|
||||
std::vector<uint64_t> _garbageRing;
|
||||
uint32_t _ringIndex { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeManager_h
|
||||
|
|
|
@ -32,17 +32,19 @@ class HashKey {
|
|||
public:
|
||||
static float getNumQuantizedValuesPerMeter();
|
||||
|
||||
HashKey() {}
|
||||
HashKey(uint64_t hash) : _hash(hash) {}
|
||||
|
||||
// These two methods are required by btHashMap.
|
||||
bool equals(const HashKey& other) const { return _hash == other._hash; }
|
||||
int32_t getHash() const { return (int32_t)((uint32_t)_hash); }
|
||||
|
||||
void clear() { _hash = _hashCount = 0; }
|
||||
bool isNull() const { return _hash == 0 && _hashCount == 0; }
|
||||
// These methods for accumulating a hash.
|
||||
void hashUint64(uint64_t data);
|
||||
void hashFloat(float data);
|
||||
void hashVec3(const glm::vec3& data);
|
||||
|
||||
uint64_t getHash64() const { return _hash; } // for debug/test purposes
|
||||
uint64_t getHash64() const { return _hash; }
|
||||
|
||||
private:
|
||||
uint64_t _hash { 0 };
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
#include "HashKey.h"
|
||||
#include "NumericalConstants.h" // for MILLIMETERS_PER_METER
|
||||
|
||||
/**jsdoc
|
||||
|
@ -96,7 +97,7 @@ void ShapeInfo::clear() {
|
|||
_sphereCollection.clear();
|
||||
_halfExtents = glm::vec3(0.0f);
|
||||
_offset = glm::vec3(0.0f);
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
_type = SHAPE_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
@ -131,14 +132,14 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
default:
|
||||
break;
|
||||
}
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
setHalfExtents(halfExtents);
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
|
@ -146,7 +147,7 @@ void ShapeInfo::setSphere(float radius) {
|
|||
_type = SHAPE_TYPE_SPHERE;
|
||||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
_halfExtents = glm::vec3(radius);
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std::vector<float>& radiuses) {
|
||||
|
@ -158,12 +159,12 @@ void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std:
|
|||
SphereData sphere = SphereData(centers[i], radiuses[i]);
|
||||
_sphereCollection.push_back(sphere);
|
||||
}
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
|
||||
_pointCollection = pointCollection;
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) {
|
||||
|
@ -172,12 +173,12 @@ void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) {
|
|||
radius = glm::max(radius, MIN_HALF_EXTENT);
|
||||
cylinderHalfHeight = glm::max(cylinderHalfHeight, 0.0f);
|
||||
_halfExtents = glm::vec3(radius, cylinderHalfHeight + radius, radius);
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
void ShapeInfo::setOffset(const glm::vec3& offset) {
|
||||
_offset = offset;
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
||||
uint32_t ShapeInfo::getNumSubShapes() const {
|
||||
|
@ -269,20 +270,21 @@ float ShapeInfo::computeVolume() const {
|
|||
return volume;
|
||||
}
|
||||
|
||||
const HashKey& ShapeInfo::getHash() const {
|
||||
uint64_t ShapeInfo::getHash() const {
|
||||
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_hashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
if (_hash64 == 0 && _type != SHAPE_TYPE_NONE) {
|
||||
HashKey hashKey;
|
||||
// The key is not yet cached therefore we must compute it.
|
||||
|
||||
_hashKey.hashUint64((uint64_t)_type);
|
||||
hashKey.hashUint64((uint64_t)_type);
|
||||
if (_type == SHAPE_TYPE_MULTISPHERE) {
|
||||
for (auto &sphereData : _sphereCollection) {
|
||||
_hashKey.hashVec3(glm::vec3(sphereData));
|
||||
_hashKey.hashFloat(sphereData.w);
|
||||
hashKey.hashVec3(glm::vec3(sphereData));
|
||||
hashKey.hashFloat(sphereData.w);
|
||||
}
|
||||
} else if (_type != SHAPE_TYPE_SIMPLE_HULL) {
|
||||
_hashKey.hashVec3(_halfExtents);
|
||||
_hashKey.hashVec3(_offset);
|
||||
hashKey.hashVec3(_halfExtents);
|
||||
hashKey.hashVec3(_offset);
|
||||
} else {
|
||||
// TODO: we could avoid hashing all of these points if we were to supply the ShapeInfo with a unique
|
||||
// descriptive string. Shapes that are uniquely described by their type and URL could just put their
|
||||
|
@ -292,7 +294,7 @@ const HashKey& ShapeInfo::getHash() const {
|
|||
const int numPoints = (int)points.size();
|
||||
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
_hashKey.hashVec3(points[i]);
|
||||
hashKey.hashVec3(points[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,23 +302,24 @@ const HashKey& ShapeInfo::getHash() const {
|
|||
if (!url.isEmpty()) {
|
||||
QByteArray baUrl = url.toLocal8Bit();
|
||||
uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size());
|
||||
_hashKey.hashUint64((uint64_t)urlHash);
|
||||
hashKey.hashUint64((uint64_t)urlHash);
|
||||
}
|
||||
|
||||
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
uint64_t numHulls = (uint64_t)_pointCollection.size();
|
||||
_hashKey.hashUint64(numHulls);
|
||||
hashKey.hashUint64(numHulls);
|
||||
} else if (_type == SHAPE_TYPE_MULTISPHERE) {
|
||||
uint64_t numSpheres = (uint64_t)_sphereCollection.size();
|
||||
_hashKey.hashUint64(numSpheres);
|
||||
hashKey.hashUint64(numSpheres);
|
||||
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
|
||||
_hashKey.hashUint64(1);
|
||||
}
|
||||
hashKey.hashUint64(1);
|
||||
}
|
||||
_hash64 = hashKey.getHash64();
|
||||
}
|
||||
return _hashKey;
|
||||
return _hash64;
|
||||
}
|
||||
|
||||
void ShapeInfo::setHalfExtents(const glm::vec3& halfExtents) {
|
||||
_halfExtents = glm::max(halfExtents, glm::vec3(MIN_HALF_EXTENT));
|
||||
_hashKey.clear();
|
||||
_hash64 = 0;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include "HashKey.h"
|
||||
|
||||
const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored
|
||||
|
||||
// Bullet has a mesh generation util for convex shapes that we used to
|
||||
|
@ -91,7 +89,7 @@ public:
|
|||
|
||||
float computeVolume() const;
|
||||
|
||||
const HashKey& getHash() const;
|
||||
uint64_t getHash() const;
|
||||
|
||||
protected:
|
||||
void setHalfExtents(const glm::vec3& halfExtents);
|
||||
|
@ -102,7 +100,7 @@ protected:
|
|||
TriangleIndices _triangleIndices;
|
||||
glm::vec3 _halfExtents = glm::vec3(0.0f);
|
||||
glm::vec3 _offset = glm::vec3(0.0f);
|
||||
mutable HashKey _hashKey;
|
||||
mutable uint64_t _hash64;
|
||||
ShapeType _type = SHAPE_TYPE_NONE;
|
||||
};
|
||||
|
||||
|
|
|
@ -55,20 +55,20 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
// test sphere
|
||||
info.setSphere(radiusX);
|
||||
++testCount;
|
||||
HashKey key = info.getHash();
|
||||
hashPtr = hashes.find(key);
|
||||
HashKey hashKey(info.getHash());
|
||||
hashPtr = hashes.find(hashKey);
|
||||
if (hashPtr) {
|
||||
std::cout << testCount << " hash collision sphere radius = " << radiusX
|
||||
<< " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr
|
||||
<< " h = 0x" << std::hex << hashKey.getHash() << " : 0x" << *hashPtr
|
||||
<< std::dec << std::endl;
|
||||
++numCollisions;
|
||||
assert(false);
|
||||
} else {
|
||||
hashes.insert(key, key.getHash());
|
||||
hashes.insert(hashKey, hashKey.getHash());
|
||||
}
|
||||
// track bit distribution counts to evaluate hash function randomness
|
||||
for (int j = 0; j < NUM_HASH_BITS; ++j) {
|
||||
if (masks[j] & key.getHash()) {
|
||||
if (masks[j] & hashKey.getHash()) {
|
||||
++bits[j];
|
||||
}
|
||||
}
|
||||
|
@ -80,21 +80,21 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
// test box
|
||||
info.setBox(glm::vec3(radiusX, radiusY, radiusZ));
|
||||
++testCount;
|
||||
HashKey key = info.getHash();
|
||||
hashPtr = hashes.find(key);
|
||||
HashKey hashKey(info.getHash());
|
||||
hashPtr = hashes.find(hashKey);
|
||||
if (hashPtr) {
|
||||
std::cout << testCount << " hash collision box dimensions = < " << radiusX
|
||||
<< ", " << radiusY << ", " << radiusZ << " >"
|
||||
<< " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr << " : 0x" << key.getHash64()
|
||||
<< " h = 0x" << std::hex << hashKey.getHash() << " : 0x" << *hashPtr << " : 0x" << hashKey.getHash64()
|
||||
<< std::dec << std::endl;
|
||||
++numCollisions;
|
||||
assert(false);
|
||||
} else {
|
||||
hashes.insert(key, key.getHash());
|
||||
hashes.insert(hashKey, hashKey.getHash());
|
||||
}
|
||||
// track bit distribution counts to evaluate hash function randomness
|
||||
for (int k = 0; k < NUM_HASH_BITS; ++k) {
|
||||
if (masks[k] & key.getHash()) {
|
||||
if (masks[k] & hashKey.getHash()) {
|
||||
++bits[k];
|
||||
}
|
||||
}
|
||||
|
@ -117,14 +117,14 @@ void ShapeInfoTests::testBoxShape() {
|
|||
ShapeInfo info;
|
||||
glm::vec3 halfExtents(1.23f, 4.56f, 7.89f);
|
||||
info.setBox(halfExtents);
|
||||
HashKey key = info.getHash();
|
||||
HashKey hashKey(info.getHash());
|
||||
|
||||
const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
HashKey otherKey = otherInfo.getHash();
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(hashKey.getHash(), otherKey.getHash());
|
||||
|
||||
delete shape;
|
||||
}
|
||||
|
@ -133,14 +133,14 @@ void ShapeInfoTests::testSphereShape() {
|
|||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
info.setSphere(radius);
|
||||
HashKey key = info.getHash();
|
||||
HashKey hashKey = info.getHash();
|
||||
|
||||
const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
HashKey otherKey = otherInfo.getHash();
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(hashKey.getHash(), otherKey.getHash());
|
||||
|
||||
delete shape;
|
||||
}
|
||||
|
@ -151,14 +151,14 @@ void ShapeInfoTests::testCylinderShape() {
|
|||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
info.setCylinder(radius, height);
|
||||
HashKey key = info.getHash();
|
||||
HashKey hashKey(info.getHash());
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
HashKey otherKey = otherInfo.getHash();
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(hashKey.getHash(), otherKey.getHash());
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
|
@ -170,14 +170,14 @@ void ShapeInfoTests::testCapsuleShape() {
|
|||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
info.setCapsule(radius, height);
|
||||
HashKey key = info.getHash();
|
||||
HashKey hashKey(info.getHash());
|
||||
|
||||
btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
|
||||
QCOMPARE(shape != nullptr, true);
|
||||
|
||||
ShapeInfo otherInfo = info;
|
||||
HashKey otherKey = otherInfo.getHash();
|
||||
QCOMPARE(key.getHash(), otherKey.getHash());
|
||||
QCOMPARE(hashKey.getHash(), otherKey.getHash());
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue