Merge branch 'physics-lock-entity-tree' of github.com:sethalves/hifi into actions-over-wire

This commit is contained in:
Seth Alves 2015-06-26 07:20:51 -07:00
commit f5f1d0829c
7 changed files with 160 additions and 52 deletions

View file

@ -891,8 +891,11 @@ void Application::paintGL() {
glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH);
Menu::getInstance()->setIsOptionChecked("First Person", _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
Application::getInstance()->cameraMenuChanged(); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
Application::getInstance()->cameraMenuChanged();
}
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
// Always use the default eye position, not the actual head eye position. // Always use the default eye position, not the actual head eye position.
@ -1384,11 +1387,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (isShifted) { if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::Mirror); Menu::getInstance()->triggerOption(MenuOption::Mirror);
} else { } else {
Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror));
if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
}
cameraMenuChanged();
} }
break; break;
case Qt::Key_P: case Qt::Key_P:
Menu::getInstance()->triggerOption(MenuOption::FirstPerson); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson));
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson));
cameraMenuChanged();
break; break;
case Qt::Key_Slash: case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::Stats); Menu::getInstance()->triggerOption(MenuOption::Stats);
@ -2351,13 +2360,17 @@ void Application::cameraMenuChanged() {
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
_myAvatar->setBoomLength(MyAvatar::ZOOM_MIN); _myAvatar->setBoomLength(MyAvatar::ZOOM_MIN);
} }
} else { } else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) {
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) { if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) {
_myAvatar->setBoomLength(MyAvatar::ZOOM_DEFAULT); _myAvatar->setBoomLength(MyAvatar::ZOOM_DEFAULT);
} }
} }
} else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) {
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
_myCamera.setMode(CAMERA_MODE_INDEPENDENT);
}
} }
} }
@ -2451,20 +2464,22 @@ void Application::update(float deltaTime) {
// Transfer the user inputs to the driveKeys // Transfer the user inputs to the driveKeys
_myAvatar->clearDriveKeys(); _myAvatar->clearDriveKeys();
if (!_controllerScriptingInterface.areActionsCaptured()) { if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD)); if (!_controllerScriptingInterface.areActionsCaptured()) {
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD)); _myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP)); _myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN)); _myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT)); _myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT)); _myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP)); _myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN)); _myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT)); _myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT)); _myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
}
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
} }
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
@ -2481,24 +2496,45 @@ void Application::update(float deltaTime) {
_entitySimulation.lock(); _entitySimulation.lock();
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete()); _physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete());
_entitySimulation.unlock();
_entities.getTree()->lockForWrite();
_entitySimulation.lock();
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
_entitySimulation.unlock();
_entities.getTree()->unlock();
_entities.getTree()->lockForWrite();
_entitySimulation.lock();
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
_entitySimulation.unlock();
_entities.getTree()->unlock();
_entitySimulation.lock();
_entitySimulation.applyActionChanges(); _entitySimulation.applyActionChanges();
_entitySimulation.unlock(); _entitySimulation.unlock();
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data(); AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete()); _physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
_physicsEngine.addObjects(avatarManager->getObjectsToAdd()); _physicsEngine.addObjects(avatarManager->getObjectsToAdd());
_physicsEngine.changeObjects(avatarManager->getObjectsToChange()); _physicsEngine.changeObjects(avatarManager->getObjectsToChange());
_entities.getTree()->lockForWrite();
_physicsEngine.stepSimulation(); _physicsEngine.stepSimulation();
_entities.getTree()->unlock();
if (_physicsEngine.hasOutgoingChanges()) { if (_physicsEngine.hasOutgoingChanges()) {
_entities.getTree()->lockForWrite();
_entitySimulation.lock(); _entitySimulation.lock();
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID()); _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
_entitySimulation.unlock(); _entitySimulation.unlock();
_entities.getTree()->unlock();
_entities.getTree()->lockForWrite();
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
_entities.getTree()->unlock();
auto collisionEvents = _physicsEngine.getCollisionEvents(); auto collisionEvents = _physicsEngine.getCollisionEvents();
avatarManager->handleCollisionEvents(collisionEvents); avatarManager->handleCollisionEvents(collisionEvents);

View file

@ -444,6 +444,8 @@ public slots:
void notifyPacketVersionMismatch(); void notifyPacketVersionMismatch();
void domainConnectionDenied(const QString& reason); void domainConnectionDenied(const QString& reason);
void cameraMenuChanged();
private slots: private slots:
void clearDomainOctreeDetails(); void clearDomainOctreeDetails();
@ -460,7 +462,7 @@ private slots:
void setFullscreen(bool fullscreen); void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode); void setEnable3DTVMode(bool enable3DTVMode);
void setEnableVRMode(bool enableVRMode); void setEnableVRMode(bool enableVRMode);
void cameraMenuChanged();
void rotationModeChanged(); void rotationModeChanged();
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);

