mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 16:26:17 +02:00
Merge pull request #4269 from AndrewMeadows/thermonuclear
ModelEntityItem gets _shapeType
This commit is contained in:
commit
fa5eebd93e
36 changed files with 362 additions and 423 deletions
|
@ -155,6 +155,7 @@
|
|||
var elModelAnimationSettings = document.getElementById("property-model-animation-settings");
|
||||
var elModelTextures = document.getElementById("property-model-textures");
|
||||
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||
var elModelShapeType = document.getElementById("property-model-shape");
|
||||
|
||||
var elTextSections = document.querySelectorAll(".text-section");
|
||||
var elTextText = document.getElementById("property-text-text");
|
||||
|
@ -258,6 +259,7 @@
|
|||
elModelAnimationSettings.value = properties.animationSettings;
|
||||
elModelTextures.value = properties.textures;
|
||||
elModelOriginalTextures.value = properties.originalTextures;
|
||||
elModelShapeType.value = properties.shapeType;
|
||||
}
|
||||
|
||||
if (properties.type != "Text") {
|
||||
|
@ -404,6 +406,7 @@
|
|||
elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex'));
|
||||
elModelAnimationSettings.addEventListener('change', createEmitTextPropertyUpdateFunction('animationSettings'));
|
||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||
elModelShapeType.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeType'));
|
||||
|
||||
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
|
||||
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
|
||||
|
@ -664,6 +667,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="model-section property">
|
||||
<div class="label">Shape Type</div>
|
||||
<div class="value">
|
||||
<select name="SelectShapeType" id="property-model-shape" name="SelectShapeType">
|
||||
<option value=0>None</option>
|
||||
<option value=1>Box</option>
|
||||
<option value=2>Sphere</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-section property">
|
||||
<div class="label">Text</div>
|
||||
|
|
|
@ -760,19 +760,19 @@ void SkeletonModel::buildShapes() {
|
|||
Shape::Type type = joint.shapeType;
|
||||
int parentIndex = joint.parentIndex;
|
||||
if (parentIndex == -1 || radius < EPSILON) {
|
||||
type = SHAPE_TYPE_UNKNOWN;
|
||||
} else if (type == SHAPE_TYPE_CAPSULE && halfHeight < EPSILON) {
|
||||
type = INVALID_SHAPE;
|
||||
} else if (type == CAPSULE_SHAPE && halfHeight < EPSILON) {
|
||||
// this shape is forced to be a sphere
|
||||
type = SHAPE_TYPE_SPHERE;
|
||||
type = SPHERE_SHAPE;
|
||||
}
|
||||
Shape* shape = NULL;
|
||||
if (type == SHAPE_TYPE_SPHERE) {
|
||||
if (type == SPHERE_SHAPE) {
|
||||
shape = new VerletSphereShape(radius, &(points[i]));
|
||||
shape->setEntity(this);
|
||||
float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume());
|
||||
points[i].setMass(mass);
|
||||
totalMass += mass;
|
||||
} else if (type == SHAPE_TYPE_CAPSULE) {
|
||||
} else if (type == CAPSULE_SHAPE) {
|
||||
assert(parentIndex != -1);
|
||||
shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i]));
|
||||
shape->setEntity(this);
|
||||
|
|
|
@ -96,11 +96,6 @@ void BoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
|
|||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||
}
|
||||
|
||||
void BoxEntityItem::computeShapeInfo(ShapeInfo& info) const {
|
||||
glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
|
||||
info.setBox(halfExtents);
|
||||
}
|
||||
|
||||
void BoxEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qDebug() << " BOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
void computeShapeInfo(ShapeInfo& info) const;
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
||||
|
|
|
@ -57,8 +57,6 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
|
|||
_collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE;
|
||||
_locked = ENTITY_ITEM_DEFAULT_LOCKED;
|
||||
_userData = ENTITY_ITEM_DEFAULT_USER_DATA;
|
||||
|
||||
recalculateCollisionShape();
|
||||
}
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
||||
|
@ -70,7 +68,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
|||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_physicsInfo = NULL;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
_element = NULL;
|
||||
|
@ -86,7 +83,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
|
|||
_lastEditedFromRemote = 0;
|
||||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_created = UNKNOWN_CREATED_TIME;
|
||||
_physicsInfo = NULL;
|
||||
_dirtyFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
_element = NULL;
|
||||
|
@ -541,7 +537,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
|
||||
|
||||
recalculateCollisionShape();
|
||||
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) {
|
||||
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
|
||||
// closely match where the entities should be if they'd stepped forward in time to "now". The server
|
||||
|
@ -1003,14 +998,7 @@ float EntityItem::getRadius() const {
|
|||
}
|
||||
|
||||
void EntityItem::computeShapeInfo(ShapeInfo& info) const {
|
||||
info.clear();
|
||||
}
|
||||
|
||||
void EntityItem::recalculateCollisionShape() {
|
||||
AACube entityAACube = getMinimumAACube();
|
||||
entityAACube.scale(TREE_SCALE); // scale to meters
|
||||
_collisionShape.setTranslation(entityAACube.calcCenter());
|
||||
_collisionShape.setScale(entityAACube.getScale());
|
||||
info.setParams(getShapeType(), 0.5f * getDimensionsInMeters());
|
||||
}
|
||||
|
||||
const float MIN_POSITION_DELTA = 0.0001f;
|
||||
|
@ -1023,7 +1011,6 @@ const float MIN_SPIN_DELTA = 0.0003f;
|
|||
void EntityItem::updatePosition(const glm::vec3& value) {
|
||||
if (glm::distance(_position, value) * (float)TREE_SCALE > MIN_POSITION_DELTA) {
|
||||
_position = value;
|
||||
recalculateCollisionShape();
|
||||
_dirtyFlags |= EntityItem::DIRTY_POSITION;
|
||||
}
|
||||
}
|
||||
|
@ -1032,7 +1019,6 @@ void EntityItem::updatePositionInMeters(const glm::vec3& value) {
|
|||
glm::vec3 position = glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f);
|
||||
if (glm::distance(_position, position) * (float)TREE_SCALE > MIN_POSITION_DELTA) {
|
||||
_position = position;
|
||||
recalculateCollisionShape();
|
||||
_dirtyFlags |= EntityItem::DIRTY_POSITION;
|
||||
}
|
||||
}
|
||||
|
@ -1040,7 +1026,6 @@ void EntityItem::updatePositionInMeters(const glm::vec3& value) {
|
|||
void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||
if (_dimensions != value) {
|
||||
_dimensions = glm::abs(value);
|
||||
recalculateCollisionShape();
|
||||
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
||||
}
|
||||
}
|
||||
|
@ -1049,7 +1034,6 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
|
|||
glm::vec3 dimensions = glm::abs(value) / (float) TREE_SCALE;
|
||||
if (_dimensions != dimensions) {
|
||||
_dimensions = dimensions;
|
||||
recalculateCollisionShape();
|
||||
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
||||
}
|
||||
}
|
||||
|
@ -1057,7 +1041,6 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
|
|||
void EntityItem::updateRotation(const glm::quat& rotation) {
|
||||
if (glm::dot(_rotation, rotation) < MIN_ALIGNMENT_DOT) {
|
||||
_rotation = rotation;
|
||||
recalculateCollisionShape();
|
||||
_dirtyFlags |= EntityItem::DIRTY_POSITION;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <AACubeShape.h>
|
||||
#include <AnimationCache.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||
#include <CollisionInfo.h>
|
||||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
|
@ -150,7 +149,7 @@ public:
|
|||
glm::vec3 getPositionInMeters() const { return _position * (float) TREE_SCALE; } /// get position in meters
|
||||
|
||||
/// set position in domain scale units (0.0 - 1.0)
|
||||
void setPosition(const glm::vec3& value) { _position = value; recalculateCollisionShape(); }
|
||||
void setPosition(const glm::vec3& value) { _position = value; }
|
||||
void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE)
|
||||
{ setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); }
|
||||
|
||||
|
@ -162,13 +161,13 @@ public:
|
|||
float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3& value) { _dimensions = value; recalculateCollisionShape(); }
|
||||
virtual void setDimensions(const glm::vec3& value) { _dimensions = value; }
|
||||
|
||||
/// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately
|
||||
void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); }
|
||||
|
||||
const glm::quat& getRotation() const { return _rotation; }
|
||||
void setRotation(const glm::quat& rotation) { _rotation = rotation; recalculateCollisionShape(); }
|
||||
void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
||||
|
||||
float getGlowLevel() const { return _glowLevel; }
|
||||
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
|
||||
|
@ -225,7 +224,7 @@ public:
|
|||
|
||||
/// registration point as ratio of entity
|
||||
void setRegistrationPoint(const glm::vec3& value)
|
||||
{ _registrationPoint = glm::clamp(value, 0.0f, 1.0f); recalculateCollisionShape(); }
|
||||
{ _registrationPoint = glm::clamp(value, 0.0f, 1.0f); }
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
|
||||
|
@ -254,11 +253,12 @@ public:
|
|||
// TODO: We need to get rid of these users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
||||
void applyHardCollision(const CollisionInfo& collisionInfo);
|
||||
virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; }
|
||||
virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); }
|
||||
virtual void computeShapeInfo(ShapeInfo& info) const;
|
||||
|
||||
/// return preferred shape type (actual physical shape may differ)
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
||||
|
||||
// updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags
|
||||
void updatePosition(const glm::vec3& value);
|
||||
void updatePositionInMeters(const glm::vec3& value);
|
||||
|
@ -277,6 +277,7 @@ public:
|
|||
void updateIgnoreForCollisions(bool value);
|
||||
void updateCollisionsWillMove(bool value);
|
||||
void updateLifetime(float value);
|
||||
virtual void updateShapeType(ShapeType type) { /* do nothing */ }
|
||||
|
||||
uint32_t getDirtyFlags() const { return _dirtyFlags; }
|
||||
void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; }
|
||||
|
@ -297,7 +298,6 @@ protected:
|
|||
static bool _sendPhysicsUpdates;
|
||||
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
virtual void recalculateCollisionShape();
|
||||
|
||||
EntityTypes::EntityType _type;
|
||||
QUuid _id;
|
||||
|
@ -353,11 +353,9 @@ protected:
|
|||
/// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis
|
||||
void setRadius(float value);
|
||||
|
||||
AACubeShape _collisionShape;
|
||||
|
||||
// _physicsInfo is a hook reserved for use by the EntitySimulation, which is guaranteed to set _physicsInfo
|
||||
// to a non-NULL value when the EntityItem has a representation in the physics engine.
|
||||
void* _physicsInfo; // only set by EntitySimulation
|
||||
void* _physicsInfo = NULL; // only set by EntitySimulation
|
||||
|
||||
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
|
||||
uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
|
||||
|
|
|
@ -64,6 +64,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
|
||||
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
|
||||
CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR),
|
||||
CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE),
|
||||
|
||||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
|
@ -210,6 +211,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_LINE_HEIGHT, lineHeight);
|
||||
CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_SHAPE_TYPE, shapeType);
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
@ -268,6 +270,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(textColor, getTextColor());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR_GETTER(backgroundColor, getBackgroundColor());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(shapeType);
|
||||
|
||||
// Sitting properties support
|
||||
QScriptValue sittingPoints = engine->newObject();
|
||||
|
@ -347,6 +350,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lineHeight, setLineHeight);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(textColor, setTextColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(backgroundColor, setBackgroundColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(shapeType, setShapeType, ShapeType);
|
||||
|
||||
_lastEdited = usecTimestampNow();
|
||||
}
|
||||
|
@ -510,6 +514,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, properties.getAnimationIsPlaying());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)(properties.getShapeType()));
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Light) {
|
||||
|
@ -731,6 +736,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Light) {
|
||||
|
@ -820,6 +826,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_lineHeightChanged = true;
|
||||
_textColorChanged = true;
|
||||
_backgroundColorChanged = true;
|
||||
_shapeTypeChanged = true;
|
||||
}
|
||||
|
||||
AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const {
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <FBXReader.h> // for SittingPoint
|
||||
#include <PropertyFlags.h>
|
||||
#include <OctreeConstants.h>
|
||||
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
|
@ -82,8 +82,10 @@ enum EntityPropertyList {
|
|||
PROP_TEXTURES,
|
||||
PROP_ANIMATION_SETTINGS,
|
||||
PROP_USER_DATA,
|
||||
|
||||
PROP_LAST_ITEM = PROP_USER_DATA,
|
||||
PROP_SHAPE_TYPE,
|
||||
|
||||
// NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below
|
||||
PROP_LAST_ITEM = PROP_SHAPE_TYPE,
|
||||
|
||||
// These properties of TextEntity piggy back off of properties of ModelEntities, the type doesn't matter
|
||||
// since the derived class knows how to interpret it's own properties and knows the types it expects
|
||||
|
@ -179,6 +181,7 @@ public:
|
|||
DEFINE_PROPERTY(PROP_LINE_HEIGHT, LineHeight, lineHeight, float);
|
||||
DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType);
|
||||
|
||||
public:
|
||||
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
|
||||
|
|
|
@ -180,6 +180,15 @@
|
|||
#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \
|
||||
properties.setProperty(#P, _##P);
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S, E) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
E newValue = (E)(P.toVariant().toInt()); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
|
|
|
@ -11,9 +11,6 @@
|
|||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <AACubeShape.h>
|
||||
#include <ShapeCollider.h>
|
||||
|
||||
#include <FBXReader.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
||||
|
@ -570,33 +567,6 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
|
|||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeElement::findShapeCollisions(const Shape* shape, CollisionList& collisions) const {
|
||||
bool atLeastOneCollision = false;
|
||||
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
|
||||
QList<EntityItem*>::const_iterator entityEnd = _entityItems->end();
|
||||
while(entityItr != entityEnd) {
|
||||
EntityItem* entity = (*entityItr);
|
||||
|
||||
// entities that are set for ignore for collisions then don't consider them for collision
|
||||
const Shape* otherCollisionShape = &entity->getCollisionShapeInMeters();
|
||||
|
||||
bool ignoreForCollisions = entity->getIgnoreForCollisions();
|
||||
if (shape != otherCollisionShape && !ignoreForCollisions) {
|
||||
if (ShapeCollider::collideShapes(shape, otherCollisionShape, collisions)) {
|
||||
CollisionInfo* lastCollision = collisions.getLastCollision();
|
||||
if (lastCollision) {
|
||||
lastCollision->_extraData = entity;
|
||||
atLeastOneCollision = true;
|
||||
} else {
|
||||
qDebug() << "UNEXPECTED - ShapeCollider::collideShapes() returned true, but no lastCollision.";
|
||||
}
|
||||
}
|
||||
}
|
||||
++entityItr;
|
||||
}
|
||||
return atLeastOneCollision;
|
||||
}
|
||||
|
||||
void EntityTreeElement::updateEntityItemID(const EntityItemID& creatorTokenEntityID, const EntityItemID& knownIDEntityID) {
|
||||
uint16_t numberOfEntities = _entityItems->size();
|
||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
||||
|
|
|
@ -142,8 +142,6 @@ public:
|
|||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
||||
virtual bool findShapeCollisions(const Shape* shape, CollisionList& collisions) const;
|
||||
|
||||
const QList<EntityItem*>& getEntities() const { return *_entityItems; }
|
||||
QList<EntityItem*>& getEntities() { return *_entityItems; }
|
||||
bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; }
|
||||
|
|
|
@ -42,16 +42,11 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityI
|
|||
_cutoff = PI;
|
||||
|
||||
setProperties(properties);
|
||||
|
||||
// a light is not collide-able so we make it's shape be a tiny sphere at origin
|
||||
_emptyShape.setTranslation(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
_emptyShape.setRadius(0.0f);
|
||||
}
|
||||
|
||||
void LightEntityItem::setDimensions(const glm::vec3& value) {
|
||||
float maxDimension = glm::max(value.x, value.y, value.z);
|
||||
_dimensions = glm::vec3(maxDimension, maxDimension, maxDimension);
|
||||
recalculateCollisionShape();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#ifndef hifi_LightEntityItem_h
|
||||
#define hifi_LightEntityItem_h
|
||||
|
||||
#include <SphereShape.h>
|
||||
#include "EntityItem.h"
|
||||
|
||||
class LightEntityItem : public EntityItem {
|
||||
|
@ -98,13 +97,10 @@ public:
|
|||
float getCutoff() const { return _cutoff; }
|
||||
void setCutoff(float value) { _cutoff = value; }
|
||||
|
||||
virtual const Shape& getCollisionShapeInMeters() const { return _emptyShape; }
|
||||
|
||||
static bool getLightsArePickable() { return _lightsArePickable; }
|
||||
static void setLightsArePickable(bool value) { _lightsArePickable = value; }
|
||||
|
||||
protected:
|
||||
virtual void recalculateCollisionShape() { /* nothing to do */ }
|
||||
|
||||
// properties of a light
|
||||
rgbColor _ambientColor;
|
||||
|
@ -117,9 +113,6 @@ protected:
|
|||
float _exponent;
|
||||
float _cutoff;
|
||||
|
||||
// used for collision detection
|
||||
SphereShape _emptyShape;
|
||||
|
||||
static bool _lightsArePickable;
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationSettings, getAnimationSettings);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -66,6 +67,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationSettings, setAnimationSettings);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -116,6 +118,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_TEXTURES, setTextures);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_SETTINGS, setAnimationSettings);
|
||||
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -131,6 +134,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
|
|||
requestedProperties += PROP_ANIMATION_PLAYING;
|
||||
requestedProperties += PROP_ANIMATION_SETTINGS;
|
||||
requestedProperties += PROP_TEXTURES;
|
||||
requestedProperties += PROP_SHAPE_TYPE;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -153,6 +157,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, getAnimationIsPlaying());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, getTextures());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, getAnimationSettings());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
|
||||
}
|
||||
|
||||
|
||||
|
@ -245,21 +250,6 @@ bool ModelEntityItem::needsToCallUpdate() const {
|
|||
return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate();
|
||||
}
|
||||
|
||||
void ModelEntityItem::computeShapeInfo(ShapeInfo& info) const {
|
||||
// HACK: Default first first approximation is to boxify the entity... but only if it is small enough.
|
||||
// The limit here is chosen to something that most avatars could not comfortably fit inside
|
||||
// to prevent houses from getting boxified... we don't want the things inside houses to
|
||||
// collide with a house as if it were a giant solid block.
|
||||
const float MAX_SIZE_FOR_BOXIFICATION_HACK = 3.0f;
|
||||
float diagonal = glm::length(getDimensionsInMeters());
|
||||
if (diagonal < MAX_SIZE_FOR_BOXIFICATION_HACK) {
|
||||
glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
|
||||
info.setBox(halfExtents);
|
||||
} else {
|
||||
info.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::update(const quint64& now) {
|
||||
// only advance the frame index if we're playing
|
||||
if (getAnimationIsPlaying()) {
|
||||
|
@ -280,6 +270,13 @@ void ModelEntityItem::debugDump() const {
|
|||
qDebug() << " model URL:" << getModelURL();
|
||||
}
|
||||
|
||||
void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||
if (type != _shapeType) {
|
||||
_shapeType = type;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setAnimationURL(const QString& url) {
|
||||
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
|
||||
_animationURL = url;
|
||||
|
|
|
@ -46,9 +46,10 @@ public:
|
|||
|
||||
virtual void update(const quint64& now);
|
||||
virtual bool needsToCallUpdate() const;
|
||||
void computeShapeInfo(ShapeInfo& info) const;
|
||||
virtual void debugDump() const;
|
||||
|
||||
void updateShapeType(ShapeType type);
|
||||
virtual ShapeType getShapeType() const { return _shapeType; }
|
||||
|
||||
// TODO: Move these to subclasses, or other appropriate abstraction
|
||||
// getters/setters applicable to models and particles
|
||||
|
@ -126,6 +127,7 @@ protected:
|
|||
AnimationLoop _animationLoop;
|
||||
QString _animationSettings;
|
||||
QString _textures;
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
|
||||
// used on client side
|
||||
bool _jointMappingCompleted;
|
||||
|
|
|
@ -94,19 +94,6 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi
|
|||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||
}
|
||||
|
||||
void SphereEntityItem::recalculateCollisionShape() {
|
||||
_sphereShape.setTranslation(getCenterInMeters());
|
||||
glm::vec3 dimensionsInMeters = getDimensionsInMeters();
|
||||
float largestDiameter = glm::max(dimensionsInMeters.x, dimensionsInMeters.y, dimensionsInMeters.z);
|
||||
_sphereShape.setRadius(largestDiameter / 2.0f);
|
||||
}
|
||||
|
||||
void SphereEntityItem::computeShapeInfo(ShapeInfo& info) const {
|
||||
glm::vec3 halfExtents = 0.5f * getDimensionsInMeters();
|
||||
// TODO: support ellipsoid shapes
|
||||
info.setSphere(halfExtents.x);
|
||||
}
|
||||
|
||||
bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#ifndef hifi_SphereEntityItem_h
|
||||
#define hifi_SphereEntityItem_h
|
||||
|
||||
#include <SphereShape.h>
|
||||
#include "EntityItem.h"
|
||||
|
||||
class SphereEntityItem : public EntityItem {
|
||||
|
@ -51,12 +50,10 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
virtual const Shape& getCollisionShapeInMeters() const { return _sphereShape; }
|
||||
|
||||
// TODO: implement proper contains for 3D ellipsoid
|
||||
//virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
void computeShapeInfo(ShapeInfo& info) const;
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; }
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
|
@ -66,10 +63,8 @@ public:
|
|||
virtual void debugDump() const;
|
||||
|
||||
protected:
|
||||
virtual void recalculateCollisionShape();
|
||||
|
||||
rgbColor _color;
|
||||
SphereShape _sphereShape;
|
||||
};
|
||||
|
||||
#endif // hifi_SphereEntityItem_h
|
||||
|
|
|
@ -44,7 +44,6 @@ void TextEntityItem::setDimensions(const glm::vec3& value) {
|
|||
// NOTE: Text Entities always have a "depth" of 1cm.
|
||||
float fixedDepth = 0.01f / (float)TREE_SCALE;
|
||||
_dimensions = glm::vec3(value.x, value.y, fixedDepth);
|
||||
recalculateCollisionShape();
|
||||
}
|
||||
|
||||
EntityItemProperties TextEntityItem::getProperties() const {
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <GeometryUtil.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OctalCode.h>
|
||||
#include <Shape.h>
|
||||
|
||||
#include "FBXReader.h"
|
||||
|
||||
|
@ -1950,7 +1951,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
|||
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
||||
joint.name = model.name;
|
||||
joint.shapePosition = glm::vec3(0.0f);
|
||||
joint.shapeType = SHAPE_TYPE_UNKNOWN;
|
||||
joint.shapeType = INVALID_SHAPE;
|
||||
|
||||
foreach (const QString& childID, childMap.values(modelID)) {
|
||||
QString type = typeFlags.value(childID);
|
||||
|
@ -2374,10 +2375,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
|||
if (collideLikeCapsule) {
|
||||
joint.shapeRotation = rotationBetween(defaultCapsuleAxis, jointShapeInfo.boneBegin);
|
||||
joint.shapePosition = 0.5f * jointShapeInfo.boneBegin;
|
||||
joint.shapeType = SHAPE_TYPE_CAPSULE;
|
||||
joint.shapeType = CAPSULE_SHAPE;
|
||||
} else {
|
||||
// collide the joint like a sphere
|
||||
joint.shapeType = SHAPE_TYPE_SPHERE;
|
||||
joint.shapeType = SPHERE_SHAPE;
|
||||
if (jointShapeInfo.numVertices > 0) {
|
||||
jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
|
||||
joint.shapePosition = jointShapeInfo.averageVertex;
|
||||
|
@ -2397,8 +2398,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
|
|||
if (distanceFromEnd > joint.distanceToParent && distanceFromBegin > joint.distanceToParent) {
|
||||
// The shape is further from both joint endpoints than the endpoints are from each other
|
||||
// which probably means the model has a bad transform somewhere. We disable this shape
|
||||
// by setting its type to SHAPE_TYPE_UNKNOWN.
|
||||
joint.shapeType = SHAPE_TYPE_UNKNOWN;
|
||||
// by setting its type to INVALID_SHAPE.
|
||||
joint.shapeType = INVALID_SHAPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include <Extents.h>
|
||||
#include <Transform.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <Extents.h>
|
||||
#include <Transform.h>
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
#include <model/Material.h>
|
||||
|
||||
|
@ -53,12 +54,6 @@ public:
|
|||
QVector<glm::vec3> normals;
|
||||
};
|
||||
|
||||
enum ShapeType {
|
||||
SHAPE_TYPE_SPHERE = 0,
|
||||
SHAPE_TYPE_CAPSULE = 1,
|
||||
SHAPE_TYPE_UNKNOWN = 2
|
||||
};
|
||||
|
||||
/// A single joint (transformation node) extracted from an FBX document.
|
||||
class FBXJoint {
|
||||
public:
|
||||
|
@ -83,7 +78,7 @@ public:
|
|||
QString name;
|
||||
glm::vec3 shapePosition; // in joint frame
|
||||
glm::quat shapeRotation; // in joint frame
|
||||
ShapeType shapeType;
|
||||
quint8 shapeType;
|
||||
bool isSkeletonJoint;
|
||||
};
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
return VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME;
|
||||
return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE;
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
|
|
@ -127,6 +127,7 @@ const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
|
|||
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
|
||||
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Shape.h>
|
||||
#include <ShapeCollider.h>
|
||||
|
||||
#include "CoverageMap.h"
|
||||
#include "OctreeConstants.h"
|
||||
|
@ -856,26 +855,6 @@ bool findCapsulePenetrationOp(OctreeElement* element, void* extraData) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool findShapeCollisionsOp(OctreeElement* element, void* extraData) {
|
||||
ShapeArgs* args = static_cast<ShapeArgs*>(extraData);
|
||||
// coarse check against bounds
|
||||
AACube cube = element->getAACube();
|
||||
cube.scale(TREE_SCALE);
|
||||
if (!cube.expandedContains(args->shape->getTranslation(), args->shape->getBoundingRadius())) {
|
||||
return false;
|
||||
}
|
||||
if (element->hasContent()) {
|
||||
if (element->findShapeCollisions(args->shape, args->collisions)) {
|
||||
args->found = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!element->isLeaf()) {
|
||||
return true; // recurse on children
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint qHash(const glm::vec3& point) {
|
||||
// NOTE: TREE_SCALE = 16384 (15 bits) and multiplier is 1024 (11 bits),
|
||||
// so each component (26 bits) uses more than its alloted 21 bits.
|
||||
|
@ -947,37 +926,6 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end
|
|||
return args.found;
|
||||
}
|
||||
|
||||
bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions,
|
||||
Octree::lockType lockType, bool* accurateResult) {
|
||||
|
||||
ShapeArgs args = { shape, collisions, false };
|
||||
|
||||
bool gotLock = false;
|
||||
if (lockType == Octree::Lock) {
|
||||
lockForRead();
|
||||
gotLock = true;
|
||||
} else if (lockType == Octree::TryLock) {
|
||||
gotLock = tryLockForRead();
|
||||
if (!gotLock) {
|
||||
if (accurateResult) {
|
||||
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
|
||||
}
|
||||
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
|
||||
}
|
||||
}
|
||||
|
||||
recurseTreeWithOperation(findShapeCollisionsOp, &args);
|
||||
|
||||
if (gotLock) {
|
||||
unlock();
|
||||
}
|
||||
|
||||
if (accurateResult) {
|
||||
*accurateResult = true; // if user asked to accuracy or result, let them know this is accurate
|
||||
}
|
||||
return args.found;
|
||||
}
|
||||
|
||||
bool Octree::findContentInCube(const AACube& cube, CubeList& cubes) {
|
||||
if (!tryLockForRead()) {
|
||||
return false;
|
||||
|
|
|
@ -308,9 +308,6 @@ public:
|
|||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
||||
bool findShapeCollisions(const Shape* shape, CollisionList& collisions,
|
||||
Octree::lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
||||
bool findContentInCube(const AACube& cube, CubeList& cubes);
|
||||
|
||||
OctreeElement* getElementEnclosingPoint(const glm::vec3& point,
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
#include <AACubeShape.h>
|
||||
#include <ShapeCollider.h>
|
||||
|
||||
#include "AACube.h"
|
||||
#include "OctalCode.h"
|
||||
|
@ -1396,12 +1395,6 @@ bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
|||
return _cube.findSpherePenetration(center, radius, penetration);
|
||||
}
|
||||
|
||||
bool OctreeElement::findShapeCollisions(const Shape* shape, CollisionList& collisions) const {
|
||||
AACube cube = getAACube();
|
||||
cube.scale(TREE_SCALE);
|
||||
return ShapeCollider::collideShapeWithAACubeLegacy(shape, cube.calcCenter(), cube.getScale(), collisions);
|
||||
}
|
||||
|
||||
// TODO: consider removing this, or switching to using getOrCreateChildElementContaining(const AACube& box)...
|
||||
OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float z, float s) {
|
||||
OctreeElement* child = NULL;
|
||||
|
|
|
@ -128,8 +128,6 @@ public:
|
|||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
||||
virtual bool findShapeCollisions(const Shape* shape, CollisionList& collisions) const;
|
||||
|
||||
// Base class methods you don't need to implement
|
||||
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }
|
||||
OctreeElement* getChildAtIndex(int childIndex) const;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <Shape.h> // for FOO_SHAPE types
|
||||
#include <SharedUtil.h> // for MILLIMETERS_PER_METER
|
||||
|
||||
#include "ShapeInfoUtil.h"
|
||||
|
@ -18,36 +17,30 @@
|
|||
int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
||||
int bulletShapeType = INVALID_SHAPE_PROXYTYPE;
|
||||
switch(shapeInfoType) {
|
||||
case BOX_SHAPE:
|
||||
case SHAPE_TYPE_BOX:
|
||||
bulletShapeType = BOX_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SPHERE_SHAPE:
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
bulletShapeType = SPHERE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case CAPSULE_SHAPE:
|
||||
case SHAPE_TYPE_CAPSULE_Y:
|
||||
bulletShapeType = CAPSULE_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case CYLINDER_SHAPE:
|
||||
bulletShapeType = CYLINDER_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
return bulletShapeType;
|
||||
}
|
||||
|
||||
int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
||||
int shapeInfoType = INVALID_SHAPE;
|
||||
int shapeInfoType = SHAPE_TYPE_NONE;
|
||||
switch(bulletShapeType) {
|
||||
case BOX_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = BOX_SHAPE;
|
||||
shapeInfoType = SHAPE_TYPE_BOX;
|
||||
break;
|
||||
case SPHERE_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SPHERE_SHAPE;
|
||||
shapeInfoType = SHAPE_TYPE_SPHERE;
|
||||
break;
|
||||
case CAPSULE_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = CAPSULE_SHAPE;
|
||||
break;
|
||||
case CYLINDER_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = CYLINDER_SHAPE;
|
||||
shapeInfoType = SHAPE_TYPE_CAPSULE_Y;
|
||||
break;
|
||||
}
|
||||
return shapeInfoType;
|
||||
|
@ -57,29 +50,16 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
|||
if (shape) {
|
||||
int type = ShapeInfoUtil::fromBulletShapeType(shape->getShapeType());
|
||||
switch(type) {
|
||||
case BOX_SHAPE: {
|
||||
case SHAPE_TYPE_BOX: {
|
||||
const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
|
||||
info.setBox(bulletToGLM(boxShape->getHalfExtentsWithMargin()));
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE: {
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
|
||||
info.setSphere(sphereShape->getRadius());
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE: {
|
||||
// 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 CAPSULE_SHAPE: {
|
||||
// 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,77 +71,23 @@ 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 BOX_SHAPE: {
|
||||
// data[0] is halfExtents
|
||||
shape = new btBoxShape(glmToBullet(data[0]));
|
||||
case SHAPE_TYPE_BOX: {
|
||||
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));
|
||||
}
|
||||
break;
|
||||
case SPHERE_SHAPE: {
|
||||
float radius = data[0].z;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
float radius = info.getHalfExtents().x;
|
||||
shape = new btSphereShape(radius);
|
||||
}
|
||||
break;
|
||||
case CYLINDER_SHAPE: {
|
||||
// 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 CAPSULE_SHAPE: {
|
||||
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;
|
||||
}
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include "DoubleHashKey.h"
|
||||
|
||||
// translates between ShapeInfo and btShape
|
||||
|
||||
namespace ShapeInfoUtil {
|
||||
|
@ -26,8 +24,6 @@ namespace ShapeInfoUtil {
|
|||
|
||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
|
||||
DoubleHashKey computeHash(const ShapeInfo& info);
|
||||
|
||||
// TODO? just use bullet shape types everywhere?
|
||||
int toBulletShapeType(int shapeInfoType);
|
||||
int fromBulletShapeType(int bulletShapeType);
|
||||
|
|
|
@ -27,14 +27,17 @@ ShapeManager::~ShapeManager() {
|
|||
}
|
||||
|
||||
btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||
if (info.getType() == SHAPE_TYPE_NONE) {
|
||||
return NULL;
|
||||
}
|
||||
// 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 +54,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 +98,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);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// DoubleHashKey.h
|
||||
// libraries/physcis/src
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.11.02
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -12,27 +12,38 @@
|
|||
#ifndef hifi_DoubleHashKey_h
|
||||
#define hifi_DoubleHashKey_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// DoubleHashKey for use with btHashMap
|
||||
class DoubleHashKey {
|
||||
public:
|
||||
static unsigned int hashFunction(unsigned int value, int primeIndex);
|
||||
static unsigned int hashFunction2(unsigned int value);
|
||||
static uint32_t hashFunction(uint32_t value, uint32_t primeIndex);
|
||||
static uint32_t hashFunction2(uint32_t value);
|
||||
|
||||
DoubleHashKey() : _hash(0), _hash2(0) { }
|
||||
|
||||
DoubleHashKey(unsigned int value, int primeIndex = 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;
|
||||
}
|
||||
|
||||
unsigned int getHash() const { return (unsigned int)_hash; }
|
||||
void computeHash(uint32_t value, uint32_t primeIndex = 0);
|
||||
uint32_t getHash() const { return _hash; }
|
||||
uint32_t getHash2() const { return _hash2; }
|
||||
|
||||
int _hash;
|
||||
int _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,78 +13,82 @@
|
|||
|
||||
#include "SharedUtil.h" // for MILLIMETERS_PER_METER
|
||||
|
||||
//#include "DoubleHashKey.h"
|
||||
#include "ShapeInfo.h"
|
||||
|
||||
void ShapeInfo::clear() {
|
||||
_type = INVALID_SHAPE;
|
||||
_data.clear();
|
||||
_type = SHAPE_TYPE_NONE;
|
||||
_halfExtents = glm::vec3(0.0f);
|
||||
_doubleHashKey.clear();
|
||||
_externalData = NULL;
|
||||
}
|
||||
|
||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QVector<glm::vec3>* data) {
|
||||
_type = type;
|
||||
switch(type) {
|
||||
case SHAPE_TYPE_NONE:
|
||||
_halfExtents = glm::vec3(0.0f);
|
||||
break;
|
||||
case SHAPE_TYPE_BOX:
|
||||
_halfExtents = halfExtents;
|
||||
break;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
// sphere radius is max of halfExtents
|
||||
float radius = glm::max(glm::max(halfExtents.x, halfExtents.y), halfExtents.z);
|
||||
_halfExtents = glm::vec3(radius);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
_halfExtents = halfExtents;
|
||||
}
|
||||
_externalData = data;
|
||||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
_type = BOX_SHAPE;
|
||||
_data.clear();
|
||||
// _data[0] = < halfX, halfY, halfZ >
|
||||
_data.push_back(halfExtents);
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
_halfExtents = halfExtents;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
_type = SPHERE_SHAPE;
|
||||
_data.clear();
|
||||
// _data[0] = < radius, radius, radius >
|
||||
_data.push_back(glm::vec3(radius));
|
||||
_type = SHAPE_TYPE_SPHERE;
|
||||
_halfExtents = glm::vec3(radius, radius, radius);
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCylinder(float radius, float halfHeight) {
|
||||
_type = CYLINDER_SHAPE;
|
||||
_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 = CAPSULE_SHAPE;
|
||||
_data.clear();
|
||||
// _data[0] = < radius, halfHeight, radius >
|
||||
_data.push_back(glm::vec3(radius, halfHeight, radius));
|
||||
}
|
||||
|
||||
glm::vec3 ShapeInfo::getBoundingBoxDiagonal() const {
|
||||
switch(_type) {
|
||||
case BOX_SHAPE:
|
||||
case SPHERE_SHAPE:
|
||||
case CYLINDER_SHAPE:
|
||||
case CAPSULE_SHAPE:
|
||||
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 {
|
||||
const float DEFAULT_VOLUME = 1.0f;
|
||||
float volume = DEFAULT_VOLUME;
|
||||
switch(_type) {
|
||||
case BOX_SHAPE: {
|
||||
// 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;
|
||||
case SHAPE_TYPE_BOX: {
|
||||
// factor of 8.0 because the components of _halfExtents are all halfExtents
|
||||
volume = 8.0f * _halfExtents.x * _halfExtents.y * _halfExtents.z;
|
||||
break;
|
||||
}
|
||||
case SPHERE_SHAPE: {
|
||||
float radius = _data[0].x;
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = 4.0f * PI * radius * radius * radius / 3.0f;
|
||||
break;
|
||||
}
|
||||
case CYLINDER_SHAPE: {
|
||||
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 CAPSULE_SHAPE: {
|
||||
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 +97,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,28 +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_HULL,
|
||||
SHAPE_TYPE_PLANE,
|
||||
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(INVALID_SHAPE) {}
|
||||
|
||||
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
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
void ShapeInfoTests::testHashFunctions() {
|
||||
int maxTests = 10000000;
|
||||
ShapeInfo info;
|
||||
btHashMap<btHashInt, int> hashes;
|
||||
btHashMap<btHashInt, uint32_t> hashes;
|
||||
|
||||
int bits[32];
|
||||
unsigned int masks[32];
|
||||
uint32_t bits[32];
|
||||
uint32_t masks[32];
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
bits[i] = 0;
|
||||
masks[i] = 1U << i;
|
||||
|
@ -45,26 +45,27 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
// test sphere
|
||||
info.setSphere(radiusX);
|
||||
++testCount;
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
int* hashPtr = hashes.find(key._hash);
|
||||
if (hashPtr && *hashPtr == key._hash2) {
|
||||
DoubleHashKey key = info.getHash();
|
||||
uint32_t* hashPtr = hashes.find(key.getHash());
|
||||
if (hashPtr && *hashPtr == key.getHash2()) {
|
||||
std::cout << testCount << " hash collision radiusX = " << radiusX
|
||||
<< " h1 = 0x" << std::hex << (unsigned int)(key._hash)
|
||||
<< " h2 = 0x" << std::hex << (unsigned int)(key._hash2)
|
||||
<< " h1 = 0x" << std::hex << key.getHash()
|
||||
<< " h2 = 0x" << std::hex << key.getHash2()
|
||||
<< std::endl;
|
||||
++numCollisions;
|
||||
assert(false);
|
||||
} else {
|
||||
hashes.insert(key._hash, key._hash2);
|
||||
hashes.insert(key.getHash(), key.getHash2());
|
||||
}
|
||||
for (int k = 0; k < 32; ++k) {
|
||||
if (masks[k] & key._hash2) {
|
||||
if (masks[k] & key.getHash2()) {
|
||||
++bits[k];
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 1; y < numSteps && testCount < maxTests; ++y) {
|
||||
float radiusY = (float)y * deltaLength;
|
||||
/* TODO: reimplement Cylinder and Capsule shapes
|
||||
// test cylinder and capsule
|
||||
int types[] = { CYLINDER_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
|
@ -74,58 +75,59 @@ void ShapeInfoTests::testHashFunctions() {
|
|||
break;
|
||||
}
|
||||
case CAPSULE_SHAPE_PROXYTYPE: {
|
||||
info.setCapsule(radiusX, radiusY);
|
||||
info.setCapsuleY(radiusX, radiusY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++testCount;
|
||||
key = ShapeInfoUtil::computeHash(info);
|
||||
hashPtr = hashes.find(key._hash);
|
||||
if (hashPtr && *hashPtr == key._hash2) {
|
||||
key = info.getHash();
|
||||
hashPtr = hashes.find(key.getHash());
|
||||
if (hashPtr && *hashPtr == key.getHash2()) {
|
||||
std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY
|
||||
<< " h1 = 0x" << std::hex << (unsigned int)(key._hash)
|
||||
<< " h2 = 0x" << std::hex << (unsigned int)(key._hash2)
|
||||
<< " h1 = 0x" << std::hex << key.getHash()
|
||||
<< " h2 = 0x" << std::hex << key.getHash2()
|
||||
<< std::endl;
|
||||
++numCollisions;
|
||||
assert(false);
|
||||
} else {
|
||||
hashes.insert(key._hash, key._hash2);
|
||||
hashes.insert(key.getHash(), key.getHash2());
|
||||
}
|
||||
for (int k = 0; k < 32; ++k) {
|
||||
if (masks[k] & key._hash2) {
|
||||
if (masks[k] & key.getHash2()) {
|
||||
++bits[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for (int z = 1; z < numSteps && testCount < maxTests; ++z) {
|
||||
float radiusZ = (float)z * deltaLength;
|
||||
// test box
|
||||
info.setBox(glm::vec3(radiusX, radiusY, radiusZ));
|
||||
++testCount;
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
hashPtr = hashes.find(key._hash);
|
||||
if (hashPtr && *hashPtr == key._hash2) {
|
||||
DoubleHashKey key = info.getHash();
|
||||
hashPtr = hashes.find(key.getHash());
|
||||
if (hashPtr && *hashPtr == key.getHash2()) {
|
||||
std::cout << testCount << " hash collision radiusX = " << radiusX
|
||||
<< " radiusY = " << radiusY << " radiusZ = " << radiusZ
|
||||
<< " h1 = 0x" << std::hex << (unsigned int)(key._hash)
|
||||
<< " h2 = 0x" << std::hex << (unsigned int)(key._hash2)
|
||||
<< " h1 = 0x" << std::hex << key.getHash()
|
||||
<< " h2 = 0x" << std::hex << key.getHash2()
|
||||
<< std::endl;
|
||||
++numCollisions;
|
||||
assert(false);
|
||||
} else {
|
||||
hashes.insert(key._hash, key._hash2);
|
||||
hashes.insert(key.getHash(), key.getHash2());
|
||||
}
|
||||
for (int k = 0; k < 32; ++k) {
|
||||
if (masks[k] & key._hash2) {
|
||||
if (masks[k] & key.getHash2()) {
|
||||
++bits[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned long int msec = timer.getTimeMilliseconds();
|
||||
uint64_t msec = timer.getTimeMilliseconds();
|
||||
std::cout << msec << " msec with " << numCollisions << " collisions out of " << testCount << " hashes" << std::endl;
|
||||
|
||||
// print out distribution of bits
|
||||
|
@ -138,7 +140,7 @@ void ShapeInfoTests::testBoxShape() {
|
|||
ShapeInfo info;
|
||||
glm::vec3 halfExtents(1.23f, 4.56f, 7.89f);
|
||||
info.setBox(halfExtents);
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
if (!shape) {
|
||||
|
@ -148,15 +150,15 @@ void ShapeInfoTests::testBoxShape() {
|
|||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo);
|
||||
if (key._hash != otherKey._hash) {
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Box shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl;
|
||||
<< " ERROR: expected Box shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
|
||||
if (key._hash2 != otherKey._hash2) {
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Box shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl;
|
||||
<< " ERROR: expected Box shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
|
||||
delete shape;
|
||||
|
@ -166,74 +168,78 @@ void ShapeInfoTests::testSphereShape() {
|
|||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
info.setSphere(radius);
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo);
|
||||
if (key._hash != otherKey._hash) {
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Sphere shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl;
|
||||
<< " ERROR: expected Sphere shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key._hash2 != otherKey._hash2) {
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Sphere shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl;
|
||||
<< " ERROR: expected Sphere shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
|
||||
delete shape;
|
||||
}
|
||||
|
||||
void ShapeInfoTests::testCylinderShape() {
|
||||
/* TODO: reimplement Cylinder shape
|
||||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
info.setCylinder(radius, height);
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo);
|
||||
if (key._hash != otherKey._hash) {
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Cylinder shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl;
|
||||
<< " ERROR: expected Cylinder shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key._hash2 != otherKey._hash2) {
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Cylinder shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl;
|
||||
<< " ERROR: expected Cylinder shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeInfoTests::testCapsuleShape() {
|
||||
/* TODO: reimplement Capsule shape
|
||||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
info.setCapsule(radius, height);
|
||||
DoubleHashKey key = ShapeInfoUtil::computeHash(info);
|
||||
DoubleHashKey key = info.getHash();
|
||||
|
||||
btCollisionShape* shape = ShapeInfoUtil::createShapeFromInfo(info);
|
||||
|
||||
ShapeInfo otherInfo;
|
||||
ShapeInfoUtil::collectInfoFromShape(shape, otherInfo);
|
||||
|
||||
DoubleHashKey otherKey = ShapeInfoUtil::computeHash(otherInfo);
|
||||
if (key._hash != otherKey._hash) {
|
||||
DoubleHashKey otherKey = otherInfo.getHash();
|
||||
if (key.getHash() != otherKey.getHash()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Capsule shape hash = " << key._hash << " but found hash = " << otherKey._hash << std::endl;
|
||||
<< " ERROR: expected Capsule shape hash = " << key.getHash() << " but found hash = " << otherKey.getHash() << std::endl;
|
||||
}
|
||||
if (key._hash2 != otherKey._hash2) {
|
||||
if (key.getHash2() != otherKey.getHash2()) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: expected Capsule shape hash2 = " << key._hash2 << " but found hash2 = " << otherKey._hash2 << std::endl;
|
||||
<< " ERROR: expected Capsule shape hash2 = " << key.getHash2() << " but found hash2 = " << otherKey.getHash2() << std::endl;
|
||||
}
|
||||
|
||||
delete shape;
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeInfoTests::runAllTests() {
|
||||
|
|
|
@ -188,6 +188,7 @@ void ShapeManagerTests::addSphereShape() {
|
|||
}
|
||||
|
||||
void ShapeManagerTests::addCylinderShape() {
|
||||
/* TODO: reimplement Cylinder shape
|
||||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
|
@ -204,9 +205,11 @@ void ShapeManagerTests::addCylinderShape() {
|
|||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Cylinder ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeManagerTests::addCapsuleShape() {
|
||||
/* TODO: reimplement Capsule shape
|
||||
ShapeInfo info;
|
||||
float radius = 1.23f;
|
||||
float height = 4.56f;
|
||||
|
@ -223,6 +226,7 @@ void ShapeManagerTests::addCapsuleShape() {
|
|||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: Capsule ShapeInfo --> shape --> ShapeInfo --> shape did not work" << std::endl;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ShapeManagerTests::runAllTests() {
|
||||
|
|
Loading…
Reference in a new issue