mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 10:53:34 +02:00
route more entity updates into physics engine
This commit is contained in:
parent
eda779b434
commit
ec1f11c1a8
13 changed files with 290 additions and 147 deletions
|
@ -50,7 +50,9 @@ void EntityCollisionSystem::update() {
|
|||
if (_entities->tryLockForRead()) {
|
||||
QList<EntityItem*>& movingEntities = _entities->getMovingEntities();
|
||||
foreach (EntityItem* entity, movingEntities) {
|
||||
checkEntity(entity);
|
||||
if (!entity->getMotionState()) {
|
||||
checkEntity(entity);
|
||||
}
|
||||
}
|
||||
_entities->unlock();
|
||||
}
|
||||
|
|
|
@ -91,9 +91,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) {
|
|||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_lastUpdated = 0;
|
||||
_created = 0;
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
_motionState = NULL;
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
_updateFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
|
@ -107,9 +105,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
|
|||
_lastEditedFromRemoteInRemoteTime = 0;
|
||||
_lastUpdated = 0;
|
||||
_created = properties.getCreated();
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
_motionState = NULL;
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
_updateFlags = 0;
|
||||
_changedOnServer = 0;
|
||||
initFromEntityItemID(entityItemID);
|
||||
|
@ -118,11 +114,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
|
|||
}
|
||||
|
||||
EntityItem::~EntityItem() {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// Make sure the EntityItem has been removed from the physics engine AND
|
||||
// that its _motionState has been destroyed BEFORE you get here.
|
||||
assert(_motionState == NULL);
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
|
@ -519,7 +513,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
READ_ENTITY_PROPERTY_SETTER(PROP_GRAVITY, glm::vec3, updateGravity);
|
||||
READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping);
|
||||
READ_ENTITY_PROPERTY_SETTER(PROP_LIFETIME, float, updateLifetime);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT, updateScript);
|
||||
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint);
|
||||
READ_ENTITY_PROPERTY_SETTER(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
|
||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping);
|
||||
|
@ -797,23 +791,23 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
|
|||
}
|
||||
}
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters); // this will call recalculate collision shape if needed
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocityInMeters);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePositionInMeters); // this will call recalculate collision shape if needed
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensionsInMeters); // NOTE: radius is obsolete
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, updateMass);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocityInMeters);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravityInMeters);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, updateScript);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
|
||||
|
||||
|
@ -985,7 +979,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
|
|||
if (_dimensions != value) {
|
||||
_dimensions = value;
|
||||
recalculateCollisionShape();
|
||||
_updateFlags |= EntityItem::UPDATE_SHAPE;
|
||||
_updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,7 +988,7 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) {
|
|||
if (_dimensions != dimensions) {
|
||||
_dimensions = dimensions;
|
||||
recalculateCollisionShape();
|
||||
_updateFlags |= EntityItem::UPDATE_SHAPE;
|
||||
_updateFlags |= (EntityItem::UPDATE_SHAPE | EntityItem::UPDATE_MASS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1025,7 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) {
|
|||
void EntityItem::updateGravity(const glm::vec3& value) {
|
||||
if (_gravity != value) {
|
||||
_gravity = value;
|
||||
_updateFlags |= EntityItem::UPDATE_VELOCITY;
|
||||
_updateFlags |= EntityItem::UPDATE_GRAVITY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1039,7 +1033,7 @@ void EntityItem::updateGravityInMeters(const glm::vec3& value) {
|
|||
glm::vec3 gravity = value / (float) TREE_SCALE;
|
||||
if (_gravity != gravity) {
|
||||
_gravity = gravity;
|
||||
_updateFlags |= EntityItem::UPDATE_VELOCITY;
|
||||
_updateFlags |= EntityItem::UPDATE_GRAVITY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1071,12 +1065,17 @@ void EntityItem::updateLifetime(float value) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
void EntityItem::updateScript(const QString& value) {
|
||||
if (_script != value) {
|
||||
_script = value;
|
||||
_updateFlags |= EntityItem::UPDATE_SCRIPT;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::destroyMotionState() {
|
||||
if (_motionState) {
|
||||
delete _motionState;
|
||||
_motionState = NULL;
|
||||
}
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <VoxelDetail.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
|
@ -35,9 +36,7 @@ class EntityTreeElementExtraEncodeData;
|
|||
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
||||
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
class EntityMotionState;
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
/// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
|
||||
/// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
|
||||
|
@ -46,14 +45,21 @@ class EntityItem {
|
|||
|
||||
public:
|
||||
enum EntityUpdateFlags {
|
||||
UPDATE_POSITION = 0x0001,
|
||||
UPDATE_VELOCITY = 0x0002,
|
||||
UPDATE_MASS = 0x0004,
|
||||
UPDATE_COLLISION_GROUP = 0x0008,
|
||||
UPDATE_MOTION_TYPE = 0x0010,
|
||||
UPDATE_SHAPE = 0x0020,
|
||||
UPDATE_LIFETIME = 0x0040
|
||||
//UPDATE_APPEARANCE = 0x8000,
|
||||
// flags for things that need to be relayed to physics engine
|
||||
UPDATE_POSITION = PHYSICS_UPDATE_POSITION, //0x0001,
|
||||
UPDATE_VELOCITY = PHYSICS_UPDATE_VELOCITY, //0x0002,
|
||||
UPDATE_GRAVITY = PHYSICS_UPDATE_GRAVITY, //0x0004,
|
||||
UPDATE_MASS = PHYSICS_UPDATE_MASS, //0x0008,
|
||||
UPDATE_COLLISION_GROUP = PHYSICS_UPDATE_COLLISION_GROUP, //0x0010,
|
||||
UPDATE_MOTION_TYPE = PHYSICS_UPDATE_MOTION_TYPE, //0x0020,
|
||||
UPDATE_SHAPE = PHYSICS_UPDATE_SHAPE, //0x0040,
|
||||
//...
|
||||
// add new flags here in the middle
|
||||
//...
|
||||
// non-physics stuff
|
||||
UPDATE_SCRIPT = 0x2000,
|
||||
UPDATE_LIFETIME = 0x4000,
|
||||
UPDATE_APPEARANCE = 0x8000
|
||||
};
|
||||
|
||||
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
|
||||
|
@ -292,19 +298,18 @@ public:
|
|||
void updateIgnoreForCollisions(bool value);
|
||||
void updateCollisionsWillMove(bool value);
|
||||
void updateLifetime(float value);
|
||||
void updateScript(const QString& value);
|
||||
|
||||
uint32_t getUpdateFlags() const { return _updateFlags; }
|
||||
void clearUpdateFlags() { _updateFlags = 0; }
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
EntityMotionState* getMotionState() const { return _motionState; }
|
||||
virtual EntityMotionState* createMotionState() { return NULL; }
|
||||
void destroyMotionState();
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
SimulationState getSimulationState() const { return _simulationState; }
|
||||
|
||||
protected:
|
||||
friend class EntityTree;
|
||||
void clearUpdateFlags() { _updateFlags = 0; }
|
||||
void setSimulationState(SimulationState state) { _simulationState = state; }
|
||||
|
||||
virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init
|
||||
|
@ -348,9 +353,7 @@ protected:
|
|||
void setRadius(float value);
|
||||
|
||||
AACubeShape _collisionShape;
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
EntityMotionState* _motionState;
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
SimulationState _simulationState; // only set by EntityTree
|
||||
|
||||
// UpdateFlags are set whenever a property changes that requires the change to be communicated to other
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
#include <BulletUtil.h>
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "EntityMotionState.h"
|
||||
|
@ -41,9 +42,10 @@ MotionType EntityMotionState::getMotionType() const {
|
|||
// HACK: According to EntityTree the meaning of "static" is "not moving" whereas
|
||||
// to Bullet it means "can't move". For demo purposes we temporarily interpret
|
||||
// Entity::weightless to mean Bullet::static.
|
||||
return _entity->hasGravity() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC;
|
||||
return _entity->getCollisionsWillMove() ? MOTION_TYPE_DYNAMIC : MOTION_TYPE_STATIC;
|
||||
}
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// This callback is invoked by the physics simulation in two cases:
|
||||
// (1) when the RigidBody is first added to the world
|
||||
// (irregardless of MotionType: STATIC, DYNAMIC, or KINEMATIC)
|
||||
|
@ -64,34 +66,54 @@ void EntityMotionState::getWorldTransform (btTransform &worldTrans) const {
|
|||
// This callback is invoked by the physics simulation at the end of each simulation frame...
|
||||
// iff the corresponding RigidBody is DYNAMIC and has moved.
|
||||
void EntityMotionState::setWorldTransform (const btTransform &worldTrans) {
|
||||
glm::vec3 pos;
|
||||
bulletToGLM(worldTrans.getOrigin(), pos);
|
||||
_entity->setPositionInMeters(pos + _cachedWorldOffset);
|
||||
uint32_t updateFlags = _entity->getUpdateFlags();
|
||||
if (! (updateFlags & PHYSICS_UPDATE_POSITION)) {
|
||||
glm::vec3 pos;
|
||||
bulletToGLM(worldTrans.getOrigin(), pos);
|
||||
_entity->setPositionInMeters(pos + _cachedWorldOffset);
|
||||
|
||||
glm::quat rot;
|
||||
bulletToGLM(worldTrans.getRotation(), rot);
|
||||
_entity->setRotation(rot);
|
||||
}
|
||||
|
||||
glm::quat rot;
|
||||
bulletToGLM(worldTrans.getRotation(), rot);
|
||||
_entity->setRotation(rot);
|
||||
|
||||
glm::vec3 v;
|
||||
getVelocity(v);
|
||||
_entity->setVelocityInMeters(v);
|
||||
getAngularVelocity(v);
|
||||
_entity->setAngularVelocity(v);
|
||||
if (! (updateFlags & PHYSICS_UPDATE_VELOCITY)) {
|
||||
glm::vec3 v;
|
||||
getVelocity(v);
|
||||
_entity->setVelocityInMeters(v);
|
||||
getAngularVelocity(v);
|
||||
_entity->setAngularVelocity(v);
|
||||
}
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
void EntityMotionState::applyVelocities() const {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
if (_body) {
|
||||
setVelocity(_entity->getVelocityInMeters());
|
||||
setAngularVelocity(_entity->getAngularVelocity());
|
||||
_body->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
void EntityMotionState::applyGravity() const {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
if (_body) {
|
||||
setGravity(_entity->getGravityInMeters());
|
||||
_body->setActivationState(ACTIVE_TAG);
|
||||
}
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
void EntityMotionState::computeShapeInfo(ShapeInfo& info) {
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
// HACK: for now we make everything a box.
|
||||
glm::vec3 halfExtents = _entity->getDimensionsInMeters();
|
||||
glm::vec3 halfExtents = 0.5f * _entity->getDimensionsInMeters();
|
||||
btVector3 bulletHalfExtents;
|
||||
glmToBullet(halfExtents, bulletHalfExtents);
|
||||
info.setBox(bulletHalfExtents);
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
}
|
||||
|
||||
void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) {
|
||||
|
@ -100,4 +122,3 @@ void EntityMotionState::getBoundingCubes(AACube& oldCube, AACube& newCube) {
|
|||
_oldBoundingCube = newCube;
|
||||
}
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -12,10 +12,16 @@
|
|||
#ifndef hifi_EntityMotionState_h
|
||||
#define hifi_EntityMotionState_h
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include <AACube.h>
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
#include <CustomMotionState.h>
|
||||
#else // USE_BULLET_PHYSICS
|
||||
// CustomMotionState stubbery
|
||||
class CustomMotionState {
|
||||
public:
|
||||
bool _foo;
|
||||
};
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
||||
class EntityItem;
|
||||
|
||||
|
@ -29,9 +35,12 @@ public:
|
|||
|
||||
MotionType getMotionType() const;
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
void getWorldTransform (btTransform &worldTrans) const;
|
||||
void setWorldTransform (const btTransform &worldTrans);
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
void applyVelocities() const;
|
||||
void applyGravity() const;
|
||||
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
|
||||
|
@ -42,5 +51,4 @@ protected:
|
|||
AACube _oldBoundingCube;
|
||||
};
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
#endif // hifi_EntityMotionState_h
|
||||
|
|
|
@ -77,12 +77,13 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons
|
|||
}
|
||||
|
||||
/// Adds a new entity item to the tree
|
||||
void EntityTree::addEntityItem(EntityItem* entity) {
|
||||
void EntityTree::addEntityInternal(EntityItem* entity) {
|
||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||
EntityItemID entityID = entity->getEntityItemID();
|
||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||
if (containingElement) {
|
||||
qDebug() << "UNEXPECTED!!!! don't call addEntityItem() on existing EntityItems. entityID=" << entityID;
|
||||
// should probably assert here
|
||||
qDebug() << "UNEXPECTED!!!! don't call addEntityInternal() on existing EntityItems. entityID=" << entityID;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -90,17 +91,39 @@ void EntityTree::addEntityItem(EntityItem* entity) {
|
|||
AddEntityOperator theOperator(this, entity);
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
|
||||
updateEntityState(entity);
|
||||
emitAddingEntity(entity);
|
||||
}
|
||||
|
||||
void EntityTree::emitAddingEntity(EntityItem* entity) {
|
||||
// add entity to proper internal lists
|
||||
EntityItem::SimulationState newState = entity->computeSimulationState();
|
||||
switch (newState) {
|
||||
case EntityItem::Moving:
|
||||
_movingEntities.push_back(entity);
|
||||
break;
|
||||
|
||||
case EntityItem::Mortal:
|
||||
_mortalEntities.push_back(entity);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
entity->setSimulationState(newState);
|
||||
entity->clearUpdateFlags();
|
||||
|
||||
// add entity to physics engine
|
||||
if (_physicsEngine && !entity->getMotionState()) {
|
||||
addEntityToPhysicsEngine(entity);
|
||||
}
|
||||
|
||||
_isDirty = true;
|
||||
|
||||
// finally emit the signal
|
||||
emit addingEntity(entity->getEntityItemID());
|
||||
}
|
||||
|
||||
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
|
||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||
if (!containingElement) {
|
||||
qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID;
|
||||
|
@ -127,20 +150,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// check to see if we need to simulate this entity...
|
||||
QString entityScriptBefore = existingEntity->getScript();
|
||||
|
||||
UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties);
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
_isDirty = true;
|
||||
|
||||
updateEntityState(existingEntity);
|
||||
|
||||
QString entityScriptAfter = existingEntity->getScript();
|
||||
if (entityScriptBefore != entityScriptAfter) {
|
||||
emitEntityScriptChanging(entityID); // the entity script has changed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
containingElement = getContainingElement(entityID);
|
||||
|
@ -177,8 +189,7 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
|
|||
|
||||
if (result) {
|
||||
// this does the actual adding of the entity
|
||||
addEntityItem(result);
|
||||
emitAddingEntity(entityID);
|
||||
addEntityInternal(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -204,14 +215,6 @@ void EntityTree::setPhysicsEngine(PhysicsEngine* engine) {
|
|||
_physicsEngine = engine;
|
||||
}
|
||||
|
||||
void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) {
|
||||
emit addingEntity(entityItemID);
|
||||
}
|
||||
|
||||
void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
|
||||
emit entityScriptChanging(entityItemID);
|
||||
}
|
||||
|
||||
void EntityTree::deleteEntity(const EntityItemID& entityID) {
|
||||
emit deletingEntity(entityID);
|
||||
|
||||
|
@ -619,13 +622,6 @@ void EntityTree::updateEntityState(EntityItem* entity) {
|
|||
break;
|
||||
}
|
||||
entity->setSimulationState(newState);
|
||||
|
||||
if (_physicsEngine) {
|
||||
EntityMotionState* motionState = entity->getMotionState();
|
||||
if (motionState) {
|
||||
_physicsEngine->updateEntityMotionType(motionState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,8 +697,15 @@ void EntityTree::updateChangedEntities(quint64 now, QSet<EntityItemID>& entities
|
|||
entitiesToDelete << thisEntity->getEntityItemID();
|
||||
clearEntityState(thisEntity);
|
||||
} else {
|
||||
// TODO: Andrew to push changes to physics engine (when we know how to sort the changes)
|
||||
uint32_t flags = thisEntity->getUpdateFlags();
|
||||
if (flags & EntityItem::UPDATE_SCRIPT) {
|
||||
emit entityScriptChanging(thisEntity->getEntityItemID());
|
||||
}
|
||||
|
||||
updateEntityState(thisEntity);
|
||||
if (_physicsEngine && thisEntity->getMotionState()) {
|
||||
_physicsEngine->updateEntity(thisEntity->getMotionState(), flags);
|
||||
}
|
||||
}
|
||||
thisEntity->clearUpdateFlags();
|
||||
}
|
||||
|
@ -742,7 +745,7 @@ void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesT
|
|||
qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds.";
|
||||
entitiesToDelete << thisEntity->getEntityItemID();
|
||||
clearEntityState(thisEntity);
|
||||
} else {
|
||||
} else if (newCube != oldCube) {
|
||||
moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube);
|
||||
updateEntityState(thisEntity);
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ public:
|
|||
|
||||
// The newer API...
|
||||
EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
void addEntityItem(EntityItem* entityItem);
|
||||
void addEntityInternal(EntityItem* entityItem);
|
||||
void emitAddingEntity(EntityItem* entityItem);
|
||||
|
||||
EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -147,9 +148,6 @@ public:
|
|||
|
||||
void trackDeletedEntity(const EntityItemID& entityID);
|
||||
|
||||
void emitAddingEntity(const EntityItemID& entityItemID);
|
||||
void emitEntityScriptChanging(const EntityItemID& entityItemID);
|
||||
|
||||
QList<EntityItem*>& getMovingEntities() { return _movingEntities; }
|
||||
|
||||
void setPhysicsEngine(PhysicsEngine* engine);
|
||||
|
|
|
@ -742,12 +742,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
|
|||
// TODO: Do we need to also do this?
|
||||
// 3) remember the old cube for the entity so we can mark it as dirty
|
||||
if (entityItem) {
|
||||
QString entityScriptBefore = entityItem->getScript();
|
||||
uint32_t oldFlags = entityItem->getUpdateFlags();
|
||||
bool bestFitBefore = bestFitEntityBounds(entityItem);
|
||||
EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID);
|
||||
|
||||
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
|
||||
if (entityItem->getUpdateFlags()) {
|
||||
if (!oldFlags && entityItem->getUpdateFlags()) {
|
||||
// this entity is not yet on the changed list and needs to be added
|
||||
_myTree->entityChanged(entityItem);
|
||||
}
|
||||
bool bestFitAfter = bestFitEntityBounds(entityItem);
|
||||
|
@ -763,21 +764,14 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString entityScriptAfter = entityItem->getScript();
|
||||
if (entityScriptBefore != entityScriptAfter) {
|
||||
_myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed
|
||||
}
|
||||
|
||||
} else {
|
||||
entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args);
|
||||
if (entityItem) {
|
||||
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
|
||||
addEntityItem(entityItem); // add this new entity to this elements entities
|
||||
_myTree->emitAddingEntity(entityItem);
|
||||
entityItemID = entityItem->getEntityItemID();
|
||||
_myTree->setContainingElement(entityItemID, this);
|
||||
_myTree->updateEntityState(entityItem);
|
||||
_myTree->emitAddingEntity(entityItemID); // we just added an entity
|
||||
}
|
||||
}
|
||||
// Move the buffer forward to read more entities
|
||||
|
|
|
@ -299,14 +299,25 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) {
|
|||
}
|
||||
|
||||
// set the entity properties and mark our element as changed.
|
||||
_existingEntity->setProperties(_properties);
|
||||
uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags();
|
||||
bool somethingChanged = _existingEntity->setProperties(_properties);
|
||||
uint32_t newUpdateFlags = _existingEntity->getUpdateFlags();
|
||||
if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) {
|
||||
// this entity hasn't yet been added to changed list
|
||||
_tree->entityChanged(_existingEntity);
|
||||
}
|
||||
if (_wantDebug) {
|
||||
qDebug() << " *** set properties ***";
|
||||
}
|
||||
} else {
|
||||
// otherwise, this is an add case.
|
||||
entityTreeElement->addEntityItem(_existingEntity);
|
||||
_existingEntity->setProperties(_properties); // still need to update the properties!
|
||||
uint32_t oldUpdateFlags = _existingEntity->getUpdateFlags();
|
||||
bool somethingChanged = _existingEntity->setProperties(_properties); // still need to update the properties!
|
||||
if (somethingChanged && !oldUpdateFlags && _existingEntity->getUpdateFlags()) {
|
||||
// this entity hasn't yet been added to changed list
|
||||
_tree->entityChanged(_existingEntity);
|
||||
}
|
||||
_tree->setContainingElement(_entityItemID, entityTreeElement);
|
||||
if (_wantDebug) {
|
||||
qDebug() << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***";
|
||||
|
|
|
@ -72,6 +72,12 @@ void CustomMotionState::setAngularVelocity(const glm::vec3& velocity) const {
|
|||
_body->setAngularVelocity(v);
|
||||
}
|
||||
|
||||
void CustomMotionState::setGravity(const glm::vec3& gravity) const {
|
||||
btVector3 g;
|
||||
glmToBullet(gravity, g);
|
||||
_body->setGravity(g);
|
||||
}
|
||||
|
||||
void CustomMotionState::getVelocity(glm::vec3& velocityOut) const {
|
||||
bulletToGLM(_body->getLinearVelocity(), velocityOut);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
//virtual void setWorldTransform (const btTransform &worldTrans);
|
||||
|
||||
virtual void applyVelocities() const = 0;
|
||||
virtual void applyGravity() const = 0;
|
||||
|
||||
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
||||
|
||||
|
@ -49,6 +50,7 @@ public:
|
|||
|
||||
void setVelocity(const glm::vec3& velocity) const;
|
||||
void setAngularVelocity(const glm::vec3& velocity) const;
|
||||
void setGravity(const glm::vec3& gravity) const;
|
||||
|
||||
void getVelocity(glm::vec3& velocityOut) const;
|
||||
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
|
||||
|
|
|
@ -32,7 +32,7 @@ void PhysicsEngine::init() {
|
|||
// NOTE: we don't care about memory leaking groundShape and groundObject -->
|
||||
// they'll exist until the executable exits.
|
||||
const float halfSide = 200.0f;
|
||||
const float halfHeight = 10.0f;
|
||||
const float halfHeight = 1.0f;
|
||||
|
||||
btCollisionShape* groundShape = new btBoxShape(btVector3(halfSide, halfHeight, halfSide));
|
||||
btTransform groundTransform;
|
||||
|
@ -40,6 +40,7 @@ void PhysicsEngine::init() {
|
|||
groundTransform.setOrigin(btVector3(halfSide, -halfHeight, halfSide));
|
||||
|
||||
btCollisionObject* groundObject = new btCollisionObject();
|
||||
groundObject->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||
groundObject->setCollisionShape(groundShape);
|
||||
groundObject->setWorldTransform(groundTransform);
|
||||
_dynamicsWorld->addCollisionObject(groundObject);
|
||||
|
@ -131,7 +132,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) {
|
|||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
float mass = 0.0f;
|
||||
btRigidBody* body = NULL;
|
||||
switch(motionState->_motionType) {
|
||||
switch(motionState->getMotionType()) {
|
||||
case MOTION_TYPE_KINEMATIC: {
|
||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
|
@ -147,6 +148,7 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) {
|
|||
body->updateInertiaTensor();
|
||||
motionState->_body = body;
|
||||
motionState->applyVelocities();
|
||||
motionState->applyGravity();
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_STATIC:
|
||||
|
@ -158,6 +160,8 @@ bool PhysicsEngine::addEntity(CustomMotionState* motionState) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
// wtf?
|
||||
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
||||
body->setRestitution(motionState->_restitution);
|
||||
body->setFriction(motionState->_friction);
|
||||
_dynamicsWorld->addRigidBody(body);
|
||||
|
@ -182,60 +186,132 @@ bool PhysicsEngine::removeEntity(CustomMotionState* motionState) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PhysicsEngine::updateEntityMotionType(CustomMotionState* motionState) {
|
||||
bool PhysicsEngine::updateEntity(CustomMotionState* motionState, uint32_t flags) {
|
||||
btRigidBody* body = motionState->_body;
|
||||
if (!body) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (flags & PHYSICS_UPDATE_HARD) {
|
||||
// a hard update requires the body be pulled out of physics engine, changed, then reinserted
|
||||
updateEntityHard(body, motionState, flags);
|
||||
} else if (flags & PHYSICS_UPDATE_EASY) {
|
||||
// an easy update does not require that the body be pulled out of physics engine
|
||||
updateEntityEasy(body, motionState, flags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// private
|
||||
void PhysicsEngine::updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) {
|
||||
MotionType newType = motionState->getMotionType();
|
||||
MotionType oldType = MOTION_TYPE_DYNAMIC;
|
||||
if (body->isStaticObject()) {
|
||||
oldType = MOTION_TYPE_STATIC;
|
||||
} else if (body->isKinematicObject()) {
|
||||
oldType = MOTION_TYPE_KINEMATIC;
|
||||
}
|
||||
MotionType newType = motionState->getMotionType();
|
||||
if (oldType != newType) {
|
||||
// pull body out of physics engine
|
||||
_dynamicsWorld->removeRigidBody(body);
|
||||
|
||||
// update various properties and flags
|
||||
switch (newType) {
|
||||
case MOTION_TYPE_KINEMATIC: {
|
||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
body->setActivationState(DISABLE_DEACTIVATION);
|
||||
body->updateInertiaTensor();
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_DYNAMIC: {
|
||||
// pull body out of physics engine
|
||||
_dynamicsWorld->removeRigidBody(body);
|
||||
|
||||
if (flags & PHYSICS_UPDATE_SHAPE) {
|
||||
btCollisionShape* oldShape = body->getCollisionShape();
|
||||
ShapeInfo info;
|
||||
motionState->computeShapeInfo(info);
|
||||
btCollisionShape* newShape = _shapeManager.getShape(info);
|
||||
if (newShape != oldShape) {
|
||||
body->setCollisionShape(newShape);
|
||||
_shapeManager.releaseShape(oldShape);
|
||||
} else {
|
||||
// whoops, shape hasn't changed after all so we must release the reference
|
||||
// that was created when looking it up
|
||||
_shapeManager.releaseShape(newShape);
|
||||
}
|
||||
// MASS bit should be set whenever SHAPE is set
|
||||
assert(flags & PHYSICS_UPDATE_MASS);
|
||||
}
|
||||
bool easyUpdate = flags & PHYSICS_UPDATE_EASY;
|
||||
if (easyUpdate) {
|
||||
updateEntityEasy(body, motionState, flags);
|
||||
}
|
||||
|
||||
// update the motion parameters
|
||||
switch (newType) {
|
||||
case MOTION_TYPE_KINEMATIC: {
|
||||
int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT;
|
||||
collisionFlags &= ~(btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->setCollisionFlags(collisionFlags);
|
||||
body->forceActivationState(DISABLE_DEACTIVATION);
|
||||
|
||||
body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f));
|
||||
body->updateInertiaTensor();
|
||||
break;
|
||||
}
|
||||
case MOTION_TYPE_DYNAMIC: {
|
||||
int collisionFlags = body->getCollisionFlags() & ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->setCollisionFlags(collisionFlags);
|
||||
if (! (flags & PHYSICS_UPDATE_MASS)) {
|
||||
// always update mass properties when going dynamic (unless it's already been done)
|
||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
float mass = motionState->getMass();
|
||||
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
body->setMassProps(mass, inertia);
|
||||
body->updateInertiaTensor();
|
||||
motionState->applyVelocities();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// MOTION_TYPE_STATIC
|
||||
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
|
||||
body->updateInertiaTensor();
|
||||
break;
|
||||
}
|
||||
bool forceActivation = true;
|
||||
body->activate(forceActivation);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// MOTION_TYPE_STATIC
|
||||
int collisionFlags = body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT;
|
||||
collisionFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
body->setCollisionFlags(collisionFlags);
|
||||
body->forceActivationState(DISABLE_SIMULATION);
|
||||
|
||||
// reinsert body into physics engine
|
||||
body->setRestitution(motionState->_restitution);
|
||||
body->setFriction(motionState->_friction);
|
||||
_dynamicsWorld->addRigidBody(body);
|
||||
return true;
|
||||
body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f));
|
||||
body->updateInertiaTensor();
|
||||
|
||||
body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// reinsert body into physics engine
|
||||
_dynamicsWorld->addRigidBody(body);
|
||||
|
||||
body->activate();
|
||||
}
|
||||
|
||||
bool PhysicsEngine::updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues) {
|
||||
// TODO: implement this
|
||||
assert(motionState);
|
||||
return false;
|
||||
}
|
||||
// private
|
||||
void PhysicsEngine::updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags) {
|
||||
if (flags & PHYSICS_UPDATE_POSITION) {
|
||||
btTransform transform;
|
||||
motionState->getWorldTransform(transform);
|
||||
body->setWorldTransform(transform);
|
||||
}
|
||||
if (flags & PHYSICS_UPDATE_VELOCITY) {
|
||||
motionState->applyVelocities();
|
||||
motionState->applyGravity();
|
||||
}
|
||||
body->setRestitution(motionState->_restitution);
|
||||
body->setFriction(motionState->_friction);
|
||||
|
||||
if (flags & PHYSICS_UPDATE_MASS) {
|
||||
float mass = motionState->getMass();
|
||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||
body->setMassProps(mass, inertia);
|
||||
body->updateInertiaTensor();
|
||||
}
|
||||
body->activate();
|
||||
|
||||
btVector3 v = body->getLinearVelocity();
|
||||
btVector3 g = body->getGravity();
|
||||
|
||||
// TODO: support collision groups
|
||||
};
|
||||
|
||||
#endif // USE_BULLET_PHYSICS
|
||||
|
|
|
@ -12,6 +12,24 @@
|
|||
#ifndef hifi_PhysicsEngine_h
|
||||
#define hifi_PhysicsEngine_h
|
||||
|
||||
enum PhysicsUpdateFlag {
|
||||
PHYSICS_UPDATE_POSITION = 0x0001,
|
||||
PHYSICS_UPDATE_VELOCITY = 0x0002,
|
||||
PHYSICS_UPDATE_GRAVITY = 0x0004,
|
||||
PHYSICS_UPDATE_MASS = 0x0008,
|
||||
PHYSICS_UPDATE_COLLISION_GROUP = 0x0010,
|
||||
PHYSICS_UPDATE_MOTION_TYPE = 0x0020,
|
||||
PHYSICS_UPDATE_SHAPE = 0x0040
|
||||
};
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// The update flags trigger two varieties of updates: "hard" which require the body to be pulled
|
||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
||||
const uint32_t PHYSICS_UPDATE_HARD = PHYSICS_UPDATE_MOTION_TYPE | PHYSICS_UPDATE_SHAPE;
|
||||
const uint32_t PHYSICS_UPDATE_EASY = PHYSICS_UPDATE_POSITION | PHYSICS_UPDATE_VELOCITY |
|
||||
PHYSICS_UPDATE_GRAVITY PHYSICS_UPDATE_MASS | PHYSICS_UPDATE_COLLISION_GROUP;
|
||||
|
||||
#ifdef USE_BULLET_PHYSICS
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
|
@ -68,12 +86,14 @@ public:
|
|||
bool removeEntity(CustomMotionState* motionState);
|
||||
|
||||
/// \param motionState pointer to Entity's MotionState
|
||||
/// \param flags set of bits indicating what categories of properties need to be updated
|
||||
/// \return true if entity updated
|
||||
bool updateEntityMotionType(CustomMotionState* motionState);
|
||||
|
||||
bool updateEntityMassProperties(CustomMotionState* motionState, float mass, const glm::vec3& inertiaEigenValues);
|
||||
bool updateEntity(CustomMotionState* motionState, uint32_t flags);
|
||||
|
||||
protected:
|
||||
void updateEntityHard(btRigidBody* body, CustomMotionState* motionState, uint32_t flags);
|
||||
void updateEntityEasy(btRigidBody* body, CustomMotionState* motionState, uint32_t flags);
|
||||
|
||||
btClock _clock;
|
||||
btDefaultCollisionConfiguration* _collisionConfig;
|
||||
btCollisionDispatcher* _collisionDispatcher;
|
||||
|
|
Loading…
Reference in a new issue