View file

@ -87,24 +87,26 @@ PickRay Camera::computePickRay(float x, float y) {
void Camera::setModeString(const QString& mode) { void Camera::setModeString(const QString& mode) {
CameraMode targetMode = stringToMode(mode); CameraMode targetMode = stringToMode(mode);
switch (targetMode) { switch (targetMode) {
case CAMERA_MODE_FIRST_PERSON:
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
break;
case CAMERA_MODE_THIRD_PERSON: case CAMERA_MODE_THIRD_PERSON:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
break; break;
case CAMERA_MODE_MIRROR: case CAMERA_MODE_MIRROR:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
break; break;
case CAMERA_MODE_INDEPENDENT: case CAMERA_MODE_INDEPENDENT:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false); Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
break; break;
default: default:
break; break;
} }
qApp->cameraMenuChanged();
if (_mode != targetMode) { if (_mode != targetMode) {
setMode(targetMode); setMode(targetMode);
} }

View file

@ -268,9 +268,22 @@ Menu::Menu() {
qApp, qApp,
SLOT(setFullscreen(bool))); SLOT(setFullscreen(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode");
0, // QML Qt::Key_P, QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu);
true, qApp, SLOT(cameraMenuChanged())); cameraModeGroup->setExclusive(true);
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::FirstPerson, 0, // QML Qt:: Key_P
false, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::ThirdPerson, 0,
true, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::IndependentMode, 0,
false, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::FullscreenMirror, 0, // QML Qt::Key_H,
false, qApp, SLOT(cameraMenuChanged())));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
0, //QML Qt::SHIFT | Qt::Key_H, 0, //QML Qt::SHIFT | Qt::Key_H,
true); true);

View file

