From 25a1108b612e9d78a2de8a157f37b272b3491cce Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Wed, 8 Jul 2015 16:24:23 -0700 Subject: [PATCH 01/11] Fixed spelling error --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 55cf9e9890..2046fd622d 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -493,7 +493,7 @@ void ScriptEngine::evaluate() { QScriptValue result = evaluate(_scriptContents); - // TODO: why do we check this twice? It seems like the call to clearExcpetions() in the lower level evaluate call + // TODO: why do we check this twice? It seems like the call to clearExceptions() in the lower level evaluate call // will cause this code to never actually run... if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); From 6080ec4509ae1292dc8db991fcbcf31ea262afc2 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Wed, 8 Jul 2015 16:29:43 -0700 Subject: [PATCH 02/11] Air Hockey UI now follows window border --- examples/example/games/airHockey.js | 69 ++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 22 deletions(-) mode change 100644 => 100755 examples/example/games/airHockey.js diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js old mode 100644 new mode 100755 index a703f379bc..f70fbc232f --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -83,35 +83,60 @@ var puck_name_index = 2; var light_name_index = 3; var floor_name_index = 4; +//Create Spawn and Del. Button Vars. + +function updateButtonPosition() { + Overlays.editOverlay(spawnButton, { + x: screenSize.x / 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + }); + Overlays.editOverlay(deleteButton, { + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + }); +} + +function onScriptUpdate() { + var oldScreenSize = screenSize; + + screenSize = Controller.getViewportDimensions(); + + if (screenSize.x !== oldScreenSize.x || screenSize.y !== oldScreenSize.y) { + updateButtonPosition(); + } +} + +screenSize = Controller.getViewportDimensions(); var deleteButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, - y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 }); var spawnButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 + PADDING, - y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/puck.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 + x: screenSize.x / 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/puck.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 }); +Script.update.connect(onScriptUpdate); var floor, edge1, edge2, edge3a, edge3b, edge4a, edge4b, light; From ba4049754ae7f237e3d1d2a44884abf22b8641d4 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Wed, 8 Jul 2015 16:53:55 -0700 Subject: [PATCH 03/11] Restored indentatioN --- examples/example/games/airHockey.js | 44 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index f70fbc232f..ca7f007df6 100755 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -109,31 +109,31 @@ function onScriptUpdate() { screenSize = Controller.getViewportDimensions(); var deleteButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, - y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 }); var spawnButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 + PADDING, - y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/puck.png", - color: { - red: 255, - green: 255, - blue: 255 - }, - alpha: 1 + x: screenSize.x / 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/puck.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 }); Script.update.connect(onScriptUpdate); From 1be0e7ebc32076ae496feb60cece8e265f121cdf Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 8 Jul 2015 19:25:16 -0700 Subject: [PATCH 04/11] fix for mirror rendering on windows * added preScale to Transform class. * preScale by -1 about the xAxis instead of post scale. I think this was working on Mac due to the different code paths in GLBackendTransform::updateTransform for core vs legacy gl profile. --- interface/src/Application.cpp | 11 ----------- libraries/render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/shared/src/Transform.h | 10 ++++++++++ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48fa53777d..7bfa500f64 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3386,14 +3386,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // load the view frustum loadViewFrustum(theCamera, _displayViewFrustum); - // flip x if in mirror mode (also requires reversing winding order for backface culling) - if (theCamera.getMode() == CAMERA_MODE_MIRROR) { - //glScalef(-1.0f, 1.0f, 1.0f); - //glFrontFace(GL_CW); - } else { - glFrontFace(GL_CCW); - } - // transform view according to theCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -3411,9 +3403,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se Transform viewTransform; viewTransform.setTranslation(theCamera.getPosition()); viewTransform.setRotation(rotation); - if (theCamera.getMode() == CAMERA_MODE_MIRROR) { -// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); - } if (renderArgs->_renderSide != RenderArgs::MONO) { glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 12a6d32ae5..4929d4b5ae 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -118,7 +118,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend args->_viewFrustum->evalProjectionMatrix(projMat); args->_viewFrustum->evalViewTransform(viewMat); if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); + viewMat.preScale(glm::vec3(-1.0f, 1.0f, 1.0f)); } batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index e961f379c8..6f841151c4 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -97,6 +97,8 @@ public: const Vec3& getScale() const; void setScale(float scale); void setScale(const Vec3& scale); // [new this] = [this.translation] * [this.rotation] * [scale] + void preScale(float scale); + void preScale(const Vec3& scale); void postScale(float scale); // [new this] = [this] * [scale] equivalent to glScale void postScale(const Vec3& scale); // [new this] = [this] * [scale] equivalent to glScale @@ -322,6 +324,14 @@ inline void Transform::setScale(const Vec3& scale) { } } +inline void Transform::preScale(float scale) { + setScale(getScale() * scale); +} + +inline void Transform::preScale(const Vec3& scale) { + setScale(getScale() * scale); +} + inline void Transform::postScale(float scale) { if (!isValidScale(scale) || scale == 1.0f) { return; From 08d1364f81616093bec3700dd26b98aec008fadf Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Jul 2015 22:35:23 -0700 Subject: [PATCH 05/11] Move file log persistence to a separate thread --- interface/src/AbstractLoggerInterface.h | 4 +- interface/src/FileLogger.cpp | 42 +++++++++---- interface/src/FileLogger.h | 10 ++-- libraries/shared/src/GenericQueueThread.h | 72 +++++++++++++++++++++++ libraries/shared/src/GenericThread.cpp | 3 +- libraries/shared/src/GenericThread.h | 2 +- 6 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 libraries/shared/src/GenericQueueThread.h diff --git a/interface/src/AbstractLoggerInterface.h b/interface/src/AbstractLoggerInterface.h index fe45346e4c..3823060b13 100644 --- a/interface/src/AbstractLoggerInterface.h +++ b/interface/src/AbstractLoggerInterface.h @@ -24,7 +24,7 @@ public: inline bool extraDebugging() { return _extraDebugging; } inline void setExtraDebugging(bool debugging) { _extraDebugging = debugging; } - virtual void addMessage(QString) = 0; + virtual void addMessage(const QString&) = 0; virtual QString getLogData() = 0; virtual void locateLog() = 0; @@ -32,7 +32,7 @@ signals: void logReceived(QString message); private: - bool _extraDebugging; + bool _extraDebugging{ false }; }; #endif // hifi_AbstractLoggerInterface_h diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index 4808842036..bcae96b2ea 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -21,11 +21,35 @@ const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt"; const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss"; const QString LOGS_DIRECTORY = "Logs"; +class FilePersistThread : public GenericQueueThread < QString > { +public: + FilePersistThread(FileLogger& logger) : _logger(logger) { + setObjectName("LogFileWriter"); + } + +protected: + virtual bool processQueueItems(const Queue& messages) { + QFile file(_logger._fileName); + if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { + QTextStream out(&file); + foreach(const QString& message, messages) { + out << message; + } + } + return true; + } +private: + FileLogger& _logger; +}; + +static FilePersistThread* _persistThreadInstance; + FileLogger::FileLogger(QObject* parent) : AbstractLoggerInterface(parent), _logData("") { - setExtraDebugging(false); + _persistThreadInstance = new FilePersistThread(*this); + _persistThreadInstance->initialize(true); _fileName = FileUtils::standardPath(LOGS_DIRECTORY); QHostAddress clientAddress = getLocalAddress(); @@ -33,16 +57,14 @@ FileLogger::FileLogger(QObject* parent) : _fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); } -void FileLogger::addMessage(QString message) { - QMutexLocker locker(&_mutex); - emit logReceived(message); - _logData += message; +FileLogger::~FileLogger() { + _persistThreadInstance->terminate(); +} - QFile file(_fileName); - if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { - QTextStream out(&file); - out << message; - } +void FileLogger::addMessage(const QString& message) { + _persistThreadInstance->queueItem(message); + emit logReceived(message); + //_logData += message; } void FileLogger::locateLog() { diff --git a/interface/src/FileLogger.h b/interface/src/FileLogger.h index 3dbbfd26cd..72bffa6445 100644 --- a/interface/src/FileLogger.h +++ b/interface/src/FileLogger.h @@ -13,23 +13,25 @@ #define hifi_FileLogger_h #include "AbstractLoggerInterface.h" -#include +#include class FileLogger : public AbstractLoggerInterface { Q_OBJECT public: FileLogger(QObject* parent = NULL); + virtual ~FileLogger(); - virtual void addMessage(QString); + virtual void addMessage(const QString&); virtual QString getLogData() { return _logData; } virtual void locateLog(); private: QString _logData; QString _fileName; - QMutex _mutex; - + friend class FilePersistThread; }; + + #endif // hifi_FileLogger_h diff --git a/libraries/shared/src/GenericQueueThread.h b/libraries/shared/src/GenericQueueThread.h new file mode 100644 index 0000000000..2a48ff7418 --- /dev/null +++ b/libraries/shared/src/GenericQueueThread.h @@ -0,0 +1,72 @@ +// +// Created by Bradley Austin Davis 2015/07/08. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_GenericQueueThread_h +#define hifi_GenericQueueThread_h + +#include + +#include +#include +#include + +#include "GenericThread.h" +#include "NumericalConstants.h" + +template +class GenericQueueThread : public GenericThread { +public: + using Queue = QQueue; + GenericQueueThread(QObject* parent = nullptr) + : GenericThread(parent) {} + + virtual ~GenericQueueThread() {} + + void queueItem(const T& t) { + lock(); + queueItemInternal(t); + unlock(); + _hasItems.wakeAll(); + } + +protected: + virtual void queueItemInternal(const T& t) { + _items.push_back(t); + } + + virtual uint32_t getMaxWait() { + return MSECS_PER_SECOND; + } + + virtual bool process() { + if (!_items.size()) { + _hasItemsMutex.lock(); + _hasItems.wait(&_hasItemsMutex, getMaxWait()); + _hasItemsMutex.unlock(); + } + + if (!_items.size()) { + return isStillRunning(); + } + + Queue processItems; + lock(); + processItems.swap(_items); + unlock(); + return processQueueItems(processItems); + } + + virtual bool processQueueItems(const Queue& items) = 0; + + Queue _items; + QWaitCondition _hasItems; + QMutex _hasItemsMutex; +}; + +#endif // hifi_GenericQueueThread_h diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 3068ca2ab6..a7e0f3456b 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -14,7 +14,8 @@ #include "GenericThread.h" -GenericThread::GenericThread() : +GenericThread::GenericThread(QObject* parent) : + QObject(parent), _stopThread(false), _isThreaded(false) // assume non-threaded, must call initialize() { diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index b2c0eb13db..6fe6b6ccb4 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -23,7 +23,7 @@ class GenericThread : public QObject { Q_OBJECT public: - GenericThread(); + GenericThread(QObject* parent = nullptr); virtual ~GenericThread(); /// Call to start the thread. From 63dfd570f198e243709bad1a54f0af1821fe3a49 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 8 Jul 2015 22:54:31 -0700 Subject: [PATCH 06/11] Adding priority support to GenericThread --- interface/src/FileLogger.cpp | 6 +++--- libraries/shared/src/GenericThread.cpp | 3 ++- libraries/shared/src/GenericThread.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index bcae96b2ea..508586c23c 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -23,7 +23,7 @@ const QString LOGS_DIRECTORY = "Logs"; class FilePersistThread : public GenericQueueThread < QString > { public: - FilePersistThread(FileLogger& logger) : _logger(logger) { + FilePersistThread(const FileLogger& logger) : _logger(logger) { setObjectName("LogFileWriter"); } @@ -39,7 +39,7 @@ protected: return true; } private: - FileLogger& _logger; + const FileLogger& _logger; }; static FilePersistThread* _persistThreadInstance; @@ -49,7 +49,7 @@ FileLogger::FileLogger(QObject* parent) : _logData("") { _persistThreadInstance = new FilePersistThread(*this); - _persistThreadInstance->initialize(true); + _persistThreadInstance->initialize(true, QThread::LowestPriority); _fileName = FileUtils::standardPath(LOGS_DIRECTORY); QHostAddress clientAddress = getLocalAddress(); diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index a7e0f3456b..9c1c7c590c 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -28,13 +28,14 @@ GenericThread::~GenericThread() { } } -void GenericThread::initialize(bool isThreaded) { +void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _isThreaded = isThreaded; if (_isThreaded) { _thread = new QThread(this); // match the thread name to our object name _thread->setObjectName(objectName()); + _thread->setPriority(priority); // when the worker thread is started, call our engine's run.. connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine())); diff --git a/libraries/shared/src/GenericThread.h b/libraries/shared/src/GenericThread.h index 6fe6b6ccb4..f261dc5b37 100644 --- a/libraries/shared/src/GenericThread.h +++ b/libraries/shared/src/GenericThread.h @@ -28,7 +28,7 @@ public: /// Call to start the thread. /// \param bool isThreaded true by default. false for non-threaded mode and caller must call threadRoutine() regularly. - void initialize(bool isThreaded = true); + void initialize(bool isThreaded = true, QThread::Priority priority = QThread::NormalPriority); /// Call to stop the thread void terminate(); From 2fff560ff9dadfcbb2d8b60eebd881676812cbae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Jul 2015 09:54:35 -0700 Subject: [PATCH 07/11] Fixing log file viewer --- interface/src/FileLogger.cpp | 13 ++++++++++--- interface/src/FileLogger.h | 7 +++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index 508586c23c..00da80814b 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -45,8 +45,7 @@ private: static FilePersistThread* _persistThreadInstance; FileLogger::FileLogger(QObject* parent) : - AbstractLoggerInterface(parent), - _logData("") + AbstractLoggerInterface(parent) { _persistThreadInstance = new FilePersistThread(*this); _persistThreadInstance->initialize(true, QThread::LowestPriority); @@ -64,9 +63,17 @@ FileLogger::~FileLogger() { void FileLogger::addMessage(const QString& message) { _persistThreadInstance->queueItem(message); emit logReceived(message); - //_logData += message; } void FileLogger::locateLog() { FileUtils::locateFile(_fileName); } + +QString FileLogger::getLogData() { + QString result; + QFile f(_fileName); + if (f.open(QFile::ReadOnly | QFile::Text)) { + result = QTextStream(&f).readAll(); + } + return result; +} diff --git a/interface/src/FileLogger.h b/interface/src/FileLogger.h index 72bffa6445..549654ca5c 100644 --- a/interface/src/FileLogger.h +++ b/interface/src/FileLogger.h @@ -22,12 +22,11 @@ public: FileLogger(QObject* parent = NULL); virtual ~FileLogger(); - virtual void addMessage(const QString&); - virtual QString getLogData() { return _logData; } - virtual void locateLog(); + virtual void addMessage(const QString&) override; + virtual QString getLogData() override; + virtual void locateLog() override; private: - QString _logData; QString _fileName; friend class FilePersistThread; }; From 46bca30698138ff45b865199defbe01d161f2b1a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Jul 2015 11:29:53 -0700 Subject: [PATCH 08/11] MotionState reports zero velocity for slow objects This reduces the number of updates for an Entity that is effectively at rest due to a balance between some spring action and gravity, but nevertheless has a slight non-zero velocity at the end of each simulation step. --- libraries/physics/src/EntityMotionState.cpp | 6 +++--- libraries/physics/src/ObjectMotionState.cpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a975d21c4d..8d77f815b7 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -248,7 +248,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { btTransform xform = _body->getWorldTransform(); _serverPosition = bulletToGLM(xform.getOrigin()); _serverRotation = bulletToGLM(xform.getRotation()); - _serverVelocity = bulletToGLM(_body->getLinearVelocity()); + _serverVelocity = getBodyLinearVelocity(); _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); _lastStep = simulationStep; _serverActionData = _entity->getActionData(); @@ -536,7 +536,7 @@ void EntityMotionState::bump(quint8 priority) { void EntityMotionState::resetMeasuredBodyAcceleration() { _lastMeasureStep = ObjectMotionState::getWorldSimulationStep(); if (_body) { - _lastVelocity = bulletToGLM(_body->getLinearVelocity()); + _lastVelocity = getBodyLinearVelocity(); } else { _lastVelocity = glm::vec3(0.0f); } @@ -555,7 +555,7 @@ void EntityMotionState::measureBodyAcceleration() { // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt - glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity()); + glm::vec3 velocity = getBodyLinearVelocity(); _measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt; _lastVelocity = velocity; if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) { diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 7ff119fb79..8e4bbdae1c 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -80,7 +80,17 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { } glm::vec3 ObjectMotionState::getBodyLinearVelocity() const { - return bulletToGLM(_body->getLinearVelocity()); + // returns the body's velocity unless it is moving too slow in which case returns zero + btVector3 velocity = _body->getLinearVelocity(); + + // NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates + // to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving + // just under this velocity threshold would trigger an update about V/dX times per second. + const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec + if (velocity.length2() < MIN_LINEAR_SPEED_SQUARED) { + velocity *= 0.0f; + } + return bulletToGLM(velocity); } glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const { return glm::vec3(0.0f); // Subclasses override where meaningful. From 612e9649d8ab85c64cbab526f6f0d5849b323df5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Jul 2015 11:32:30 -0700 Subject: [PATCH 09/11] fix update logic of ObjectActionOffset --- libraries/physics/src/ObjectActionOffset.cpp | 104 +++++++++++-------- libraries/physics/src/ObjectActionOffset.h | 1 + 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index 7cf35b27d7..ff789dfefe 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -16,7 +16,11 @@ const uint16_t ObjectActionOffset::offsetVersion = 1; ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity) : - ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity) { + ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity), + _pointToOffsetFrom(0.f), + _linearDistance(0.0f), + _linearTimeScale(FLT_MAX), + _positionalTargetSet(false) { #if WANT_DEBUG qDebug() << "ObjectActionOffset::ObjectActionOffset"; #endif @@ -44,6 +48,7 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { unlock(); return; } + ObjectMotionState* motionState = static_cast(physicsInfo); btRigidBody* rigidBody = motionState->getRigidBody(); if (!rigidBody) { @@ -52,21 +57,32 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { return; } - if (_positionalTargetSet) { - glm::vec3 offset = _pointToOffsetFrom - bulletToGLM(rigidBody->getCenterOfMassPosition()); - float offsetLength = glm::length(offset); - float offsetError = _linearDistance - offsetLength; - - // if (glm::abs(offsetError) > IGNORE_POSITION_DELTA) { - if (glm::abs(offsetError) > 0.0f) { - float offsetErrorAbs = glm::abs(offsetError); - float offsetErrorDirection = - offsetError / offsetErrorAbs; - glm::vec3 previousVelocity = bulletToGLM(rigidBody->getLinearVelocity()); - - glm::vec3 velocityAdjustment = glm::normalize(offset) * offsetErrorDirection * offsetErrorAbs / _linearTimeScale; - rigidBody->setLinearVelocity(glmToBullet(previousVelocity + velocityAdjustment)); - // rigidBody->setLinearVelocity(glmToBullet(velocityAdjustment)); + const float MAX_LINEAR_TIMESCALE = 600.0f; // 10 minutes is a long time + if (_positionalTargetSet && _linearTimeScale < MAX_LINEAR_TIMESCALE) { + if (_needsActivation) { rigidBody->activate(); + _needsActivation = false; + } + glm::vec3 objectPosition = bulletToGLM(rigidBody->getCenterOfMassPosition()); + glm::vec3 springAxis = objectPosition - _pointToOffsetFrom; // from anchor to object + float distance = glm::length(springAxis); + if (distance > FLT_EPSILON) { + springAxis /= distance; // normalize springAxis + + // compute (critically damped) target velocity of spring relaxation + glm::vec3 offset = (distance - _linearDistance) * springAxis; + glm::vec3 targetVelocity = (-1.0f / _linearTimeScale) * offset; + + // compute current velocity and its parallel component + glm::vec3 currentVelocity = bulletToGLM(rigidBody->getLinearVelocity()); + glm::vec3 parallelVelocity = glm::dot(currentVelocity, springAxis) * springAxis; + + // we blend the parallel component with the spring's target velocity to get the new velocity + float blend = deltaTimeStep / _linearTimeScale; + if (blend > 1.0f) { + blend = 1.0f; + } + rigidBody->setLinearVelocity(glmToBullet(currentVelocity + blend * (targetVelocity - parallelVelocity)); } } @@ -75,45 +91,45 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { bool ObjectActionOffset::updateArguments(QVariantMap arguments) { - bool pOk0 = true; + bool ok = true; glm::vec3 pointToOffsetFrom = - EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", pOk0, true); + EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true); + if (!ok) { + return false; + } - bool pOk1 = true; + ok = true; float linearTimeScale = - EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", pOk1, false); + EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false); + if (ok) { + if (linearTimeScale <= 0.0f) { + qDebug() << "offset action -- linearTimeScale must be greater than zero."; + return false; + } + } else { + linearTimeScale = 0.1f; + } - bool pOk2 = true; + ok = true; float linearDistance = - EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", pOk2, false); - - if (!pOk0) { - return false; - } - if (pOk1 && linearTimeScale <= 0.0f) { - qDebug() << "offset action -- linearTimeScale must be greater than zero."; - return false; + EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false); + if (!ok) { + linearDistance = 0.0f; } - lockForWrite(); - - _pointToOffsetFrom = pointToOffsetFrom; - _positionalTargetSet = true; - - if (pOk1) { + // only change stuff if something actually changed + if (_pointToOffsetFrom != pointToOffsetFrom + || _linearTimeScale != linearTimeScale + || _linearDistance != linearDistance) { + lockForWrite(); + _pointToOffsetFrom = pointToOffsetFrom; _linearTimeScale = linearTimeScale; - } else { - _linearTimeScale = 0.1f; - } - - if (pOk2) { _linearDistance = linearDistance; - } else { - _linearDistance = 1.0f; + _positionalTargetSet = true; + _active = true; + _needsActivation = true; + unlock(); } - - _active = true; - unlock(); return true; } diff --git a/libraries/physics/src/ObjectActionOffset.h b/libraries/physics/src/ObjectActionOffset.h index 1918da6996..a0190f3832 100644 --- a/libraries/physics/src/ObjectActionOffset.h +++ b/libraries/physics/src/ObjectActionOffset.h @@ -36,6 +36,7 @@ public: float _linearDistance; float _linearTimeScale; bool _positionalTargetSet; + bool _needsActivation = true; }; #endif // hifi_ObjectActionOffset_h From ccf14b2e50123907743fce7487233e477d95276d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Jul 2015 11:43:57 -0700 Subject: [PATCH 10/11] fix syntax error typo --- libraries/physics/src/ObjectActionOffset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index ff789dfefe..6189128997 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -82,7 +82,7 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) { if (blend > 1.0f) { blend = 1.0f; } - rigidBody->setLinearVelocity(glmToBullet(currentVelocity + blend * (targetVelocity - parallelVelocity)); + rigidBody->setLinearVelocity(glmToBullet(currentVelocity + blend * (targetVelocity - parallelVelocity))); } } From 55207a8fb1ce7da208cf0bd1d22b578dc1729661 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Jul 2015 11:59:28 -0700 Subject: [PATCH 11/11] enforce coding standards --- libraries/physics/src/ObjectActionOffset.cpp | 2 +- libraries/physics/src/ObjectMotionState.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectActionOffset.cpp b/libraries/physics/src/ObjectActionOffset.cpp index 6189128997..2391ded13d 100644 --- a/libraries/physics/src/ObjectActionOffset.cpp +++ b/libraries/physics/src/ObjectActionOffset.cpp @@ -17,7 +17,7 @@ const uint16_t ObjectActionOffset::offsetVersion = 1; ObjectActionOffset::ObjectActionOffset(const QUuid& id, EntityItemPointer ownerEntity) : ObjectAction(ACTION_TYPE_OFFSET, id, ownerEntity), - _pointToOffsetFrom(0.f), + _pointToOffsetFrom(0.0f), _linearDistance(0.0f), _linearTimeScale(FLT_MAX), _positionalTargetSet(false) { diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 8e4bbdae1c..aeec85f7ea 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -92,6 +92,7 @@ glm::vec3 ObjectMotionState::getBodyLinearVelocity() const { } return bulletToGLM(velocity); } + glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const { return glm::vec3(0.0f); // Subclasses override where meaningful. }