From 824c219fa015219c751353b80b17b5e1f308919b Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Tue, 23 Jun 2015 09:26:38 -0700 Subject: [PATCH 1/6] started fixing camera mode issue --- interface/src/Application.cpp | 23 ++++++++++++++++++----- interface/src/Application.h | 3 ++- interface/src/Camera.cpp | 12 +++++++----- interface/src/Menu.cpp | 22 ++++++++++++++++------ interface/src/Menu.h | 2 ++ 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ba6c86cafb..68e8360f3e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -889,8 +889,11 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); - Menu::getInstance()->setIsOptionChecked("First Person", _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Application::getInstance()->cameraMenuChanged(); + if (!(Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode) || Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror))); { + 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) { // Always use the default eye position, not the actual head eye position. @@ -1380,11 +1383,17 @@ void Application::keyPressEvent(QKeyEvent* event) { if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Mirror); } 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; 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; case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); @@ -2411,13 +2420,17 @@ void Application::cameraMenuChanged() { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myAvatar->setBoomLength(MyAvatar::ZOOM_MIN); } - } else { + } else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) { if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) { _myAvatar->setBoomLength(MyAvatar::ZOOM_DEFAULT); } } + } else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) { + if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { + _myCamera.setMode(CAMERA_MODE_INDEPENDENT); + } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index c9e5bea76e..dba0eb0a64 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -433,6 +433,8 @@ public slots: void notifyPacketVersionMismatch(); void domainConnectionDenied(const QString& reason); + + void cameraMenuChanged(); private slots: void clearDomainOctreeDetails(); @@ -449,7 +451,6 @@ private slots: void setFullscreen(bool fullscreen); void setEnable3DTVMode(bool enable3DTVMode); void setEnableVRMode(bool enableVRMode); - void cameraMenuChanged(); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index e501b91dea..7257f10ddd 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -105,22 +105,24 @@ void Camera::setModeString(const QString& mode) { CameraMode targetMode = stringToMode(mode); switch (targetMode) { + case CAMERA_MODE_FIRST_PERSON: + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); + break; case CAMERA_MODE_THIRD_PERSON: - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false); - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); break; case CAMERA_MODE_MIRROR: Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); break; case CAMERA_MODE_INDEPENDENT: - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false); - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); + Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true); break; default: break; } + Application::getInstance()->cameraMenuChanged(); + if (_mode != targetMode) { setMode(targetMode); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 216f733709..b7a77c559a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -268,15 +268,25 @@ Menu::Menu() { qApp, SLOT(setFullscreen(bool))); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, - 0, // QML Qt::Key_P, - true, qApp, SLOT(cameraMenuChanged())); + MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode"); + QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu); + 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, 0, //QML Qt::SHIFT | Qt::Key_H, true); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, - 0, // QML Qt::Key_H, - false, qApp, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, #ifdef Q_OS_MAC diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b892ebc3c..c44bcba5fa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -195,6 +195,8 @@ namespace MenuOption { const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; const QString FirstPerson = "First Person"; + const QString ThirdPerson = "Third Person"; + const QString IndependentMode = "Independent Mode"; const QString Forward = "Forward"; const QString FrameTimer = "Show Timer"; const QString Fullscreen = "Fullscreen"; From 778e19ac117c7e24ac3a2ac20fad927d77ff5de2 Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Tue, 23 Jun 2015 11:45:08 -0700 Subject: [PATCH 2/6] fixed camera mode issue --- interface/src/Application.cpp | 2 +- interface/src/Camera.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 68e8360f3e..30e4a138d0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -889,7 +889,7 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); - if (!(Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode) || Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror))); { + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); Application::getInstance()->cameraMenuChanged(); diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 7257f10ddd..c7eba213e6 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -103,7 +103,7 @@ PickRay Camera::computePickRay(float x, float y) { void Camera::setModeString(const QString& mode) { CameraMode targetMode = stringToMode(mode); - + switch (targetMode) { case CAMERA_MODE_FIRST_PERSON: Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); @@ -121,7 +121,7 @@ void Camera::setModeString(const QString& mode) { break; } - Application::getInstance()->cameraMenuChanged(); + qApp->cameraMenuChanged(); if (_mode != targetMode) { setMode(targetMode); From 56944afd39e8c865e5934bc62cd44a47a9de7008 Mon Sep 17 00:00:00 2001 From: Sam Gondelman Date: Thu, 25 Jun 2015 12:36:36 -0700 Subject: [PATCH 3/6] avatar doesn't move in independent mode, alphabetized menu options --- interface/src/Application.cpp | 28 +++++++++++++++------------- interface/src/Menu.h | 8 ++++---- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8a9cf74bd0..a6b2a71c40 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2464,20 +2464,22 @@ void Application::update(float deltaTime) { // Transfer the user inputs to the driveKeys _myAvatar->clearDriveKeys(); - if (!_controllerScriptingInterface.areActionsCaptured()) { - _myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD)); - _myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD)); - _myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP)); - _myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN)); - _myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT)); - _myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT)); - _myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP)); - _myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN)); - _myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT)); - _myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT)); + if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { + if (!_controllerScriptingInterface.areActionsCaptured()) { + _myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD)); + _myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD)); + _myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP)); + _myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN)); + _myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT)); + _myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT)); + _myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP)); + _myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN)); + _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... diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b9b09bc3f0..0097437107 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -158,6 +158,7 @@ namespace MenuOption { const QString CascadedShadows = "Cascaded"; const QString CachesSize = "RAM Caches Size"; const QString CalibrateCamera = "Calibrate Camera"; + const QString CenterPlayerInView = "Center Player In View"; const QString Chat = "Chat..."; const QString Collisions = "Collisions"; const QString Console = "Console..."; @@ -195,17 +196,14 @@ namespace MenuOption { const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; const QString FirstPerson = "First Person"; - const QString ThirdPerson = "Third Person"; - const QString IndependentMode = "Independent Mode"; const QString Forward = "Forward"; const QString FrameTimer = "Show Timer"; const QString Fullscreen = "Fullscreen"; const QString FullscreenMirror = "Fullscreen Mirror"; - const QString CenterPlayerInView = "Center Player In View"; const QString GlowWhenSpeaking = "Glow When Speaking"; - const QString NamesAboveHeads = "Names Above Heads"; const QString HMDTools = "HMD Tools"; const QString IncreaseAvatarSize = "Increase Avatar Size"; + const QString IndependentMode = "Independent Mode"; const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; @@ -219,6 +217,7 @@ namespace MenuOption { const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString MuteFaceTracking = "Mute Face Tracking"; + const QString NamesAboveHeads = "Names Above Heads"; const QString NoFaceTracking = "None"; const QString OctreeStats = "Entity Statistics"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; @@ -279,6 +278,7 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; + const QString ThirdPerson = "Third Person"; const QString ToolWindow = "Tool Window"; const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; From a0d77c061cdb4875f604c314c3b3d9a01db7255f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Jun 2015 07:00:28 -0700 Subject: [PATCH 4/6] lock the entity tree during physics operations that access then entity tree. if the simulation and entity-tree are both going to be locked, be sure to lock the entity tree first (and unlock it last), because this is what the network-reading thread does --- interface/src/Application.cpp | 21 +++++ libraries/physics/src/EntityMotionState.cpp | 92 ++++++++++++++++----- libraries/physics/src/EntityMotionState.h | 4 + 3 files changed, 95 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8a572d2d41..d9c5589631 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2496,24 +2496,45 @@ void Application::update(float deltaTime) { _entitySimulation.lock(); _physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete()); + _entitySimulation.unlock(); + + _entities.getTree()->lockForWrite(); + _entitySimulation.lock(); _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); + _entitySimulation.unlock(); + _entities.getTree()->unlock(); + + _entities.getTree()->lockForWrite(); + _entitySimulation.lock(); _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); + _entitySimulation.unlock(); + _entities.getTree()->unlock(); + + _entitySimulation.lock(); _entitySimulation.applyActionChanges(); _entitySimulation.unlock(); + AvatarManager* avatarManager = DependencyManager::get().data(); _physicsEngine.deleteObjects(avatarManager->getObjectsToDelete()); _physicsEngine.addObjects(avatarManager->getObjectsToAdd()); _physicsEngine.changeObjects(avatarManager->getObjectsToChange()); + _entities.getTree()->lockForWrite(); _physicsEngine.stepSimulation(); + _entities.getTree()->unlock(); if (_physicsEngine.hasOutgoingChanges()) { + _entities.getTree()->lockForWrite(); _entitySimulation.lock(); _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID()); _entitySimulation.unlock(); + _entities.getTree()->unlock(); + _entities.getTree()->lockForWrite(); avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); + _entities.getTree()->unlock(); + auto collisionEvents = _physicsEngine.getCollisionEvents(); avatarManager->handleCollisionEvents(collisionEvents); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index eeb9d5ca10..2ca996e2a5 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -19,6 +19,10 @@ #include "PhysicsHelpers.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 quint8 STEPS_TO_DECIDE_BALLISTIC = 4; @@ -42,6 +46,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer { _type = MOTIONSTATE_TYPE_ENTITY; assert(_entity != nullptr); + assert(entityTreeIsLocked()); setMass(_entity->computeMass()); } @@ -50,7 +55,35 @@ EntityMotionState::~EntityMotionState() { assert(!_entity); } +#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 EntityMotionState::entityTreeIsLocked() const { + return true; +} +#endif + void EntityMotionState::updateServerPhysicsVariables() { + assert(entityTreeIsLocked()); _serverPosition = _entity->getPosition(); _serverRotation = _entity->getRotation(); _serverVelocity = _entity->getVelocity(); @@ -60,6 +93,7 @@ void EntityMotionState::updateServerPhysicsVariables() { // virtual void EntityMotionState::handleEasyChanges(uint32_t flags) { + assert(entityTreeIsLocked()); updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); if (flags & EntityItem::DIRTY_SIMULATOR_ID) { @@ -101,6 +135,7 @@ MotionType EntityMotionState::computeObjectMotionType() const { if (!_entity) { return MOTION_TYPE_STATIC; } + assert(entityTreeIsLocked()); if (_entity->getCollisionsWillMove()) { return MOTION_TYPE_DYNAMIC; } @@ -108,6 +143,7 @@ MotionType EntityMotionState::computeObjectMotionType() const { } bool EntityMotionState::isMoving() const { + assert(entityTreeIsLocked()); return _entity && _entity->isMoving(); } @@ -120,6 +156,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { if (!_entity) { return; } + assert(entityTreeIsLocked()); if (_motionType == MOTION_TYPE_KINEMATIC) { // This is physical kinematic motion which steps strictly by the subframe count // of the physics simulation. @@ -140,6 +177,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (!_entity) { return; } + assert(entityTreeIsLocked()); measureBodyAcceleration(); _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset()); _entity->setRotation(bulletToGLM(worldTrans.getRotation())); @@ -164,9 +202,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { #ifdef WANT_DEBUG quint64 now = usecTimestampNow(); qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); - qCDebug(physics) << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; - qCDebug(physics) << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; - qCDebug(physics) << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; + qCDebug(physics) << " last edited:" << _entity->getLastEdited() + << formatUsecTime(now - _entity->getLastEdited()) << "ago"; + qCDebug(physics) << " last simulated:" << _entity->getLastSimulated() + << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; + qCDebug(physics) << " last updated:" << _entity->getLastUpdated() + << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; #endif } @@ -174,16 +215,18 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { btCollisionShape* EntityMotionState::computeNewShape() { if (_entity) { ShapeInfo shapeInfo; + assert(entityTreeIsLocked()); _entity->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); } return nullptr; } -bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { +bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const { if (!_body || !_entity) { return false; } + assert(entityTreeIsLocked()); return _candidateForOwnership || sessionID == _entity->getSimulatorID(); } @@ -200,7 +243,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _sentActive = false; return false; } - + #ifdef WANT_DEBUG glm::vec3 wasPosition = _serverPosition; glm::quat wasRotation = _serverRotation; @@ -213,7 +256,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { const float INACTIVE_UPDATE_PERIOD = 0.5f; if (!_sentActive) { // 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) return (dt > INACTIVE_UPDATE_PERIOD); } @@ -231,10 +274,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _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. - // 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. // TODO: compensate for _worldOffset offset here @@ -242,7 +285,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { btTransform worldTrans = _body->getWorldTransform(); glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); - + float dx2 = glm::distance2(position, _serverPosition); const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters @@ -258,13 +301,13 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { return true; } - + if (glm::length2(_serverAngularVelocity) > 0.0f) { // compute rotation error float attenuation = powf(1.0f - _body->getAngularDamping(), dt); _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. for (int i = 0; i < numSteps; ++i) { _serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation); @@ -276,7 +319,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { #ifdef WANT_DEBUG if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ...."; - + qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity; qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity; @@ -293,10 +336,11 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } 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 - // after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL. + // 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. assert(_entity); assert(_body); + assert(entityTreeIsLocked()); if (!remoteSimulationOutOfSync(simulationStep)) { _candidateForOwnership = false; @@ -326,6 +370,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) { assert(_entity); + assert(entityTreeIsLocked()); bool active = _body->isActive(); if (!active) { @@ -435,17 +480,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _lastStep = step; } -uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { +uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { + assert(entityTreeIsLocked()); uint32_t dirtyFlags = 0; if (_body && _entity) { - dirtyFlags = _entity->getDirtyFlags(); + dirtyFlags = _entity->getDirtyFlags(); _entity->clearDirtyFlags(); // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { - dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } return dirtyFlags; @@ -455,6 +501,7 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() { // virtual QUuid EntityMotionState::getSimulatorID() const { if (_entity) { + assert(entityTreeIsLocked()); return _entity->getSimulatorID(); } return QUuid(); @@ -469,12 +516,12 @@ void EntityMotionState::bump() { void EntityMotionState::resetMeasuredBodyAcceleration() { _lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); if (_body) { - _lastVelocity = bulletToGLM(_body->getLinearVelocity()); + _lastVelocity = bulletToGLM(_body->getLinearVelocity()); } else { _lastVelocity = glm::vec3(0.0f); } _measuredAcceleration = glm::vec3(0.0f); -} +} void EntityMotionState::measureBodyAcceleration() { // try to manually measure the true acceleration of the object @@ -504,7 +551,7 @@ glm::vec3 EntityMotionState::getObjectLinearVelocityChange() const { return _measuredAcceleration * _measuredDeltaTime; } -// virtual +// virtual void EntityMotionState::setMotionType(MotionType motionType) { ObjectMotionState::setMotionType(motionType); resetMeasuredBodyAcceleration(); @@ -514,12 +561,13 @@ void EntityMotionState::setMotionType(MotionType motionType) { // virtual QString EntityMotionState::getName() { if (_entity) { + assert(entityTreeIsLocked()); return _entity->getName(); } return ""; } -// virtual +// virtual int16_t EntityMotionState::computeCollisionGroup() { switch (computeObjectMotionType()){ case MOTION_TYPE_STATIC: diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2d732f8ee0..4f777a4575 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -83,6 +83,10 @@ public: friend class PhysicalEntitySimulation; protected: + #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS + bool entityTreeIsLocked() const; + #endif + virtual btCollisionShape* computeNewShape(); virtual void clearObjectBackPointer(); virtual void setMotionType(MotionType motionType); From 2682c4720d4bf048a09c4bf9340281fcf432d4a2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Jun 2015 07:04:10 -0700 Subject: [PATCH 5/6] fix alt-branch of ifdef --- libraries/physics/src/EntityMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 2ca996e2a5..0dad876349 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -77,7 +77,7 @@ bool EntityMotionState::entityTreeIsLocked() const { } } #else -bool EntityMotionState::entityTreeIsLocked() const { +bool entityTreeIsLocked() { return true; } #endif From 015498a6e0281bd2ef9d43161745feb19b6aea46 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 26 Jun 2015 07:20:22 -0700 Subject: [PATCH 6/6] move function up so this builds in non-debug mode --- libraries/physics/src/EntityMotionState.cpp | 55 +++++++++++---------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 0dad876349..5e9591a031 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -27,6 +27,34 @@ static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f; 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) : ObjectMotionState(shape), _entity(entity), @@ -55,33 +83,6 @@ EntityMotionState::~EntityMotionState() { assert(!_entity); } -#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 - void EntityMotionState::updateServerPhysicsVariables() { assert(entityTreeIsLocked()); _serverPosition = _entity->getPosition();