@ -158,6 +158,7 @@ namespace MenuOption {
const QString CascadedShadows = "Cascaded"; const QString CascadedShadows = "Cascaded";
const QString CachesSize = "RAM Caches Size"; const QString CachesSize = "RAM Caches Size";
const QString CalibrateCamera = "Calibrate Camera"; const QString CalibrateCamera = "Calibrate Camera";
const QString CenterPlayerInView = "Center Player In View";
const QString Chat = "Chat..."; const QString Chat = "Chat...";
const QString Collisions = "Collisions"; const QString Collisions = "Collisions";
const QString Console = "Console..."; const QString Console = "Console...";
@ -199,11 +200,10 @@ namespace MenuOption {
const QString FrameTimer = "Show Timer"; const QString FrameTimer = "Show Timer";
const QString Fullscreen = "Fullscreen"; const QString Fullscreen = "Fullscreen";
const QString FullscreenMirror = "Fullscreen Mirror"; const QString FullscreenMirror = "Fullscreen Mirror";
const QString CenterPlayerInView = "Center Player In View";
const QString GlowWhenSpeaking = "Glow When Speaking"; const QString GlowWhenSpeaking = "Glow When Speaking";
const QString NamesAboveHeads = "Names Above Heads";
const QString HMDTools = "HMD Tools"; const QString HMDTools = "HMD Tools";
const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File..."; const QString LoadScript = "Open and Run Script File...";
@ -217,6 +217,7 @@ namespace MenuOption {
const QString MuteAudio = "Mute Microphone"; const QString MuteAudio = "Mute Microphone";
const QString MuteEnvironment = "Mute Environment"; const QString MuteEnvironment = "Mute Environment";
const QString MuteFaceTracking = "Mute Face Tracking"; const QString MuteFaceTracking = "Mute Face Tracking";
const QString NamesAboveHeads = "Names Above Heads";
const QString NoFaceTracking = "None"; const QString NoFaceTracking = "None";
const QString OctreeStats = "Entity Statistics"; const QString OctreeStats = "Entity Statistics";
const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString OnlyDisplayTopTen = "Only Display Top Ten";
@ -277,6 +278,7 @@ namespace MenuOption {
const QString StopAllScripts = "Stop All Scripts"; const QString StopAllScripts = "Stop All Scripts";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString TestPing = "Test Ping"; const QString TestPing = "Test Ping";
const QString ThirdPerson = "Third Person";
const QString ToolWindow = "Tool Window"; const QString ToolWindow = "Tool Window";
const QString TransmitterDrive = "Transmitter Drive"; const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head"; const QString TurnWithHead = "Turn using Head";

View file

@ -19,10 +19,42 @@
#include "PhysicsHelpers.h" #include "PhysicsHelpers.h"
#include "PhysicsLogging.h" #include "PhysicsLogging.h"
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
#include "EntityTree.h"
#endif
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4; static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
bool EntityMotionState::entityTreeIsLocked() const {
EntityTreeElement* element = _entity ? _entity->getElement() : nullptr;
EntityTree* tree = element ? element->getTree() : nullptr;
if (tree) {
bool readSuccess = tree->tryLockForRead();
if (readSuccess) {
tree->unlock();
}
bool writeSuccess = tree->tryLockForWrite();
if (writeSuccess) {
tree->unlock();
}
if (readSuccess && writeSuccess) {
return false; // if we can take either kind of lock, there was no tree lock.
}
return true; // either read or write failed, so there is some lock in place.
} else {
return true;
}
}
#else
bool entityTreeIsLocked() {
return true;
}
#endif
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) :
ObjectMotionState(shape), ObjectMotionState(shape),
_entity(entity), _entity(entity),
@ -46,6 +78,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
{ {
_type = MOTIONSTATE_TYPE_ENTITY; _type = MOTIONSTATE_TYPE_ENTITY;
assert(_entity != nullptr); assert(_entity != nullptr);
assert(entityTreeIsLocked());
setMass(_entity->computeMass()); setMass(_entity->computeMass());
} }
@ -55,6 +88,7 @@ EntityMotionState::~EntityMotionState() {
} }
void EntityMotionState::updateServerPhysicsVariables() { void EntityMotionState::updateServerPhysicsVariables() {
assert(entityTreeIsLocked());
_serverPosition = _entity->getPosition(); _serverPosition = _entity->getPosition();
_serverRotation = _entity->getRotation(); _serverRotation = _entity->getRotation();
_serverVelocity = _entity->getVelocity(); _serverVelocity = _entity->getVelocity();
@ -64,6 +98,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
// virtual // virtual
void EntityMotionState::handleEasyChanges(uint32_t flags) { void EntityMotionState::handleEasyChanges(uint32_t flags) {
assert(entityTreeIsLocked());
updateServerPhysicsVariables(); updateServerPhysicsVariables();
ObjectMotionState::handleEasyChanges(flags); ObjectMotionState::handleEasyChanges(flags);
if (flags & EntityItem::DIRTY_SIMULATOR_ID) { if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
@ -105,6 +140,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
if (!_entity) { if (!_entity) {
return MOTION_TYPE_STATIC; return MOTION_TYPE_STATIC;
} }
assert(entityTreeIsLocked());
if (_entity->getCollisionsWillMove()) { if (_entity->getCollisionsWillMove()) {
return MOTION_TYPE_DYNAMIC; return MOTION_TYPE_DYNAMIC;
} }
@ -112,6 +148,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
} }
bool EntityMotionState::isMoving() const { bool EntityMotionState::isMoving() const {
assert(entityTreeIsLocked());
return _entity && _entity->isMoving(); return _entity && _entity->isMoving();
} }
@ -124,6 +161,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
if (!_entity) { if (!_entity) {
return; return;
} }
assert(entityTreeIsLocked());
if (_motionType == MOTION_TYPE_KINEMATIC) { if (_motionType == MOTION_TYPE_KINEMATIC) {
// This is physical kinematic motion which steps strictly by the subframe count // This is physical kinematic motion which steps strictly by the subframe count
// of the physics simulation. // of the physics simulation.
@ -144,6 +182,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
if (!_entity) { if (!_entity) {
return; return;
} }
assert(entityTreeIsLocked());
measureBodyAcceleration(); measureBodyAcceleration();
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
_entity->setRotation(bulletToGLM(worldTrans.getRotation())); _entity->setRotation(bulletToGLM(worldTrans.getRotation()));
@ -168,9 +207,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID();
qCDebug(physics) << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; qCDebug(physics) << " last edited:" << _entity->getLastEdited()
qCDebug(physics) << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; << formatUsecTime(now - _entity->getLastEdited()) << "ago";
qCDebug(physics) << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; qCDebug(physics) << " last simulated:" << _entity->getLastSimulated()
<< formatUsecTime(now - _entity->getLastSimulated()) << "ago";
qCDebug(physics) << " last updated:" << _entity->getLastUpdated()
<< formatUsecTime(now - _entity->getLastUpdated()) << "ago";
#endif #endif
} }
@ -178,16 +220,18 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
btCollisionShape* EntityMotionState::computeNewShape() { btCollisionShape* EntityMotionState::computeNewShape() {
if (_entity) { if (_entity) {
ShapeInfo shapeInfo; ShapeInfo shapeInfo;
assert(entityTreeIsLocked());
_entity->computeShapeInfo(shapeInfo); _entity->computeShapeInfo(shapeInfo);
return getShapeManager()->getShape(shapeInfo); return getShapeManager()->getShape(shapeInfo);
} }
return nullptr; return nullptr;
} }
bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
if (!_body || !_entity) { if (!_body || !_entity) {
return false; return false;
} }
assert(entityTreeIsLocked());
return _candidateForOwnership || sessionID == _entity->getSimulatorID(); return _candidateForOwnership || sessionID == _entity->getSimulatorID();
} }
@ -204,7 +248,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
_sentActive = false; _sentActive = false;
return false; return false;
} }
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
glm::vec3 wasPosition = _serverPosition; glm::vec3 wasPosition = _serverPosition;
glm::quat wasRotation = _serverRotation; glm::quat wasRotation = _serverRotation;
@ -217,7 +261,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
const float INACTIVE_UPDATE_PERIOD = 0.5f; const float INACTIVE_UPDATE_PERIOD = 0.5f;
if (!_sentActive) { if (!_sentActive) {
// we resend the inactive update every INACTIVE_UPDATE_PERIOD // we resend the inactive update every INACTIVE_UPDATE_PERIOD
// until it is removed from the outgoing updates // until it is removed from the outgoing updates
// (which happens when we don't own the simulation and it isn't touching our simulation) // (which happens when we don't own the simulation and it isn't touching our simulation)
return (dt > INACTIVE_UPDATE_PERIOD); return (dt > INACTIVE_UPDATE_PERIOD);
} }
@ -235,10 +279,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
_serverPosition += dt * _serverVelocity; _serverPosition += dt * _serverVelocity;
} }
// Else we measure the error between current and extrapolated transform (according to expected behavior // Else we measure the error between current and extrapolated transform (according to expected behavior
// of remote EntitySimulation) and return true if the error is significant. // of remote EntitySimulation) and return true if the error is significant.
// NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame // NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame
// due to _worldOffset. // due to _worldOffset.
// TODO: compensate for _worldOffset offset here // TODO: compensate for _worldOffset offset here
@ -246,7 +290,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
btTransform worldTrans = _body->getWorldTransform(); btTransform worldTrans = _body->getWorldTransform();
glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); glm::vec3 position = bulletToGLM(worldTrans.getOrigin());
float dx2 = glm::distance2(position, _serverPosition); float dx2 = glm::distance2(position, _serverPosition);
const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters
@ -262,13 +306,13 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true; return true;
} }
if (glm::length2(_serverAngularVelocity) > 0.0f) { if (glm::length2(_serverAngularVelocity) > 0.0f) {
// compute rotation error // compute rotation error
float attenuation = powf(1.0f - _body->getAngularDamping(), dt); float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
_serverAngularVelocity *= attenuation; _serverAngularVelocity *= attenuation;
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore // Bullet caps the effective rotation velocity inside its rotation integration step, therefore
// we must integrate with the same algorithm and timestep in order achieve similar results. // we must integrate with the same algorithm and timestep in order achieve similar results.
for (int i = 0; i < numSteps; ++i) { for (int i = 0; i < numSteps; ++i) {
_serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation); _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
@ -280,7 +324,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) {
qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ...."; qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ....";
qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity; qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity;
qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity; qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity;
@ -297,10 +341,11 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
} }
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID) { bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID) {
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called // NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL. // after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
assert(_entity); assert(_entity);
assert(_body); assert(_body);
assert(entityTreeIsLocked());
if (!remoteSimulationOutOfSync(simulationStep)) { if (!remoteSimulationOutOfSync(simulationStep)) {
_candidateForOwnership = false; _candidateForOwnership = false;
@ -330,6 +375,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) { void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
assert(_entity); assert(_entity);
assert(entityTreeIsLocked());
bool active = _body->isActive(); bool active = _body->isActive();
if (!active) { if (!active) {
@ -439,17 +485,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
_lastStep = step; _lastStep = step;
} }
uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
assert(entityTreeIsLocked());
uint32_t dirtyFlags = 0; uint32_t dirtyFlags = 0;
if (_body && _entity) { if (_body && _entity) {
dirtyFlags = _entity->getDirtyFlags(); dirtyFlags = _entity->getDirtyFlags();
_entity->clearDirtyFlags(); _entity->clearDirtyFlags();
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
int bodyFlags = _body->getCollisionFlags(); int bodyFlags = _body->getCollisionFlags();
bool isMoving = _entity->isMoving(); bool isMoving = _entity->isMoving();
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
} }
} }
return dirtyFlags; return dirtyFlags;
@ -459,6 +506,7 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
// virtual // virtual
QUuid EntityMotionState::getSimulatorID() const { QUuid EntityMotionState::getSimulatorID() const {
if (_entity) { if (_entity) {
assert(entityTreeIsLocked());
return _entity->getSimulatorID(); return _entity->getSimulatorID();
} }
return QUuid(); return QUuid();
@ -473,12 +521,12 @@ void EntityMotionState::bump() {
void EntityMotionState::resetMeasuredBodyAcceleration() { void EntityMotionState::resetMeasuredBodyAcceleration() {
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); _lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
if (_body) { if (_body) {
_lastVelocity = bulletToGLM(_body->getLinearVelocity()); _lastVelocity = bulletToGLM(_body->getLinearVelocity());
} else { } else {
_lastVelocity = glm::vec3(0.0f); _lastVelocity = glm::vec3(0.0f);
} }
_measuredAcceleration = glm::vec3(0.0f); _measuredAcceleration = glm::vec3(0.0f);
} }
void EntityMotionState::measureBodyAcceleration() { void EntityMotionState::measureBodyAcceleration() {
// try to manually measure the true acceleration of the object // try to manually measure the true acceleration of the object
@ -508,7 +556,7 @@ glm::vec3 EntityMotionState::getObjectLinearVelocityChange() const {
return _measuredAcceleration * _measuredDeltaTime; return _measuredAcceleration * _measuredDeltaTime;
} }
// virtual // virtual
void EntityMotionState::setMotionType(MotionType motionType) { void EntityMotionState::setMotionType(MotionType motionType) {
ObjectMotionState::setMotionType(motionType); ObjectMotionState::setMotionType(motionType);
resetMeasuredBodyAcceleration(); resetMeasuredBodyAcceleration();
@ -518,12 +566,13 @@ void EntityMotionState::setMotionType(MotionType motionType) {
// virtual // virtual
QString EntityMotionState::getName() { QString EntityMotionState::getName() {
if (_entity) { if (_entity) {
assert(entityTreeIsLocked());
return _entity->getName(); return _entity->getName();
} }
return ""; return "";
} }
// virtual // virtual
int16_t EntityMotionState::computeCollisionGroup() { int16_t EntityMotionState::computeCollisionGroup() {
switch (computeObjectMotionType()){ switch (computeObjectMotionType()){
case MOTION_TYPE_STATIC: case MOTION_TYPE_STATIC:

View file

@ -83,6 +83,10 @@ public:
friend class PhysicalEntitySimulation; friend class PhysicalEntitySimulation;
protected: protected:
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
bool entityTreeIsLocked() const;
#endif
virtual btCollisionShape* computeNewShape(); virtual btCollisionShape* computeNewShape();
virtual void clearObjectBackPointer(); virtual void clearObjectBackPointer();
virtual void setMotionType(MotionType motionType); virtual void setMotionType(MotionType motionType);