From 22190c1340aac18ba59b0c653482740eea101cef Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Thu, 22 May 2014 17:55:25 -0700 Subject: [PATCH 01/77] Made overlays thread safe for write operations, which solved a script crash. --- interface/src/ui/overlays/Overlays.cpp | 6 +++--- interface/src/ui/overlays/Overlays.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 9e4a594bbc..6c6f150ae7 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -96,7 +96,6 @@ void Overlays::render3D() { } } -// TODO: make multi-threaded safe unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { unsigned int thisID = 0; bool created = false; @@ -140,6 +139,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope } if (created) { + QWriteLocker lock(&_lock); thisID = _nextOverlayID; _nextOverlayID++; if (is3D) { @@ -152,9 +152,9 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope return thisID; } -// TODO: make multi-threaded safe bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { Overlay* thisOverlay = NULL; + QWriteLocker lock(&_lock); if (_overlays2D.contains(id)) { thisOverlay = _overlays2D[id]; } else if (_overlays3D.contains(id)) { @@ -167,9 +167,9 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { return false; } -// TODO: make multi-threaded safe void Overlays::deleteOverlay(unsigned int id) { Overlay* overlayToDelete; + QWriteLocker lock(&_lock); if (_overlays2D.contains(id)) { overlayToDelete = _overlays2D.take(id); } else if (_overlays3D.contains(id)) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index b3477be0c2..20015b8af9 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -45,6 +45,7 @@ private: QList _overlaysToDelete; unsigned int _nextOverlayID; QGLWidget* _parent; + QReadWriteLock _lock; }; From 55ed3e98a5615e4b739407860b27e0a0779f1dce Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 23 May 2014 10:44:40 -0700 Subject: [PATCH 02/77] Added some missing locks to make Overlays thread safe for reading as well. --- interface/src/ui/overlays/Overlays.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 6c6f150ae7..bcac86d7f1 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -39,6 +39,7 @@ void Overlays::init(QGLWidget* parent) { } void Overlays::update(float deltatime) { + QWriteLocker lock(&_lock); foreach (Overlay* thisOverlay, _overlays2D) { thisOverlay->update(deltatime); } @@ -52,12 +53,14 @@ void Overlays::update(float deltatime) { } void Overlays::render2D() { + QReadLocker lock(&_lock); foreach(Overlay* thisOverlay, _overlays2D) { thisOverlay->render(); } } void Overlays::render3D() { + QReadLocker lock(&_lock); if (_overlays3D.size() == 0) { return; } @@ -182,6 +185,7 @@ void Overlays::deleteOverlay(unsigned int id) { } unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { + QReadLocker lock(&_lock); QMapIterator i(_overlays2D); i.toBack(); while (i.hasPrevious()) { From 495a54291c6fd01b889373fa7e8af6e44cfcac92 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 May 2014 10:57:14 -0700 Subject: [PATCH 03/77] Use local viewer model for specular. --- interface/resources/shaders/model.frag | 5 ++++- interface/resources/shaders/model.vert | 6 ++++++ interface/resources/shaders/model_normal_map.frag | 7 +++++-- interface/resources/shaders/model_normal_map.vert | 6 +++++- .../resources/shaders/model_normal_specular_map.frag | 7 +++++-- interface/resources/shaders/model_specular_map.frag | 5 ++++- interface/resources/shaders/skin_model.vert | 9 ++++++--- .../resources/shaders/skin_model_normal_map.vert | 11 +++++++---- 8 files changed, 42 insertions(+), 14 deletions(-) diff --git a/interface/resources/shaders/model.frag b/interface/resources/shaders/model.frag index a9d93f2f6a..488736abf9 100644 --- a/interface/resources/shaders/model.frag +++ b/interface/resources/shaders/model.frag @@ -14,6 +14,9 @@ // the diffuse texture uniform sampler2D diffuseMap; +// the interpolated position +varying vec4 position; + // the interpolated normal varying vec4 normal; @@ -26,7 +29,7 @@ void main(void) { gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); // compute the specular component (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), normalizedNormal)); // modulate texture by base color and add specular contribution diff --git a/interface/resources/shaders/model.vert b/interface/resources/shaders/model.vert index 904e3c2a8b..f78ed5045b 100644 --- a/interface/resources/shaders/model.vert +++ b/interface/resources/shaders/model.vert @@ -11,6 +11,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the interpolated position +varying vec4 position; + // the interpolated normal varying vec4 normal; @@ -19,6 +22,9 @@ void main(void) { // transform and store the normal for interpolation normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + // likewise with the position + position = gl_ModelViewMatrix * gl_Vertex; + // pass along the vertex color gl_FrontColor = gl_Color; diff --git a/interface/resources/shaders/model_normal_map.frag b/interface/resources/shaders/model_normal_map.frag index 392be1f1cf..8444f2d6ea 100644 --- a/interface/resources/shaders/model_normal_map.frag +++ b/interface/resources/shaders/model_normal_map.frag @@ -17,6 +17,9 @@ uniform sampler2D diffuseMap; // the normal map texture uniform sampler2D normalMap; +// the interpolated position +varying vec4 interpolatedPosition; + // the interpolated normal varying vec4 interpolatedNormal; @@ -38,8 +41,8 @@ void main(void) { gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); // compute the specular component (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), - viewNormal)); + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal)); // modulate texture by base color and add specular contribution gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + diff --git a/interface/resources/shaders/model_normal_map.vert b/interface/resources/shaders/model_normal_map.vert index 3607501acf..b013a0a736 100644 --- a/interface/resources/shaders/model_normal_map.vert +++ b/interface/resources/shaders/model_normal_map.vert @@ -14,6 +14,9 @@ // the tangent vector attribute vec3 tangent; +// the interpolated position +varying vec4 interpolatedPosition; + // the interpolated normal varying vec4 interpolatedNormal; @@ -22,7 +25,8 @@ varying vec4 interpolatedTangent; void main(void) { - // transform and store the normal and tangent for interpolation + // transform and store the position, normal and tangent for interpolation + interpolatedPosition = gl_ModelViewMatrix * gl_Vertex; interpolatedNormal = gl_ModelViewMatrix * vec4(gl_Normal, 0.0); interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0); diff --git a/interface/resources/shaders/model_normal_specular_map.frag b/interface/resources/shaders/model_normal_specular_map.frag index dbbb343c62..357677d82a 100644 --- a/interface/resources/shaders/model_normal_specular_map.frag +++ b/interface/resources/shaders/model_normal_specular_map.frag @@ -20,6 +20,9 @@ uniform sampler2D normalMap; // the specular map texture uniform sampler2D specularMap; +// the interpolated position +varying vec4 interpolatedPosition; + // the interpolated normal varying vec4 interpolatedNormal; @@ -41,8 +44,8 @@ void main(void) { gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); // compute the specular component (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), - viewNormal)); + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(interpolatedPosition.xyz, 0.0))), viewNormal)); // modulate texture by base color and add specular contribution gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * diff --git a/interface/resources/shaders/model_specular_map.frag b/interface/resources/shaders/model_specular_map.frag index b955b5cfa6..a07324cd1b 100644 --- a/interface/resources/shaders/model_specular_map.frag +++ b/interface/resources/shaders/model_specular_map.frag @@ -17,6 +17,9 @@ uniform sampler2D diffuseMap; // the specular texture uniform sampler2D specularMap; +// the interpolated position in view space +varying vec4 position; + // the interpolated normal varying vec4 normal; @@ -29,7 +32,7 @@ void main(void) { gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); // compute the specular component (sans exponent) - float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), normalizedNormal)); // modulate texture by base color and add specular contribution diff --git a/interface/resources/shaders/skin_model.vert b/interface/resources/shaders/skin_model.vert index 12320ba9a9..f743609dc3 100644 --- a/interface/resources/shaders/skin_model.vert +++ b/interface/resources/shaders/skin_model.vert @@ -19,11 +19,14 @@ uniform mat4 clusterMatrices[MAX_CLUSTERS]; attribute vec4 clusterIndices; attribute vec4 clusterWeights; +// the interpolated position +varying vec4 position; + // the interpolated normal varying vec4 normal; void main(void) { - vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + position = vec4(0.0, 0.0, 0.0, 0.0); normal = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])]; @@ -31,7 +34,7 @@ void main(void) { position += clusterMatrix * gl_Vertex * clusterWeight; normal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; } - position = gl_ModelViewProjectionMatrix * position; + position = gl_ModelViewMatrix * position; normal = normalize(gl_ModelViewMatrix * normal); // pass along the vertex color @@ -40,5 +43,5 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = position; + gl_Position = gl_ProjectionMatrix * position; } diff --git a/interface/resources/shaders/skin_model_normal_map.vert b/interface/resources/shaders/skin_model_normal_map.vert index 872cbe2fc3..5dbc32626a 100644 --- a/interface/resources/shaders/skin_model_normal_map.vert +++ b/interface/resources/shaders/skin_model_normal_map.vert @@ -22,6 +22,9 @@ attribute vec3 tangent; attribute vec4 clusterIndices; attribute vec4 clusterWeights; +// the interpolated position +varying vec4 interpolatedPosition; + // the interpolated normal varying vec4 interpolatedNormal; @@ -29,17 +32,17 @@ varying vec4 interpolatedNormal; varying vec4 interpolatedTangent; void main(void) { - vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + interpolatedPosition = vec4(0.0, 0.0, 0.0, 0.0); interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])]; float clusterWeight = clusterWeights[i]; - position += clusterMatrix * gl_Vertex * clusterWeight; + interpolatedPosition += clusterMatrix * gl_Vertex * clusterWeight; interpolatedNormal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; interpolatedTangent += clusterMatrix * vec4(tangent, 0.0) * clusterWeight; } - position = gl_ModelViewProjectionMatrix * position; + interpolatedPosition = gl_ModelViewMatrix * interpolatedPosition; interpolatedNormal = gl_ModelViewMatrix * interpolatedNormal; interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent; @@ -49,5 +52,5 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = position; + gl_Position = gl_ProjectionMatrix * interpolatedPosition; } From 38ae1f3be329c5c2a26aa4dae672f7d1d4326cad Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Fri, 23 May 2014 11:17:55 -0700 Subject: [PATCH 04/77] Added a new lock specific to deleting, and improved safety --- interface/src/ui/overlays/Overlays.cpp | 43 ++++++++++++++++---------- interface/src/ui/overlays/Overlays.h | 1 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index bcac86d7f1..da7b05ead7 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -39,15 +39,22 @@ void Overlays::init(QGLWidget* parent) { } void Overlays::update(float deltatime) { - QWriteLocker lock(&_lock); - foreach (Overlay* thisOverlay, _overlays2D) { - thisOverlay->update(deltatime); + + { + QWriteLocker lock(&_lock); + foreach(Overlay* thisOverlay, _overlays2D) { + thisOverlay->update(deltatime); + } + foreach(Overlay* thisOverlay, _overlays3D) { + thisOverlay->update(deltatime); + } } - foreach (Overlay* thisOverlay, _overlays3D) { - thisOverlay->update(deltatime); - } - while (!_overlaysToDelete.isEmpty()) { - delete _overlaysToDelete.takeLast(); + + if (!_overlaysToDelete.isEmpty()) { + QWriteLocker lock(&_deleteLock); + do { + delete _overlaysToDelete.takeLast(); + } while (!_overlaysToDelete.isEmpty()); } } @@ -172,15 +179,19 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) { void Overlays::deleteOverlay(unsigned int id) { Overlay* overlayToDelete; - QWriteLocker lock(&_lock); - if (_overlays2D.contains(id)) { - overlayToDelete = _overlays2D.take(id); - } else if (_overlays3D.contains(id)) { - overlayToDelete = _overlays3D.take(id); - } else { - return; + + { + QWriteLocker lock(&_lock); + if (_overlays2D.contains(id)) { + overlayToDelete = _overlays2D.take(id); + } else if (_overlays3D.contains(id)) { + overlayToDelete = _overlays3D.take(id); + } else { + return; + } } - + + QWriteLocker lock(&_deleteLock); _overlaysToDelete.push_back(overlayToDelete); } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 20015b8af9..2fbdb993f4 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -46,6 +46,7 @@ private: unsigned int _nextOverlayID; QGLWidget* _parent; QReadWriteLock _lock; + QReadWriteLock _deleteLock; }; From c36273122647c31efb253f019237e0b5472f5053 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 May 2014 09:57:37 -0700 Subject: [PATCH 05/77] Add support to load script engines not based on a file --- interface/src/Application.cpp | 19 ++++++++++++------- interface/src/Application.h | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1e3e11910e..76fc29e97a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3381,15 +3381,20 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript return _scriptEnginesHash[scriptName]; } - // start the script on a new thread... - ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface); - _scriptEnginesHash.insert(scriptName, scriptEngine); + ScriptEngine* scriptEngine; + if (scriptName.isNull()) { + scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); + } else { + // start the script on a new thread... + scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface); + _scriptEnginesHash.insert(scriptName, scriptEngine); - if (!scriptEngine->hasScript()) { - qDebug() << "Application::loadScript(), script failed to load..."; - return NULL; + if (!scriptEngine->hasScript()) { + qDebug() << "Application::loadScript(), script failed to load..."; + return NULL; + } + _runningScriptsWidget->setRunningScripts(getRunningScripts()); } - _runningScriptsWidget->setRunningScripts(getRunningScripts()); // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. diff --git a/interface/src/Application.h b/interface/src/Application.h index ea0de764b9..9ff2009f2d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -290,7 +290,7 @@ public slots: void loadScriptURLDialog(); void toggleLogDialog(); void initAvatarAndViewFrustum(); - ScriptEngine* loadScript(const QString& fileNameString, bool loadScriptFromEditor = false); + ScriptEngine* loadScript(const QString& fileNameString = QString(), bool loadScriptFromEditor = false); void stopAllScripts(bool restart = false); void stopScript(const QString& scriptName); void reloadAllScripts(); From 3d28cff9dfe5f66c9ef2cac7a8ae8e35446b2cf8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 May 2014 09:58:06 -0700 Subject: [PATCH 06/77] Add console to menu --- interface/src/Menu.cpp | 15 +++++++++++++++ interface/src/Menu.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e1d0c6a574..103cefbb2f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -78,6 +78,7 @@ Menu::Menu() : _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), + _jsConsole(NULL), _octreeStatsDialog(NULL), _lodToolsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), @@ -222,6 +223,12 @@ Menu::Menu() : _chatWindow = new ChatWindow(Application::getInstance()->getWindow()); #endif + addActionToQMenuAndActionHash(toolsMenu, + MenuOption::Console, + Qt::CTRL | Qt::Key_QuoteLeft, + this, + SLOT(showConsole())); + QMenu* viewMenu = addMenu("View"); addCheckableActionToQMenuAndActionHash(viewMenu, @@ -1195,6 +1202,14 @@ void Menu::toggleChat() { #endif } +void Menu::showConsole() { + QMainWindow* mainWindow = Application::getInstance()->getWindow(); + if (!_jsConsole) { + _jsConsole = new JSConsole(mainWindow); + } + _jsConsole->setVisible(!_jsConsole->isVisible()); +} + void Menu::audioMuteToggled() { QAction *muteAction = _actionHash.value(MenuOption::MuteAudio); muteAction->setChecked(Application::getInstance()->getAudio()->getMuted()); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 230584bf07..b1d33e0a27 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -26,6 +26,7 @@ #include "location/LocationManager.h" #include "ui/PreferencesDialog.h" #include "ui/ChatWindow.h" +#include "ui/JSConsole.h" #include "ui/ScriptEditorWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; @@ -187,6 +188,7 @@ private slots: void showMetavoxelEditor(); void showScriptEditor(); void showChat(); + void showConsole(); void toggleChat(); void audioMuteToggled(); void namedLocationCreated(LocationManager::NamedLocationCreateResponse response); @@ -241,6 +243,7 @@ private: QPointer _MetavoxelEditor; QPointer _ScriptEditor; QPointer _chatWindow; + JSConsole* _jsConsole; OctreeStatsDialog* _octreeStatsDialog; LodToolsDialog* _lodToolsDialog; int _maxVoxels; @@ -297,6 +300,7 @@ namespace MenuOption { const QString CollideWithParticles = "Collide With Particles"; const QString CollideWithVoxels = "Collide With Voxels"; const QString Collisions = "Collisions"; + const QString Console = "Console..."; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; From 8aa9cea30e76c796ba3cd1bc242dca8d34f1ac0d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 May 2014 09:59:02 -0700 Subject: [PATCH 07/77] Add custom evaluation of commands in ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 12 ++++++++++++ libraries/script-engine/src/ScriptEngine.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index be97b37b46..3f92d8426b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -304,6 +304,18 @@ void ScriptEngine::evaluate() { } } +QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { + QScriptValue result = _engine.evaluate(program, fileName, lineNumber); + bool hasUncaughtException = _engine.hasUncaughtException(); + if (hasUncaughtException) { + int line = _engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ": " << result.toString(); + } + emit evaluationFinished(result, hasUncaughtException); + _engine.clearExceptions(); + return result; +} + void ScriptEngine::sendAvatarIdentityPacket() { if (_isAvatar && _avatarData) { _avatarData->sendIdentityPacket(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 09d41e3e2e..7c9f263694 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -93,6 +93,7 @@ public: public slots: void stop(); + QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1); QObject* setInterval(const QScriptValue& function, int intervalMS); QObject* setTimeout(const QScriptValue& function, int timeoutMS); void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } @@ -108,6 +109,7 @@ signals: void printedMessage(const QString& message); void errorMessage(const QString& message); void runningStateChanged(); + void evaluationFinished(QScriptValue result, bool isException); protected: QString _scriptContents; From 5a5d5b4983cf182bd4339a9082526b9fd7d5bbf7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 May 2014 09:59:28 -0700 Subject: [PATCH 08/77] Add JSConsole --- interface/src/ui/JSConsole.cpp | 229 +++++++++++++++++++++++++++++++++ interface/src/ui/JSConsole.h | 62 +++++++++ 2 files changed, 291 insertions(+) create mode 100644 interface/src/ui/JSConsole.cpp create mode 100644 interface/src/ui/JSConsole.h diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp new file mode 100644 index 0000000000..d0880cd50b --- /dev/null +++ b/interface/src/ui/JSConsole.cpp @@ -0,0 +1,229 @@ +// +// JSConsole.cpp +// interface/src/ui +// +// Created by Ryan Huffman on 05/12/14. +// Copyright 2014 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 +// + +#include +#include +#include + +#include "Application.h" +#include "ScriptHighlighting.h" + +#include "JSConsole.h" + +const int NO_CURRENT_HISTORY_COMMAND = -1; +const int MAX_HISTORY_SIZE = 64; + +const QString ACTIVE_PROMPT_STYLESHEET = "color: rgb(0, 0, 255);"; +const QString INACTIVE_PROMPT_STYLESHEET = "color: rgba(0, 0, 0, 0.5);"; +const QString COMMAND_STYLE = "color: rgb(30, 141, 255);"; + +const QString RESULT_ERROR_STYLE = "color: rgb(255, 0, 0);"; +const QString RESULT_SUCCESS_STYLE = "color: rgb(160, 160, 160);"; + +const QString GUTTER_ERROR = "
X
"; +const QString GUTTER_PREVIOUS_COMMAND = "
<
"; + +JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : + QDialog(parent, Qt::WindowStaysOnTopHint), + _ui(new Ui::Console), + _currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND), + _commandHistory(), + _scriptEngine(scriptEngine) { + + _ui->setupUi(this); + _ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap); + _ui->promptTextEdit->installEventFilter(this); + + connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom())); + connect(_ui->promptTextEdit, SIGNAL(textChanged()), this, SLOT(resizeTextInput())); + + + if (_scriptEngine == NULL) { + _scriptEngine = Application::getInstance()->loadScript(); + } + + connect(_scriptEngine, SIGNAL(evaluationFinished(QScriptValue, bool)), + this, SLOT(handleEvalutationFinished(QScriptValue, bool))); + connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&))); + + setWindowOpacity(0.95); +} + +JSConsole::~JSConsole() { + delete _ui; +} + +void JSConsole::executeCommand(const QString& command) { + _commandHistory.prepend(command); + if (_commandHistory.length() > MAX_HISTORY_SIZE) { + _commandHistory.removeLast(); + } + + _ui->promptTextEdit->setDisabled(true); + _ui->promptGutterLabel->setStyleSheet(INACTIVE_PROMPT_STYLESHEET); + + appendMessage(">", "
" + command.toHtmlEscaped() + "
"); + + QMetaObject::invokeMethod(_scriptEngine, "evaluate", Q_ARG(const QString&, command)); + + resetCurrentCommandHistory(); +} + +void JSConsole::handleEvalutationFinished(QScriptValue result, bool isException) { + _ui->promptTextEdit->setDisabled(false); + _ui->promptGutterLabel->setStyleSheet(ACTIVE_PROMPT_STYLESHEET); + + // Make sure focus is still on this window - some commands are blocking and can take awhile to execute. + if (window()->isActiveWindow()) { + _ui->promptTextEdit->setFocus(); + } + + QString gutter = (isException || result.isError()) ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; + QString resultColor = (isException || result.isError()) ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; + QString resultStr = "
" + result.toString().toHtmlEscaped()  + "
"; + appendMessage(gutter, resultStr); +} + +void JSConsole::handlePrint(const QString& message) { + appendMessage("", message); +} + +void JSConsole::mouseReleaseEvent(QMouseEvent* event) { + _ui->promptTextEdit->setFocus(); +} + +void JSConsole::showEvent(QShowEvent* event) { + _ui->promptTextEdit->setFocus(); +} + +bool JSConsole::eventFilter(QObject* sender, QEvent* event) { + if (sender == _ui->promptTextEdit) { + if (event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast(event); + int key = keyEvent->key(); + + if ((key == Qt::Key_Return || key == Qt::Key_Enter)) { + if (keyEvent->modifiers() & Qt::ShiftModifier) { + // If the shift key is being used then treat it as a regular return/enter. If this isn't done, + // a new QTextBlock isn't created. + keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier); + } else { + QString command = _ui->promptTextEdit->toPlainText().trimmed(); + + if (!command.isEmpty()) { + QTextCursor cursor = _ui->promptTextEdit->textCursor(); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + + executeCommand(command); + } + + return true; + } + } else if (key == Qt::Key_Down) { + // Go to the next command in history if the cursor is at the last line of the current command. + int blockNumber = _ui->promptTextEdit->textCursor().blockNumber(); + int blockCount = _ui->promptTextEdit->document()->blockCount(); + if (blockNumber == blockCount - 1) { + setToNextCommandInHistory(); + return true; + } + } else if (key == Qt::Key_Up) { + // Go to the previous command in history if the cursor is at the first line of the current command. + int blockNumber = _ui->promptTextEdit->textCursor().blockNumber(); + if (blockNumber == 0) { + setToPreviousCommandInHistory(); + return true; + } + } + } + } + return false; +} + +void JSConsole::setToNextCommandInHistory() { + if (_currentCommandInHistory >= 0) { + _currentCommandInHistory--; + if (_currentCommandInHistory == NO_CURRENT_HISTORY_COMMAND) { + setAndSelectCommand(_rootCommand); + } else { + setAndSelectCommand(_commandHistory[_currentCommandInHistory]); + } + } +} + +void JSConsole::setToPreviousCommandInHistory() { + if (_currentCommandInHistory < (_commandHistory.length() - 1)) { + if (_currentCommandInHistory == NO_CURRENT_HISTORY_COMMAND) { + _rootCommand = _ui->promptTextEdit->toPlainText(); + } + _currentCommandInHistory++; + setAndSelectCommand(_commandHistory[_currentCommandInHistory]); + } +} + +void JSConsole::resetCurrentCommandHistory() { + _currentCommandInHistory = NO_CURRENT_HISTORY_COMMAND; +} + +void JSConsole::resizeTextInput() { + _ui->promptTextEdit->setMaximumHeight(_ui->promptTextEdit->document()->size().height()); + _ui->promptTextEdit->updateGeometry(); +} + +void JSConsole::setAndSelectCommand(const QString& text) { + QTextCursor cursor = _ui->promptTextEdit->textCursor(); + cursor.select(QTextCursor::Document); + cursor.deleteChar(); + cursor.insertText(text); + cursor.movePosition(QTextCursor::End); +} + +void JSConsole::scrollToBottom() { + QScrollBar* scrollBar = _ui->scrollArea->verticalScrollBar(); + scrollBar->setValue(scrollBar->maximum()); +} + +void JSConsole::appendMessage(const QString& gutter, const QString& message) { + QWidget* logLine = new QWidget(_ui->logArea); + QHBoxLayout* layout = new QHBoxLayout(logLine); + layout->setMargin(0); + layout->setSpacing(4); + + QLabel* gutterLabel = new QLabel(logLine); + QLabel* messageLabel = new QLabel(logLine); + + gutterLabel->setFixedWidth(16); + gutterLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + messageLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + QFont font("Courier New"); + font.setStyleHint(QFont::Monospace); + gutterLabel->setFont(font); + messageLabel->setFont(font); + + gutterLabel->setText(gutter); + messageLabel->setText(message); + + layout->addWidget(gutterLabel); + layout->addWidget(messageLabel); + logLine->setLayout(layout); + + layout->setAlignment(gutterLabel, Qt::AlignTop); + + layout->setStretch(0, 0); + layout->setStretch(1, 1); + + _ui->logArea->layout()->addWidget(logLine); + + _ui->logArea->updateGeometry(); + scrollToBottom(); +} diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h new file mode 100644 index 0000000000..ebc8aeb43b --- /dev/null +++ b/interface/src/ui/JSConsole.h @@ -0,0 +1,62 @@ +// +// JSConsole.h +// interface/src/ui +// +// Created by Ryan Huffman on 05/12/14. +// Copyright 2014 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 +// + +#ifndef hifi_JSConsole_h +#define hifi_JSConsole_h + +#include +#include +#include +#include + +#include "ui_console.h" +#include "ScriptEngine.h" + +class JSConsole : public QDialog { + Q_OBJECT +public: + JSConsole(QWidget* parent, ScriptEngine* scriptEngine = NULL); + ~JSConsole(); + +public slots: + void executeCommand(const QString& command); + +signals: + void commandExecuting(const QString& command); + void commandFinished(const QString& result); + +protected: + void setAndSelectCommand(const QString& command); + virtual bool eventFilter(QObject* sender, QEvent* event); + virtual void mouseReleaseEvent(QMouseEvent* event); + virtual void showEvent(QShowEvent* event); + +protected slots: + void scrollToBottom(); + void resizeTextInput(); + void handleEvalutationFinished(QScriptValue result, bool isException); + void handlePrint(const QString& message); + +private: + void appendMessage(const QString& gutter, const QString& message); + void setToNextCommandInHistory(); + void setToPreviousCommandInHistory(); + void resetCurrentCommandHistory(); + + Ui::Console* _ui; + int _currentCommandInHistory; + QList _commandHistory; + QString _rootCommand; + ScriptEngine* _scriptEngine; +}; + + +#endif // hifi_JSConsole_h From 1d7272cbbf5735cda554bffe829549eb6da88199 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 26 May 2014 10:18:04 -0700 Subject: [PATCH 09/77] Add console.ui interface file --- interface/ui/console.ui | 257 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 interface/ui/console.ui diff --git a/interface/ui/console.ui b/interface/ui/console.ui new file mode 100644 index 0000000000..2f5e6d235e --- /dev/null +++ b/interface/ui/console.ui @@ -0,0 +1,257 @@ + + + Console + + + + 0 + 0 + 1018 + 263 + + + + Dialog + + + QDialog { background: white } + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 1003 + 263 + + + + background-color: white; + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + background-color: white; + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16 + 0 + + + + + 16 + 16 + + + + + 75 + true + + + + background-color: white; font-weight: bold; color: blue; + + + > + + + + + + + + 0 + 0 + + + + + Courier New + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + Qt::TextEditorInteraction + + + + + + + + + + + + + + + + + + + + + From 422c2eac6733ddc83174396fd6d8550c988b70a8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 07:29:48 -0700 Subject: [PATCH 10/77] Update showConsole -> toggleConsole and change shortcut --- interface/src/Menu.cpp | 6 +++--- interface/src/Menu.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7e641fb069..cce8399491 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -229,9 +229,9 @@ Menu::Menu() : addActionToQMenuAndActionHash(toolsMenu, MenuOption::Console, - Qt::CTRL | Qt::Key_QuoteLeft, + Qt::CTRL | Qt::ALT | Qt::Key_J, this, - SLOT(showConsole())); + SLOT(toggleConsole())); QMenu* viewMenu = addMenu("View"); @@ -1230,7 +1230,7 @@ void Menu::toggleChat() { #endif } -void Menu::showConsole() { +void Menu::toggleConsole() { QMainWindow* mainWindow = Application::getInstance()->getWindow(); if (!_jsConsole) { _jsConsole = new JSConsole(mainWindow); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1aace5d83b..c9577e708e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -190,7 +190,7 @@ private slots: void showMetavoxelEditor(); void showScriptEditor(); void showChat(); - void showConsole(); + void toggleConsole(); void toggleChat(); void audioMuteToggled(); void namedLocationCreated(LocationManager::NamedLocationCreateResponse response); From b9248e0bbf7bfe9e57590ace44a7664d72207801 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 08:03:46 -0700 Subject: [PATCH 11/77] Update JSConsole to QWidget --- interface/src/Menu.cpp | 18 +++++++++++++++++- interface/src/Menu.h | 2 +- interface/src/ui/JSConsole.cpp | 2 +- interface/src/ui/JSConsole.h | 2 +- interface/ui/console.ui | 24 +++++++++++++----------- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index cce8399491..a924528c2b 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -72,6 +72,11 @@ const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; const float MUTE_RADIUS = 50; +const QString CONSOLE_TITLE = "Scripting Console"; +const float CONSOLE_WINDOW_OPACITY = 0.95; +const int CONSOLE_WIDTH = 800; +const int CONSOLE_HEIGHT = 200; + Menu::Menu() : _actionHash(), _audioJitterBufferSamples(0), @@ -1233,7 +1238,18 @@ void Menu::toggleChat() { void Menu::toggleConsole() { QMainWindow* mainWindow = Application::getInstance()->getWindow(); if (!_jsConsole) { - _jsConsole = new JSConsole(mainWindow); + QDialog* dialog = new QDialog(mainWindow, Qt::WindowStaysOnTopHint); + QVBoxLayout* layout = new QVBoxLayout(dialog); + dialog->setLayout(new QVBoxLayout(dialog)); + + dialog->resize(QSize(CONSOLE_WIDTH, CONSOLE_HEIGHT)); + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(new JSConsole(dialog)); + dialog->setWindowOpacity(CONSOLE_WINDOW_OPACITY); + dialog->setWindowTitle(CONSOLE_TITLE); + + _jsConsole = dialog; } _jsConsole->setVisible(!_jsConsole->isVisible()); } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c9577e708e..6b37791b45 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -245,7 +245,7 @@ private: QPointer _MetavoxelEditor; QPointer _ScriptEditor; QPointer _chatWindow; - JSConsole* _jsConsole; + QDialog* _jsConsole; OctreeStatsDialog* _octreeStatsDialog; LodToolsDialog* _lodToolsDialog; int _maxVoxels; diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index d0880cd50b..267be0bc6d 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -32,7 +32,7 @@ const QString GUTTER_ERROR = "
X
"; const QString GUTTER_PREVIOUS_COMMAND = "
<
"; JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : - QDialog(parent, Qt::WindowStaysOnTopHint), + QWidget(parent), _ui(new Ui::Console), _currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND), _commandHistory(), diff --git a/interface/src/ui/JSConsole.h b/interface/src/ui/JSConsole.h index ebc8aeb43b..f28132a1f5 100644 --- a/interface/src/ui/JSConsole.h +++ b/interface/src/ui/JSConsole.h @@ -20,7 +20,7 @@ #include "ui_console.h" #include "ScriptEngine.h" -class JSConsole : public QDialog { +class JSConsole : public QWidget { Q_OBJECT public: JSConsole(QWidget* parent, ScriptEngine* scriptEngine = NULL); diff --git a/interface/ui/console.ui b/interface/ui/console.ui index 2f5e6d235e..7c86ab3d8f 100644 --- a/interface/ui/console.ui +++ b/interface/ui/console.ui @@ -1,13 +1,13 @@ Console - + 0 0 - 1018 - 263 + 1055 + 205 @@ -75,8 +75,8 @@ 0 0 - 1003 - 263 + 1040 + 205 @@ -203,14 +203,14 @@ - background-color: white; font-weight: bold; color: blue; + background-color: white; font-weight: bold; color: rgb(169, 187, 195); > - + @@ -220,9 +220,14 @@ - Courier New + Inconsolata,Lucida Console,Andale Mono,Monaco + -1 + + font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; +font-size:14px + QFrame::NoFrame @@ -232,9 +237,6 @@ Qt::ScrollBarAlwaysOff - - Qt::TextEditorInteraction - From 9af0269151c55e07c453ffb2dba9f8ce12a87f44 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 08:05:56 -0700 Subject: [PATCH 12/77] Update console style --- interface/resources/styles/console.qss | 20 ++++++++++++++ interface/src/ui/JSConsole.cpp | 38 +++++++++++++------------- 2 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 interface/resources/styles/console.qss diff --git a/interface/resources/styles/console.qss b/interface/resources/styles/console.qss new file mode 100644 index 0000000000..c10e429cea --- /dev/null +++ b/interface/resources/styles/console.qss @@ -0,0 +1,20 @@ +* { + font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; + font-size: 14px; +} + +promptTextEdit { + color: rgb(117, 133, 140); +} + +promptTextEdit:!enabled { + color: rgba(0, 0, 0, 0.5); +} + +promptGutterLabel { + color: rgba(117, 133, 140); +} + +promptGutterLabel:!enabled { + color: rgba(0, 0, 0, 0.5); +} diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 267be0bc6d..59d2765812 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -21,15 +21,13 @@ const int NO_CURRENT_HISTORY_COMMAND = -1; const int MAX_HISTORY_SIZE = 64; -const QString ACTIVE_PROMPT_STYLESHEET = "color: rgb(0, 0, 255);"; -const QString INACTIVE_PROMPT_STYLESHEET = "color: rgba(0, 0, 0, 0.5);"; -const QString COMMAND_STYLE = "color: rgb(30, 141, 255);"; +const QString COMMAND_STYLE = "color: rgb(38, 106, 155);"; -const QString RESULT_ERROR_STYLE = "color: rgb(255, 0, 0);"; -const QString RESULT_SUCCESS_STYLE = "color: rgb(160, 160, 160);"; +const QString RESULT_SUCCESS_STYLE = "color: rgb(103, 115, 115);"; +const QString RESULT_ERROR_STYLE = "color: rgb(209, 59, 34);"; -const QString GUTTER_ERROR = "
X
"; -const QString GUTTER_PREVIOUS_COMMAND = "
<
"; +const QString GUTTER_PREVIOUS_COMMAND = "<"; +const QString GUTTER_ERROR = "X"; JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : QWidget(parent), @@ -38,8 +36,15 @@ JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : _commandHistory(), _scriptEngine(scriptEngine) { + QFile styleSheet(Application::resourcesPath() + "styles/console.qss"); + if (styleSheet.open(QIODevice::ReadOnly)) { + QDir::setCurrent(Application::resourcesPath()); + setStyleSheet(styleSheet.readAll()); + } + _ui->setupUi(this); _ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap); + _ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap); _ui->promptTextEdit->installEventFilter(this); connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom())); @@ -54,7 +59,7 @@ JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : this, SLOT(handleEvalutationFinished(QScriptValue, bool))); connect(_scriptEngine, SIGNAL(printedMessage(const QString&)), this, SLOT(handlePrint(const QString&))); - setWindowOpacity(0.95); + resizeTextInput(); } JSConsole::~JSConsole() { @@ -68,9 +73,8 @@ void JSConsole::executeCommand(const QString& command) { } _ui->promptTextEdit->setDisabled(true); - _ui->promptGutterLabel->setStyleSheet(INACTIVE_PROMPT_STYLESHEET); - appendMessage(">", "
" + command.toHtmlEscaped() + "
"); + appendMessage(">", "" + command.toHtmlEscaped() + ""); QMetaObject::invokeMethod(_scriptEngine, "evaluate", Q_ARG(const QString&, command)); @@ -79,7 +83,6 @@ void JSConsole::executeCommand(const QString& command) { void JSConsole::handleEvalutationFinished(QScriptValue result, bool isException) { _ui->promptTextEdit->setDisabled(false); - _ui->promptGutterLabel->setStyleSheet(ACTIVE_PROMPT_STYLESHEET); // Make sure focus is still on this window - some commands are blocking and can take awhile to execute. if (window()->isActiveWindow()) { @@ -88,7 +91,7 @@ void JSConsole::handleEvalutationFinished(QScriptValue result, bool isException) QString gutter = (isException || result.isError()) ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND; QString resultColor = (isException || result.isError()) ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE; - QString resultStr = "
" + result.toString().toHtmlEscaped()  + "
"; + QString resultStr = "" + result.toString().toHtmlEscaped() + ""; appendMessage(gutter, resultStr); } @@ -120,8 +123,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) { if (!command.isEmpty()) { QTextCursor cursor = _ui->promptTextEdit->textCursor(); - cursor.select(QTextCursor::Document); - cursor.removeSelectedText(); + _ui->promptTextEdit->clear(); executeCommand(command); } @@ -175,7 +177,7 @@ void JSConsole::resetCurrentCommandHistory() { } void JSConsole::resizeTextInput() { - _ui->promptTextEdit->setMaximumHeight(_ui->promptTextEdit->document()->size().height()); + _ui->promptTextEdit->setFixedHeight(_ui->promptTextEdit->document()->size().height()); _ui->promptTextEdit->updateGeometry(); } @@ -205,10 +207,8 @@ void JSConsole::appendMessage(const QString& gutter, const QString& message) { gutterLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); messageLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); - QFont font("Courier New"); - font.setStyleHint(QFont::Monospace); - gutterLabel->setFont(font); - messageLabel->setFont(font); + gutterLabel->setStyleSheet("font-size: 14px; font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;"); + messageLabel->setStyleSheet("font-size: 14px; font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;"); gutterLabel->setText(gutter); messageLabel->setText(message); From 4a0a9f8a3651a5ed6e19cd57eabd7855519f3d4b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 08:57:29 -0700 Subject: [PATCH 13/77] Update console style --- interface/resources/styles/console.qss | 8 ++++---- interface/src/ui/JSConsole.cpp | 10 +++++----- interface/ui/console.ui | 17 ++++++++--------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/interface/resources/styles/console.qss b/interface/resources/styles/console.qss index c10e429cea..9e8a3c0ad4 100644 --- a/interface/resources/styles/console.qss +++ b/interface/resources/styles/console.qss @@ -3,18 +3,18 @@ font-size: 14px; } -promptTextEdit { +#promptTextEdit { color: rgb(117, 133, 140); } -promptTextEdit:!enabled { +#promptTextEdit:!enabled { color: rgba(0, 0, 0, 0.5); } -promptGutterLabel { +#promptGutterLabel { color: rgba(117, 133, 140); } -promptGutterLabel:!enabled { +#promptGutterLabel:!enabled { color: rgba(0, 0, 0, 0.5); } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 59d2765812..87d2fb4860 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -36,17 +36,17 @@ JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : _commandHistory(), _scriptEngine(scriptEngine) { + _ui->setupUi(this); + _ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap); + _ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap); + _ui->promptTextEdit->installEventFilter(this); + QFile styleSheet(Application::resourcesPath() + "styles/console.qss"); if (styleSheet.open(QIODevice::ReadOnly)) { QDir::setCurrent(Application::resourcesPath()); setStyleSheet(styleSheet.readAll()); } - _ui->setupUi(this); - _ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap); - _ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap); - _ui->promptTextEdit->installEventFilter(this); - connect(_ui->scrollArea->verticalScrollBar(), SIGNAL(rangeChanged(int, int)), this, SLOT(scrollToBottom())); connect(_ui->promptTextEdit, SIGNAL(textChanged()), this, SLOT(resizeTextInput())); diff --git a/interface/ui/console.ui b/interface/ui/console.ui index 7c86ab3d8f..d4b0b2bc74 100644 --- a/interface/ui/console.ui +++ b/interface/ui/console.ui @@ -187,27 +187,30 @@ 16 - 0 + 23 16 - 16 + 23 - 75 - true + 50 + false - background-color: white; font-weight: bold; color: rgb(169, 187, 195); + padding: 0px 0 0 0; > + + Qt::PlainText +
@@ -224,10 +227,6 @@ -1 - - font-family: Inconsolata, Lucida Console, Andale Mono, Monaco; -font-size:14px - QFrame::NoFrame From 44c5e56a4bb6484725a34e1ad6251bf30faa6f73 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 14:09:53 -0700 Subject: [PATCH 14/77] Update JSConsole colors --- interface/resources/styles/console.qss | 8 ++++---- interface/src/ui/JSConsole.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/resources/styles/console.qss b/interface/resources/styles/console.qss index 9e8a3c0ad4..021d5d84e9 100644 --- a/interface/resources/styles/console.qss +++ b/interface/resources/styles/console.qss @@ -4,17 +4,17 @@ } #promptTextEdit { - color: rgb(117, 133, 140); + color: #425d72; } #promptTextEdit:!enabled { - color: rgba(0, 0, 0, 0.5); + color: #7f7f7f; } #promptGutterLabel { - color: rgba(117, 133, 140); + color: #a9bbc3; } #promptGutterLabel:!enabled { - color: rgba(0, 0, 0, 0.5); + color: #7f7f7f; } diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp index 87d2fb4860..921c571d44 100644 --- a/interface/src/ui/JSConsole.cpp +++ b/interface/src/ui/JSConsole.cpp @@ -21,13 +21,13 @@ const int NO_CURRENT_HISTORY_COMMAND = -1; const int MAX_HISTORY_SIZE = 64; -const QString COMMAND_STYLE = "color: rgb(38, 106, 155);"; +const QString COMMAND_STYLE = "color: #266a9b;"; -const QString RESULT_SUCCESS_STYLE = "color: rgb(103, 115, 115);"; -const QString RESULT_ERROR_STYLE = "color: rgb(209, 59, 34);"; +const QString RESULT_SUCCESS_STYLE = "color: #677373;"; +const QString RESULT_ERROR_STYLE = "color: #d13b22;"; -const QString GUTTER_PREVIOUS_COMMAND = "<"; -const QString GUTTER_ERROR = "X"; +const QString GUTTER_PREVIOUS_COMMAND = "<"; +const QString GUTTER_ERROR = "X"; JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) : QWidget(parent), From 6ef802621550b0a3d34bfe0dfcf831997f63f21b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 May 2014 14:10:09 -0700 Subject: [PATCH 15/77] Add console to script editor --- interface/src/ui/ScriptEditorWindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/ui/ScriptEditorWindow.cpp b/interface/src/ui/ScriptEditorWindow.cpp index 41732d18c6..3f63f0741b 100644 --- a/interface/src/ui/ScriptEditorWindow.cpp +++ b/interface/src/ui/ScriptEditorWindow.cpp @@ -27,6 +27,9 @@ #include "Application.h" #include "FlowLayout.h" +#include "JSConsole.h" + +const int CONSOLE_HEIGHT = 150; ScriptEditorWindow::ScriptEditorWindow() : _ScriptEditorWindowUI(new Ui::ScriptEditorWindow), @@ -48,6 +51,10 @@ ScriptEditorWindow::ScriptEditorWindow() : connect(new QShortcut(QKeySequence("Ctrl+S"), this), &QShortcut::activated, this,&ScriptEditorWindow::saveScriptClicked); connect(new QShortcut(QKeySequence("Ctrl+O"), this), &QShortcut::activated, this, &ScriptEditorWindow::loadScriptClicked); connect(new QShortcut(QKeySequence("F5"), this), &QShortcut::activated, this, &ScriptEditorWindow::toggleRunScriptClicked); + + QWidget* console = new JSConsole(this); + console->setFixedHeight(CONSOLE_HEIGHT); + this->layout()->addWidget(console); } ScriptEditorWindow::~ScriptEditorWindow() { From e89d33dc60f560042c35ec81db4074515ceb2833 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 27 May 2014 18:02:49 -0700 Subject: [PATCH 16/77] added if to not track ParticleErase packets --- .../src/octree/OctreeQueryNode.cpp | 14 +++++++ .../src/octree/OctreeQueryNode.h | 2 + .../src/octree/OctreeSendThread.cpp | 10 ++++- interface/src/Application.cpp | 7 +++- interface/src/voxels/VoxelPacketProcessor.cpp | 3 +- libraries/networking/src/LimitedNodeList.cpp | 38 +++++++++++++++++++ libraries/octree/src/OctreeSceneStats.cpp | 21 ++++++---- libraries/octree/src/OctreeSceneStats.h | 2 +- 8 files changed, 86 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index ede6dee5e3..f56a96d367 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -365,4 +365,18 @@ void OctreeQueryNode::dumpOutOfView() { void OctreeQueryNode::incrementSequenceNumber() { _sequenceNumber++; +} + +void OctreeQueryNode::updatePacketTimestamp() { + + int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_octreePacket), _myPacketType); + _octreePacketAt = _octreePacket + numBytesPacketHeader; + _octreePacketAt += sizeof(OCTREE_PACKET_FLAGS); + _octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE); + + // pack in timestamp + OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); + OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)_octreePacketAt; + *timeAt = now; + } \ No newline at end of file diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 1bb3a72a0c..a1a8aa4a66 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -101,6 +101,8 @@ public: bool isShuttingDown() const { return _isShuttingDown; } void incrementSequenceNumber(); + + void updatePacketTimestamp(); private slots: void sendThreadFinished(); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 8d6803adac..c98c8c77b8 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -142,12 +142,18 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes } const unsigned char* messageData = nodeData->getPacket(); +//unsigned char messageData[MAX_PACKET_SIZE]; +//memcpy(messageData, nodeData->getPacket(), MAX_PACKET_SIZE); // DEBUG: make copy of message to send + int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); const unsigned char* dataAt = messageData + numBytesPacketHeader; dataAt += sizeof(OCTREE_PACKET_FLAGS); OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + // If we've got a stats message ready to send, then see if we can piggyback them together if (nodeData->stats.isReadyToSend() && !nodeData->isShuttingDown()) { @@ -161,6 +167,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // copy voxel message to back of stats message memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); +//memcpy(statsMessage + statsMessageLength, messageData, nodeData->getPacketLength()); statsMessageLength += nodeData->getPacketLength(); // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since @@ -203,6 +210,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes OctreeServer::didCallWriteDatagram(this); NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); +//NodeList::getInstance()->writeDatagram((char*)messageData, nodeData->getPacketLength(), _node); packetSent = true; @@ -223,6 +231,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // just send the voxel packet OctreeServer::didCallWriteDatagram(this); NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); +//NodeList::getInstance()->writeDatagram((char*)messageData, nodeData->getPacketLength(), _node); packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); @@ -245,7 +254,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes nodeData->incrementSequenceNumber(); nodeData->resetOctreePacket(); } - return packetsSent; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 07309fab85..a8b56f360d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3301,7 +3301,12 @@ void Application::trackIncomingVoxelPacket(const QByteArray& packet, const Share _octreeSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); + if (stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec())) { + + // DEBUG! unreasonable flight time + qDebug() << " sending node type: " << NodeType::getNodeTypeName(sendingNode->getType()) << "\n"; + //qDebug() << "\t\t clock skew: " << sendingNode->getClockSkewUsec(); + } } _octreeSceneStatsLock.unlock(); } diff --git a/interface/src/voxels/VoxelPacketProcessor.cpp b/interface/src/voxels/VoxelPacketProcessor.cpp index c0f27264f6..d03eaf0946 100644 --- a/interface/src/voxels/VoxelPacketProcessor.cpp +++ b/interface/src/voxels/VoxelPacketProcessor.cpp @@ -39,7 +39,7 @@ void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, c } PacketType voxelPacketType = packetTypeForPacket(mutablePacket); - + // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA // immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first // then process any remaining bytes as if it was another packet @@ -81,6 +81,7 @@ void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, c if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { +if (voxelPacketType != PacketTypeParticleErase) app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket); if (sendingNode) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index c0d7941edf..68255bbd41 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -268,6 +268,44 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { + /* + QByteArray datagram(data, size); + + qDebug() << "\t writeDatagram()..."; + + PacketType type = packetTypeForPacket(datagram); + if (type != PacketType::PacketTypeParticleErase) { + + qDebug() << "\t\t type: " << (unsigned char)type; + qDebug() << "\t\t UUID: " << uuidFromPacketHeader(datagram); + qDebug() << "\t\t MD5: " << hashFromPacketHeader(datagram); + + + int numBytesPacketHeader = numBytesForPacketHeader(datagram); + const unsigned char* dataAt = reinterpret_cast(datagram.data()) + numBytesPacketHeader; + + unsigned char flags = (*(unsigned char*)(dataAt)); + dataAt += sizeof(unsigned char); + qDebug() << "\t\t flags: " << QString::number(flags, 2); + + uint16_t sequence = (*(uint16_t*)dataAt); + dataAt += sizeof(uint16_t); + qDebug() << "\t\t sequence: " << QString::number(sequence, 16); + + quint64 sentAt = (*(quint64*)dataAt); + dataAt += sizeof(quint64); + qDebug() << "\t\t sent at: " << QString::number(sentAt, 16) << "\n"; + } + else { + qDebug() << "size: " << size; + const char* dataAt = data; + for (int i = 0; i < size; i++) { + unsigned char byte = *((unsigned char*)dataAt); + dataAt += sizeof(unsigned char); + qDebug() << "\t\t " << QString::number(byte, 16); + } + }*/ + return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index c08e723f89..2b04b5652c 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -839,7 +839,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { return _itemValueBuffer; } -void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, +bool OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec) { const bool wantExtraDebugging = false; @@ -857,8 +857,8 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, //bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); //bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); - OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); - int flightTime = arrivedAt - sentAt + nodeClockSkewUsec; + OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); // DEBUG!!! + qint64 flightTime = arrivedAt - sentAt + nodeClockSkewUsec; if (wantExtraDebugging) { qDebug() << "sentAt:" << sentAt << " usecs"; @@ -866,13 +866,20 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; qDebug() << "flightTime:" << flightTime << " usecs"; } - + + +//qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; + // Guard against possible corrupted packets... with bad timestamps const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive const int MIN_RESONABLE_FLIGHT_TIME = 0; if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime; - return; // ignore any packets that are unreasonable +qDebug() << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; +qDebug() << "\t arrivedAt:" << QString::number(arrivedAt, 16) << " usecs"; +qDebug() << "\t nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; +qDebug() << "\t flightTime:" << flightTime << " usecs"; + return true; // ignore any packets that are unreasonable } // determine our expected sequence number... handle rollover appropriately @@ -884,7 +891,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, int sequenceOffset = (sequence - expected); if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) { qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence; - return; // ignore any packets that are unreasonable + return false; // ignore any packets that are unreasonable } // track packets here... @@ -985,6 +992,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, } } } - + return false; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index ef22fd7c1c..dd0b31b010 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -158,7 +158,7 @@ public: quint64 getLastFullTotalBytes() const { return _lastFullTotalBytes; } // Used in client implementations to track individual octree packets - void trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec); + bool trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec); quint32 getIncomingPackets() const { return _incomingPacket; } quint64 getIncomingBytes() const { return _incomingBytes; } From f361b9a8a7b91e44a260e5db450b4e181ba2ad81 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 27 May 2014 18:04:53 -0700 Subject: [PATCH 17/77] removed updatePacketTimestamp() ..from OctreeQueryNode --- assignment-client/src/octree/OctreeQueryNode.cpp | 14 -------------- assignment-client/src/octree/OctreeQueryNode.h | 2 -- 2 files changed, 16 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f56a96d367..a5f89dc71b 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -366,17 +366,3 @@ void OctreeQueryNode::dumpOutOfView() { void OctreeQueryNode::incrementSequenceNumber() { _sequenceNumber++; } - -void OctreeQueryNode::updatePacketTimestamp() { - - int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_octreePacket), _myPacketType); - _octreePacketAt = _octreePacket + numBytesPacketHeader; - _octreePacketAt += sizeof(OCTREE_PACKET_FLAGS); - _octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE); - - // pack in timestamp - OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); - OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)_octreePacketAt; - *timeAt = now; - -} \ No newline at end of file diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index a1a8aa4a66..1bb3a72a0c 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -101,8 +101,6 @@ public: bool isShuttingDown() const { return _isShuttingDown; } void incrementSequenceNumber(); - - void updatePacketTimestamp(); private slots: void sendThreadFinished(); From 8b0212dc1eb3ca7c46dc7130819fc7d25fd9850f Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Wed, 28 May 2014 23:19:15 +0530 Subject: [PATCH 18/77] remove all key bindings from running scripts dialog --- interface/src/ui/RunningScriptsWidget.cpp | 34 ++++------------------- interface/ui/runningScriptsWidget.ui | 2 +- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 328974dc9d..9bef454829 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -106,36 +106,12 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) { createRecentlyLoadedScriptsTable(); } -void RunningScriptsWidget::keyPressEvent(QKeyEvent* event) -{ - int loadScriptNumber = -1; - switch(event->key()) { - case Qt::Key_Escape: - Application::getInstance()->toggleRunningScriptsWidget(); - break; - - case Qt::Key_1: - case Qt::Key_2: - case Qt::Key_3: - case Qt::Key_4: - case Qt::Key_5: - case Qt::Key_6: - case Qt::Key_7: - case Qt::Key_8: - case Qt::Key_9: - loadScriptNumber = event->key() - Qt::Key_1; - break; - - default: - break; +void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) { + if (keyEvent->key() == Qt::Key_Escape) { + return; + } else { + FramelessDialog::keyPressEvent(keyEvent); } - if (loadScriptNumber >= 0) { - if (_recentlyLoadedScripts.size() > loadScriptNumber) { - Application::getInstance()->loadScript(_recentlyLoadedScripts.at(loadScriptNumber)); - } - } - - FramelessDialog::keyPressEvent(event); } void RunningScriptsWidget::paintEvent(QPaintEvent* event) { diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index cb0106cd48..6cb23f4c89 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -143,7 +143,7 @@ font: bold 14pt; font-size: 14pt; - (click a script or use the 1-9 keys to load and run it) + (click a script to load and run it) true From 9311eeb8f5913619b830bde3158ce4e1b313c4dc Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 28 May 2014 14:41:30 -0700 Subject: [PATCH 19/77] Fixed compiler warning --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fac0ef154f..570bdb8167 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -162,10 +162,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _bytesPerSecond(0), _nodeBoundsDisplay(this), _previousScriptLocation(), + _applicationOverlay(), _runningScriptsWidget(new RunningScriptsWidget(_window)), _runningScriptsWidgetWasVisible(false), - _trayIcon(new QSystemTrayIcon(_window)), - _applicationOverlay() + _trayIcon(new QSystemTrayIcon(_window)) { // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); From c3f6cab19913921dc2668cf1a40dedff5d177bb9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 15:20:09 -0700 Subject: [PATCH 20/77] Working on cascading shadow maps. --- interface/resources/shaders/shadow_map.frag | 12 +- interface/resources/shaders/shadow_map.vert | 10 +- interface/src/Application.cpp | 150 +++++++++++--------- interface/src/Application.h | 6 +- interface/src/renderer/Model.cpp | 9 +- interface/src/voxels/VoxelSystem.cpp | 10 +- 6 files changed, 108 insertions(+), 89 deletions(-) diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index fb3474d9ef..f53c66b095 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,15 +13,11 @@ uniform sampler2DShadow shadowMap; -// the inverse of the size of the shadow map -const float shadowScale = 1.0 / 2048.0; - varying vec4 shadowColor; void main(void) { - gl_FragColor = mix(shadowColor, gl_Color, 0.25 * - (shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r + - shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp).r * + shadow2D(shadowMap, gl_TexCoord[1].stp).r * + shadow2D(shadowMap, gl_TexCoord[2].stp).r * + shadow2D(shadowMap, gl_TexCoord[3].stp).r); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index abe5f99b44..e7efcd7c0f 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -21,10 +21,16 @@ void main(void) { vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); - // generate the shadow texture coordinate using the eye position + // generate the shadow texture coordinates using the eye position vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), - dot(gl_EyePlaneR[0], eyePosition), 1.0); + dot(gl_EyePlaneR[0], eyePosition), 1.0); + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[1], eyePosition), dot(gl_EyePlaneT[1], eyePosition), + dot(gl_EyePlaneR[1], eyePosition), 1.0); + gl_TexCoord[2] = vec4(dot(gl_EyePlaneS[2], eyePosition), dot(gl_EyePlaneT[2], eyePosition), + dot(gl_EyePlaneR[2], eyePosition), 1.0); + gl_TexCoord[3] = vec4(dot(gl_EyePlaneS[3], eyePosition), dot(gl_EyePlaneT[3], eyePosition), + dot(gl_EyePlaneR[3], eyePosition), 1.0); // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fac0ef154f..a1c2507822 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2256,94 +2256,104 @@ void Application::updateShadowMap() { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, fbo->width(), fbo->height()); - glm::vec3 lightDirection = -getSunDirection(); glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); - float nearScale = 0.0f; - const float MAX_SHADOW_DISTANCE = 2.0f; - float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / - (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); - loadViewFrustum(_myCamera, _viewFrustum); - glm::vec3 points[] = { - glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), - glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), - glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), - glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), - glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), - glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), - glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), - glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; - glm::vec3 center; - for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { - center += points[i]; - } - center /= (float)(sizeof(points) / sizeof(points[0])); - float radius = 0.0f; - for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { - radius = qMax(radius, glm::distance(points[i], center)); - } - center = inverseRotation * center; - // to reduce texture "shimmer," move in texel increments - float texelSize = (2.0f * radius) / fbo->width(); - center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, - roundf(center.z / texelSize) * texelSize); + const float MAP_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; + const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), + glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; - glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); - glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); + int halfSize = fbo->width() / 2; + float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); + + for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { + const glm::vec2& coord = MAP_COORDS[i]; + glViewport(coord.s * halfSize, coord.t * halfSize, halfSize, halfSize); - // stretch out our extents in z so that we get all of the avatars - minima.z -= _viewFrustum.getFarClip() * 0.5f; - maxima.z += _viewFrustum.getFarClip() * 0.5f; + float nearScale = MAP_DISTANCES[i] * frustumScale; + float farScale = MAP_DISTANCES[i + 1] * frustumScale; + loadViewFrustum(_myCamera, _viewFrustum); + glm::vec3 points[] = { + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; + glm::vec3 center; + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { + center += points[j]; + } + center /= (float)(sizeof(points) / sizeof(points[0])); + float radius = 0.0f; + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { + radius = qMax(radius, glm::distance(points[j], center)); + } + center = inverseRotation * center; + + // to reduce texture "shimmer," move in texel increments + float texelSize = (2.0f * radius) / halfSize; + center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, + roundf(center.z / texelSize) * texelSize); + + glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); + glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); - // save the combined matrix for rendering - _shadowMatrix = glm::transpose(glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * - glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); + // stretch out our extents in z so that we get all of the avatars + minima.z -= _viewFrustum.getFarClip() * 0.5f; + maxima.z += _viewFrustum.getFarClip() * 0.5f; - // update the shadow view frustum - _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); - _shadowViewFrustum.setOrientation(rotation); - _shadowViewFrustum.setOrthographic(true); - _shadowViewFrustum.setWidth(maxima.x - minima.x); - _shadowViewFrustum.setHeight(maxima.y - minima.y); - _shadowViewFrustum.setNearClip(minima.z); - _shadowViewFrustum.setFarClip(maxima.z); - _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); - _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); - _shadowViewFrustum.calculate(); + // save the combined matrix for rendering + _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * glm::scale(glm::vec3(0.5f, 0.5f, 1.0f)) * + glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * + glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); + // update the shadow view frustum + _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); + _shadowViewFrustum.setOrientation(rotation); + _shadowViewFrustum.setOrthographic(true); + _shadowViewFrustum.setWidth(maxima.x - minima.x); + _shadowViewFrustum.setHeight(maxima.y - minima.y); + _shadowViewFrustum.setNearClip(minima.z); + _shadowViewFrustum.setFarClip(maxima.z); + _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); + _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); + _shadowViewFrustum.calculate(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glm::vec3 axis = glm::axis(inverseRotation); - glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); - // store view matrix without translation, which we'll use for precision-sensitive objects - updateUntranslatedViewMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glm::vec3 axis = glm::axis(inverseRotation); + glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt + // store view matrix without translation, which we'll use for precision-sensitive objects + updateUntranslatedViewMatrix(); - _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); - _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); - _models.render(OctreeRenderer::SHADOW_RENDER_MODE); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt - glDisable(GL_POLYGON_OFFSET_FILL); + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); + _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); + _models.render(OctreeRenderer::SHADOW_RENDER_MODE); - glPopMatrix(); + glDisable(GL_POLYGON_OFFSET_FILL); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); + glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + fbo->release(); glViewport(0, 0, _glWidget->width(), _glWidget->height()); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0065944611..5d29a9057a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,6 +126,8 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; +static const int SHADOW_MATRIX_COUNT = 4; + class Application : public QApplication { Q_OBJECT @@ -261,7 +263,7 @@ public: /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); - const glm::mat4& getShadowMatrix() const { return _shadowMatrix; } + const glm::mat4* getShadowMatrices() const { return _shadowMatrices; } void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); @@ -491,7 +493,7 @@ private: float _rotateMirror; float _raiseMirror; - glm::mat4 _shadowMatrix; + glm::mat4 _shadowMatrices[SHADOW_MATRIX_COUNT]; Environment _environment; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 678a4b09c0..7c9ba50346 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1509,9 +1509,12 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const QVector& networkMeshes = _geometry->getMeshes(); if (receiveShadows) { - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); + for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); + } } for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 8937cef7dd..4f1b322455 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -1490,10 +1490,12 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { _shadowMapProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); - + for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); + } } else if (texture) { _perlinModulateProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); From 8f6ad2faabf0317a1bd1bab3cfb580b1b11f182b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 28 May 2014 15:27:50 -0700 Subject: [PATCH 21/77] Add 'Load default scripts' button to preferences --- interface/src/Application.cpp | 10 +++- interface/src/Application.h | 1 + interface/src/ui/PreferencesDialog.cpp | 2 + interface/ui/preferencesDialog.ui | 82 ++++++++++++++++++++++++-- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fac0ef154f..d2b05f2cc4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -105,6 +105,8 @@ const int STARTUP_JITTER_SAMPLES = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / 2 const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml"; const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; +const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.size() > 0) { QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate); @@ -362,7 +364,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : qDebug() << "This is a first run..."; // clear the scripts, and set out script to our default scripts clearScriptsBeforeRunning(); - loadScript("http://public.highfidelity.io/scripts/defaultScripts.js"); + loadScript(DEFAULT_SCRIPTS_JS_URL); QMutexLocker locker(&_settingsMutex); _settings->setValue("firstRun",QVariant(false)); @@ -3362,6 +3364,12 @@ void Application::reloadAllScripts() { stopAllScripts(true); } +void Application::loadDefaultScripts() { + if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) { + loadScript(DEFAULT_SCRIPTS_JS_URL); + } +} + void Application::manageRunningScriptsWidgetVisibility(bool shown) { if (_runningScriptsWidgetWasVisible && shown) { _runningScriptsWidget->show(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0065944611..0d4f1c89d6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -328,6 +328,7 @@ public slots: void stopAllScripts(bool restart = false); void stopScript(const QString& scriptName); void reloadAllScripts(); + void loadDefaultScripts(); void toggleRunningScriptsWidget(); void uploadHead(); diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index ed2d7097db..d5c6079d4b 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -29,6 +29,8 @@ PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : F connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser); connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser); connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser); + connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, + Application::getInstance(), &Application::loadDefaultScripts); } void PreferencesDialog::accept() { diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index bab431160d..a1c2073ab6 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -134,8 +134,8 @@ color: #0e7077 0 30 - 615 - 491 + 494 + 384 @@ -154,9 +154,9 @@ color: #0e7077 0 - -271 - 598 - 1018 + -204 + 494 + 1091 @@ -612,6 +612,78 @@ color: #0e7077 + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Scripts + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + 0 + 0 + + + + background: #0e7077; +color: #fff; +border-radius: 4px; +font: bold 14pt; +padding: 10px;margin-top:10px + + + Load Default Scripts + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + From e6d12bf239f3abec108abbab45aafc3f073abd7a Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 28 May 2014 15:56:14 -0700 Subject: [PATCH 22/77] Disabled overlay for oculus. We still have to call applicationOverlay.renderOverlay(true) or prioVR cant calibrate. --- interface/src/devices/OculusManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 8f71d38bdb..af18db4006 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -83,7 +83,9 @@ void OculusManager::display(Camera& whichCamera) { #ifdef HAVE_LIBOVR ApplicationOverlay& applicationOverlay = Application::getInstance()->getApplicationOverlay(); // We only need to render the overlays to a texture once, then we just render the texture as a quad + // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); + const bool displayOverlays = false; Application::getInstance()->getGlowEffect()->prepare(); @@ -104,7 +106,9 @@ void OculusManager::display(Camera& whichCamera) { Application::getInstance()->displaySide(whichCamera); - applicationOverlay.displayOverlayTextureOculus(whichCamera); + if (displayOverlays) { + applicationOverlay.displayOverlayTextureOculus(whichCamera); + } // and the right eye to the right side const StereoEyeParams& rightEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Right); @@ -121,7 +125,9 @@ void OculusManager::display(Camera& whichCamera) { Application::getInstance()->displaySide(whichCamera); - applicationOverlay.displayOverlayTextureOculus(whichCamera); + if (displayOverlays) { + applicationOverlay.displayOverlayTextureOculus(whichCamera); + } glPopMatrix(); From 8cd101ac57a3cdeae4f253477e3a5fde04bdbd11 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 15:57:38 -0700 Subject: [PATCH 23/77] Added getJointCombinedRotation to Models --- interface/src/renderer/Model.cpp | 12 ++++++++++-- interface/src/renderer/Model.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 678a4b09c0..91c14d7758 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -641,8 +641,16 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return false; } rotation = _jointStates[jointIndex].combinedRotation * - (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : - _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : + _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + return true; +} + +bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { + if (jointIndex == -1 || _jointStates.isEmpty()) { + return false; + } + rotation = _jointStates[jointIndex].combinedRotation; return true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index a4e45287dd..91429a3677 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -123,6 +123,7 @@ public: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; + bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; QStringList getJointNames() const; From 698ecbf9c5ab7f4c7719ee812159a1a7f9b0e613 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 15:58:45 -0700 Subject: [PATCH 24/77] Fix for shadow map rendering. --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a1c2507822..0cae0f3e75 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2266,14 +2266,14 @@ void Application::updateShadowMap() { int halfSize = fbo->width() / 2; float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); + loadViewFrustum(_myCamera, _viewFrustum); for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { const glm::vec2& coord = MAP_COORDS[i]; - glViewport(coord.s * halfSize, coord.t * halfSize, halfSize, halfSize); + glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); float nearScale = MAP_DISTANCES[i] * frustumScale; float farScale = MAP_DISTANCES[i + 1] * frustumScale; - loadViewFrustum(_myCamera, _viewFrustum); glm::vec3 points[] = { glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), From b4deed775e224d99e1f8b19d1a59e16ba9d2c392 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 15:59:42 -0700 Subject: [PATCH 25/77] Added joints position and combined rotation to scripting interface --- interface/src/avatar/Avatar.cpp | 25 +++++++++++++++++++++++++ interface/src/avatar/Avatar.h | 7 ++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 306dc0194e..55c0830dfb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -705,6 +705,30 @@ QStringList Avatar::getJointNames() const { return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointNames() : QStringList(); } +glm::vec3 Avatar::getJointPosition(int index) const { + glm::vec3 position(0,0,0); + _skeletonModel.getJointPosition(index, position); + return position; +} + +glm::vec3 Avatar::getJointPosition(const QString& name) const { + glm::vec3 position(0,0,0); + _skeletonModel.getJointPosition(getJointIndex(name), position); + return position; +} + +glm::quat Avatar::getJointCombinedRotation(int index) const { + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(index, rotation); + return rotation; +} + +glm::quat Avatar::getJointCombinedRotation(const QString& name) const { + glm::quat rotation; + _skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation); + return rotation; +} + void Avatar::setFaceModelURL(const QUrl& faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(Application::resourcesPath() + "meshes/defaultAvatar_head.fst"); @@ -725,6 +749,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // make sure we have as many models as attachments while (_attachmentModels.size() < attachmentData.size()) { Model* model = new Model(this); + model->setSnapModelToCenter(true); model->init(); _attachmentModels.append(model); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index db13656546..f928881068 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -152,7 +152,12 @@ public: quint32 getCollisionGroups() const { return _collisionGroups; } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } - + + Q_INVOKABLE glm::vec3 getJointPosition(int index) const; + Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const; + Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const; + public slots: void updateCollisionGroups(); From 372ddc92fdd27de5c5adb0c634eb97a70a068a5f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 28 May 2014 16:00:37 -0700 Subject: [PATCH 26/77] Added attaching of model to MyAvatar when close enough --- examples/editModels.js | 109 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 30d1e4edf4..cf9b9abbdc 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,6 +40,17 @@ var modelURLs = [ var toolBar; + +var jointList = MyAvatar.getJointNames(); +//print("\n# Joint list start"); +//for (var i = 0; i < jointList.length; i++) { +// Vec3.print("jointIndex = " + jointList[i] + " = " + i, MyAvatar.getJointPosition(jointList[i])); +//} +//print("# Joint list end"); + + + + function isLocked(properties) { // special case to lock the ground plane model in hq. if (location.hostname == "hq.highfidelity.io" && @@ -81,6 +92,7 @@ function controller(wichSide) { this.grabbing = false; this.modelID = { isKnownID: false }; + this.modelURL = ""; this.oldModelRotation; this.oldModelPosition; this.oldModelRadius; @@ -134,6 +146,7 @@ function controller(wichSide) { this.grabbing = true; this.modelID = modelID; + this.modelURL = properties.modelURL; this.oldModelPosition = properties.position; this.oldModelRotation = properties.modelRotation; @@ -142,6 +155,39 @@ function controller(wichSide) { } this.release = function () { + if (this.grabbing) { + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } + + print("closestJointIndex: " + closestJointIndex); + print("closestJointDistance: " + closestJointDistance); + + if (closestJointDistance < 0.1) { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.multiply(Vec3.subtract(this.oldModelPosition, jointPosition), 2); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 0.75, + true, false); + Vec3.print("offset: ", attachmentOffset); + Vec3.print("joint: ", Quat.safeEulerAngles(jointRotation)); + Vec3.print("model: ", Quat.safeEulerAngles(this.oldModelRotation)); + Vec3.print("delta: ", Quat.safeEulerAngles(attachmentRotation)); + } + } + this.grabbing = false; this.modelID.isKnownID = false; } @@ -259,6 +305,20 @@ function controller(wichSide) { this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; + + + var closestJointIndex = -1; + var closestJointDistance = 10; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), newPosition); + if (distance < closestJointDistance) { + closestJointDistance = distance; + closestJointIndex = i; + } + } +// +// print("closestJointIndex: " + closestJointIndex); +// print("closestJointDistance: " + closestJointDistance); } } @@ -408,8 +468,51 @@ function checkController(deltaTime) { } moveOverlays(); + + + + leftController.hideLaser(); + rightController.hideLaser(); + var jointPos = MyAvatar.getJointPosition("RightHand"); + var jointRot = MyAvatar.getJointCombinedRotation("RightHand"); + + Overlays.editOverlay(r, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:1, y:0, z:0 })) + }); + Overlays.editOverlay(g, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:1, z:0 })) + }); + Overlays.editOverlay(b, { + position: jointPos, + end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:0, z:1 })) + }); } - +var r = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 255, green: 0, blue: 0 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); +var g = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 255, blue: 0 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); +var b = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 0, blue: 255 }, + alpha: 1, + visible: true, + lineWidth: LASER_WIDTH + }); function initToolBar() { @@ -686,6 +789,10 @@ function scriptEnding() { rightController.cleanup(); toolBar.cleanup(); cleanupModelMenus(); + + Overlays.deleteOverlay(r); + Overlays.deleteOverlay(g); + Overlays.deleteOverlay(b); } Script.scriptEnding.connect(scriptEnding); From 81ed0d99f77e0377a596e8e779569ce8d83e3f80 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 28 May 2014 17:13:59 -0700 Subject: [PATCH 27/77] Added prediction for Oculus rift to reduce apparent latency. --- interface/src/devices/OculusManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index af18db4006..c8b2d0dcbc 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -50,7 +50,8 @@ void OculusManager::connect() { _sensorDevice = *_hmdDevice->GetSensor(); _sensorFusion = new SensorFusion; _sensorFusion->AttachToSensor(_sensorDevice); - + _sensorFusion->SetPredictionEnabled(true); + HMDInfo info; _hmdDevice->GetDeviceInfo(&info); _stereoConfig.SetHMDInfo(info); @@ -201,7 +202,7 @@ void OculusManager::reset() { void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { #ifdef HAVE_LIBOVR - _sensorFusion->GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); + _sensorFusion->GetPredictedOrientation().GetEulerAngles(&yaw, &pitch, &roll); #endif } From c7990773790e4f00fd02e30e8eb13b7ea0171508 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 28 May 2014 17:20:10 -0700 Subject: [PATCH 28/77] added flag,seq,ts to ParticleErase and ModelErase ... this fixes unreasonable flight-time issue --- assignment-client/src/models/ModelServer.cpp | 5 +-- assignment-client/src/models/ModelServer.h | 2 +- .../src/octree/OctreeQueryNode.cpp | 11 ++++--- .../src/octree/OctreeQueryNode.h | 6 ++-- .../src/octree/OctreeSendThread.cpp | 20 ++++++------ .../src/octree/OctreeSendThread.h | 2 ++ assignment-client/src/octree/OctreeServer.h | 2 +- .../src/particles/ParticleServer.cpp | 5 +-- .../src/particles/ParticleServer.h | 2 +- assignment-client/src/voxels/VoxelServer.cpp | 5 ++- assignment-client/src/voxels/VoxelServer.h | 2 +- interface/src/voxels/VoxelPacketProcessor.cpp | 2 +- libraries/models/src/ModelTree.cpp | 29 +++++++++++++++-- libraries/models/src/ModelTree.h | 2 +- libraries/networking/src/LimitedNodeList.cpp | 32 +++++++++---------- libraries/octree/src/OctreeSceneStats.cpp | 2 +- libraries/particles/src/ParticleTree.cpp | 27 ++++++++++++++-- libraries/particles/src/ParticleTree.h | 2 +- 18 files changed, 106 insertions(+), 52 deletions(-) diff --git a/assignment-client/src/models/ModelServer.cpp b/assignment-client/src/models/ModelServer.cpp index a71c98ed83..8f322e4c82 100644 --- a/assignment-client/src/models/ModelServer.cpp +++ b/assignment-client/src/models/ModelServer.cpp @@ -86,7 +86,7 @@ bool ModelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedModels; } -int ModelServer::sendSpecialPacket(const SharedNodePointer& node) { +int ModelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -100,12 +100,13 @@ int ModelServer::sendSpecialPacket(const SharedNodePointer& node) { // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 models? while (hasMoreToSend) { - hasMoreToSend = tree->encodeModelsDeletedSince(deletedModelsSentAt, + hasMoreToSend = tree->encodeModelsDeletedSince(sequenceNumber, deletedModelsSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); //qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); + sequenceNumber++; } nodeData->setLastDeletedModelsSentAt(deletePacketSentAt); diff --git a/assignment-client/src/models/ModelServer.h b/assignment-client/src/models/ModelServer.h index c2ca6d1f5b..35cb79d8cf 100644 --- a/assignment-client/src/models/ModelServer.h +++ b/assignment-client/src/models/ModelServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(const SharedNodePointer& node); + virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index a5f89dc71b..ea15770f9e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -38,7 +38,7 @@ OctreeQueryNode::OctreeQueryNode() : _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false), - _sequenceNumber(0), + //_sequenceNumber(0), _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), _isShuttingDown(false) @@ -158,11 +158,11 @@ bool OctreeQueryNode::shouldSuppressDuplicatePacket() { void OctreeQueryNode::init() { _myPacketType = getMyPacketType(); - resetOctreePacket(); // don't bump sequence + resetOctreePacket(0); // don't bump sequence } -void OctreeQueryNode::resetOctreePacket() { +void OctreeQueryNode::resetOctreePacket(OCTREE_PACKET_SEQUENCE sequenceNumber) { // if shutting down, return immediately if (_isShuttingDown) { return; @@ -200,7 +200,7 @@ void OctreeQueryNode::resetOctreePacket() { // pack in sequence number OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)_octreePacketAt; - *sequenceAt = _sequenceNumber; + *sequenceAt = sequenceNumber; _octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE); _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_SEQUENCE); @@ -362,7 +362,8 @@ void OctreeQueryNode::dumpOutOfView() { } } } - +/* void OctreeQueryNode::incrementSequenceNumber() { _sequenceNumber++; } +*/ diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 1bb3a72a0c..af293189a4 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -35,7 +35,7 @@ public: void init(); // called after creation to set up some virtual items virtual PacketType getMyPacketType() const = 0; - void resetOctreePacket(); // resets octree packet to after "V" header + void resetOctreePacket(OCTREE_PACKET_SEQUENCE sequenceNumber); // resets octree packet to after "V" header void writeToPacket(const unsigned char* buffer, unsigned int bytes); // writes to end of packet @@ -100,7 +100,7 @@ public: void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } - void incrementSequenceNumber(); + //void incrementSequenceNumber(); private slots: void sendThreadFinished(); @@ -138,7 +138,7 @@ private: bool _lodChanged; bool _lodInitialized; - OCTREE_PACKET_SEQUENCE _sequenceNumber; + //OCTREE_PACKET_SEQUENCE _sequenceNumber; quint64 _lastRootTimestamp; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index c98c8c77b8..dca18026a1 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -28,7 +28,8 @@ OctreeSendThread::OctreeSendThread(const SharedAssignmentPointer& myAssignment, _nodeUUID(node->getUUID()), _packetData(), _nodeMissingCount(0), - _isShuttingDown(false) + _isShuttingDown(false), + _sequenceNumber(0) { QString safeServerName("Octree"); if (_myServer) { @@ -137,7 +138,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. if (nodeData->shouldSuppressDuplicatePacket()) { - nodeData->resetOctreePacket(); // we still need to reset it though! + nodeData->resetOctreePacket(_sequenceNumber); // we still need to reset it though! return packetsSent; // without sending... } @@ -163,11 +164,10 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int piggyBackSize = nodeData->getPacketLength() + statsMessageLength; // If the size of the stats message and the voxel message will fit in a packet, then piggyback them - if (piggyBackSize < MAX_PACKET_SIZE) { +if (piggyBackSize < MAX_PACKET_SIZE && false) { // copy voxel message to back of stats message memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); -//memcpy(statsMessage + statsMessageLength, messageData, nodeData->getPacketLength()); statsMessageLength += nodeData->getPacketLength(); // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since @@ -210,7 +210,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes OctreeServer::didCallWriteDatagram(this); NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); -//NodeList::getInstance()->writeDatagram((char*)messageData, nodeData->getPacketLength(), _node); packetSent = true; @@ -231,7 +230,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // just send the voxel packet OctreeServer::didCallWriteDatagram(this); NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node); -//NodeList::getInstance()->writeDatagram((char*)messageData, nodeData->getPacketLength(), _node); packetSent = true; int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); @@ -251,8 +249,8 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes trueBytesSent += nodeData->getPacketLength(); truePacketsSent++; packetsSent++; - nodeData->incrementSequenceNumber(); - nodeData->resetOctreePacket(); + _sequenceNumber++; + nodeData->resetOctreePacket(_sequenceNumber); } return packetsSent; } @@ -291,7 +289,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->isPacketWaiting()) { packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); } else { - nodeData->resetOctreePacket(); + nodeData->resetOctreePacket(_sequenceNumber); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (wantCompression) { @@ -537,7 +535,9 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets if (_myServer->hasSpecialPacketToSend(_node) && !nodeData->isShuttingDown()) { - trueBytesSent += _myServer->sendSpecialPacket(_node); +qDebug() << "sending special packet..."; + trueBytesSent += _myServer->sendSpecialPacket(_sequenceNumber, _node); + nodeData->resetOctreePacket(_sequenceNumber); // because _sequenceNumber has changed truePacketsSent++; packetsSentThisInterval++; } diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index d8eed27802..9dcf266cd8 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -55,6 +55,8 @@ private: int _nodeMissingCount; bool _isShuttingDown; + + OCTREE_PACKET_SEQUENCE _sequenceNumber; }; #endif // hifi_OctreeSendThread_h diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index ff62561c58..df8519e200 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -72,7 +72,7 @@ public: // subclass may implement these method virtual void beforeRun() { }; virtual bool hasSpecialPacketToSend(const SharedNodePointer& node) { return false; } - virtual int sendSpecialPacket(const SharedNodePointer& node) { return 0; } + virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { return 0; } static void attachQueryNodeToNode(Node* newNode); diff --git a/assignment-client/src/particles/ParticleServer.cpp b/assignment-client/src/particles/ParticleServer.cpp index 649ee0cff9..e752900059 100644 --- a/assignment-client/src/particles/ParticleServer.cpp +++ b/assignment-client/src/particles/ParticleServer.cpp @@ -86,7 +86,7 @@ bool ParticleServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedParticles; } -int ParticleServer::sendSpecialPacket(const SharedNodePointer& node) { +int ParticleServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -100,12 +100,13 @@ int ParticleServer::sendSpecialPacket(const SharedNodePointer& node) { // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles? while (hasMoreToSend) { - hasMoreToSend = tree->encodeParticlesDeletedSince(deletedParticlesSentAt, + hasMoreToSend = tree->encodeParticlesDeletedSince(sequenceNumber, deletedParticlesSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); //qDebug() << "sending PacketType_PARTICLE_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); + sequenceNumber++; } nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt); diff --git a/assignment-client/src/particles/ParticleServer.h b/assignment-client/src/particles/ParticleServer.h index 1e0bb1b967..cb8e128475 100644 --- a/assignment-client/src/particles/ParticleServer.h +++ b/assignment-client/src/particles/ParticleServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(const SharedNodePointer& node); + virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 7747b8336b..1251358320 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -40,7 +40,10 @@ bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendEnvironments; } -int VoxelServer::sendSpecialPacket(const SharedNodePointer& node) { +int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequence, const SharedNodePointer& node) { + + // TODO: add flags, seq, timestamp to packet + int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_tempOutputBuffer), PacketTypeEnvironmentData); int envPacketLength = numBytesPacketHeader; int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h index bec60cadfe..8fba2e9d69 100644 --- a/assignment-client/src/voxels/VoxelServer.h +++ b/assignment-client/src/voxels/VoxelServer.h @@ -46,7 +46,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(const SharedNodePointer& node); + virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequence, const SharedNodePointer& node); private: bool _sendEnvironments; diff --git a/interface/src/voxels/VoxelPacketProcessor.cpp b/interface/src/voxels/VoxelPacketProcessor.cpp index d03eaf0946..11e62b0fe3 100644 --- a/interface/src/voxels/VoxelPacketProcessor.cpp +++ b/interface/src/voxels/VoxelPacketProcessor.cpp @@ -81,7 +81,7 @@ void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, c if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { -if (voxelPacketType != PacketTypeParticleErase) +//if (voxelPacketType != PacketTypeParticleErase) app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket); if (sendingNode) { diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 637079560b..44f1c60ac7 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -545,8 +545,8 @@ bool ModelTree::hasModelsDeletedSince(quint64 sinceTime) { } // sinceTime is an in/out parameter - it will be side effected with the last time sent out -bool ModelTree::encodeModelsDeletedSince(quint64& sinceTime, unsigned char* outputBuffer, size_t maxLength, - size_t& outputLength) { +bool ModelTree::encodeModelsDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* outputBuffer, + size_t maxLength, size_t& outputLength) { bool hasMoreToSend = true; @@ -555,6 +555,26 @@ bool ModelTree::encodeModelsDeletedSince(quint64& sinceTime, unsigned char* outp copyAt += numBytesPacketHeader; outputLength = numBytesPacketHeader; +// pack in flags +OCTREE_PACKET_FLAGS flags = 0; +OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; +*flagsAt = flags; +copyAt += sizeof(OCTREE_PACKET_FLAGS); +outputLength += sizeof(OCTREE_PACKET_FLAGS); + +// pack in sequence number +OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; +*sequenceAt = sequenceNumber; +copyAt += sizeof(OCTREE_PACKET_SEQUENCE); +outputLength += sizeof(OCTREE_PACKET_SEQUENCE); + +// pack in timestamp +OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); +OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; +*timeAt = now; +copyAt += sizeof(OCTREE_PACKET_SENT_TIME); +outputLength += sizeof(OCTREE_PACKET_SENT_TIME); + uint16_t numberOfIds = 0; // placeholder for now unsigned char* numberOfIDsAt = copyAt; memcpy(copyAt, &numberOfIds, sizeof(numberOfIds)); @@ -642,8 +662,13 @@ void ModelTree::processEraseMessage(const QByteArray& dataByteArray, const Share size_t processedBytes = numBytesPacketHeader; dataAt += numBytesPacketHeader; +dataAt += sizeof(OCTREE_PACKET_FLAGS); +dataAt += sizeof(OCTREE_PACKET_SEQUENCE); +dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); +qDebug() << "\t\t\t numberOfIds: " << numberOfIds; dataAt += sizeof(numberOfIds); processedBytes += sizeof(numberOfIds); diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index b8df1c1a22..df45ae9c15 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -69,7 +69,7 @@ public: bool hasAnyDeletedModels() const { return _recentlyDeletedModelItemIDs.size() > 0; } bool hasModelsDeletedSince(quint64 sinceTime); - bool encodeModelsDeletedSince(quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); + bool encodeModelsDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); void forgetModelsDeletedBefore(quint64 sinceTime); void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 68255bbd41..ed5ea579e0 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -268,21 +268,22 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { - /* + QByteArray datagram(data, size); qDebug() << "\t writeDatagram()..."; + int numBytesPacketHeader = numBytesForPacketHeader(datagram); + const unsigned char* dataAt = reinterpret_cast(datagram.data()) + numBytesPacketHeader; + PacketType type = packetTypeForPacket(datagram); - if (type != PacketType::PacketTypeParticleErase) { - - qDebug() << "\t\t type: " << (unsigned char)type; - qDebug() << "\t\t UUID: " << uuidFromPacketHeader(datagram); - qDebug() << "\t\t MD5: " << hashFromPacketHeader(datagram); + qDebug() << "\t\t type: " << (unsigned char)type; - int numBytesPacketHeader = numBytesForPacketHeader(datagram); - const unsigned char* dataAt = reinterpret_cast(datagram.data()) + numBytesPacketHeader; + if (type != PacketTypeOctreeStats) { + + //qDebug() << "\t\t UUID: " << uuidFromPacketHeader(datagram); + //qDebug() << "\t\t MD5: " << hashFromPacketHeader(datagram); unsigned char flags = (*(unsigned char*)(dataAt)); dataAt += sizeof(unsigned char); @@ -296,15 +297,12 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share dataAt += sizeof(quint64); qDebug() << "\t\t sent at: " << QString::number(sentAt, 16) << "\n"; } - else { - qDebug() << "size: " << size; - const char* dataAt = data; - for (int i = 0; i < size; i++) { - unsigned char byte = *((unsigned char*)dataAt); - dataAt += sizeof(unsigned char); - qDebug() << "\t\t " << QString::number(byte, 16); - } - }*/ + + if (type == PacketTypeParticleErase || type==PacketTypeModelErase) { + uint16_t ids = *((uint16_t*)dataAt); + dataAt += sizeof(uint16_t); + qDebug() << "\t\t\t ids: " << ids; + } return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 2b04b5652c..4ca2237b43 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -868,7 +868,7 @@ bool OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, } -//qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; +qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; // Guard against possible corrupted packets... with bad timestamps const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index dd8cb6e618..a597c76bd9 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -511,8 +511,8 @@ bool ParticleTree::hasParticlesDeletedSince(quint64 sinceTime) { } // sinceTime is an in/out parameter - it will be side effected with the last time sent out -bool ParticleTree::encodeParticlesDeletedSince(quint64& sinceTime, unsigned char* outputBuffer, size_t maxLength, - size_t& outputLength) { +bool ParticleTree::encodeParticlesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* outputBuffer, + size_t maxLength, size_t& outputLength) { bool hasMoreToSend = true; @@ -521,6 +521,24 @@ bool ParticleTree::encodeParticlesDeletedSince(quint64& sinceTime, unsigned char copyAt += numBytesPacketHeader; outputLength = numBytesPacketHeader; +// pack in flags +OCTREE_PACKET_FLAGS flags = 0; +memcpy(copyAt, &flags, sizeof(OCTREE_PACKET_FLAGS)); +copyAt += sizeof(OCTREE_PACKET_FLAGS); +outputLength += sizeof(OCTREE_PACKET_FLAGS); + +// pack in sequence number +memcpy(copyAt, &sequenceNumber, sizeof(OCTREE_PACKET_SEQUENCE)); +copyAt += sizeof(OCTREE_PACKET_SEQUENCE); +outputLength += sizeof(OCTREE_PACKET_SEQUENCE); + +// pack in timestamp +OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); +memcpy(copyAt, &now, sizeof(OCTREE_PACKET_SENT_TIME)); +copyAt += sizeof(OCTREE_PACKET_SENT_TIME); +outputLength += sizeof(OCTREE_PACKET_SENT_TIME); + + uint16_t numberOfIds = 0; // placeholder for now unsigned char* numberOfIDsAt = copyAt; memcpy(copyAt, &numberOfIds, sizeof(numberOfIds)); @@ -609,8 +627,13 @@ void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const Sh size_t processedBytes = numBytesPacketHeader; dataAt += numBytesPacketHeader; +dataAt += sizeof(OCTREE_PACKET_FLAGS); +dataAt += sizeof(OCTREE_PACKET_SEQUENCE); +dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); +qDebug() << "\t\t\t numberOfIds: " << numberOfIds; dataAt += sizeof(numberOfIds); processedBytes += sizeof(numberOfIds); diff --git a/libraries/particles/src/ParticleTree.h b/libraries/particles/src/ParticleTree.h index 0a2ac285b7..88cff94249 100644 --- a/libraries/particles/src/ParticleTree.h +++ b/libraries/particles/src/ParticleTree.h @@ -67,7 +67,7 @@ public: bool hasAnyDeletedParticles() const { return _recentlyDeletedParticleIDs.size() > 0; } bool hasParticlesDeletedSince(quint64 sinceTime); - bool encodeParticlesDeletedSince(quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); + bool encodeParticlesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* packetData, size_t maxLength, size_t& outputLength); void forgetParticlesDeletedBefore(quint64 sinceTime); void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); From 5d4b0df1088b9700cc8ecb8600845b15797dc4b6 Mon Sep 17 00:00:00 2001 From: wangyix Date: Wed, 28 May 2014 17:41:38 -0700 Subject: [PATCH 29/77] added flag,seq,st to EnvironmentData, untested removed/commented out debug prints --- assignment-client/src/voxels/VoxelServer.cpp | 30 ++++++++++++++++++-- assignment-client/src/voxels/VoxelServer.h | 2 +- interface/src/Environment.cpp | 5 ++++ libraries/models/src/ModelTree.cpp | 1 - libraries/networking/src/LimitedNodeList.cpp | 4 +-- libraries/octree/src/OctreeSceneStats.cpp | 3 +- libraries/particles/src/ParticleTree.cpp | 1 - 7 files changed, 38 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 1251358320..181a51ebc9 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -40,12 +40,36 @@ bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendEnvironments; } -int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequence, const SharedNodePointer& node) { +int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { - // TODO: add flags, seq, timestamp to packet +unsigned char* copyAt = _tempOutputBuffer; int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_tempOutputBuffer), PacketTypeEnvironmentData); +copyAt += numBytesPacketHeader; int envPacketLength = numBytesPacketHeader; + + +// pack in flags +OCTREE_PACKET_FLAGS flags = 0; +OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; +*flagsAt = flags; +copyAt += sizeof(OCTREE_PACKET_FLAGS); +envPacketLength += sizeof(OCTREE_PACKET_FLAGS); + +// pack in sequence number +OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; +*sequenceAt = sequenceNumber; +copyAt += sizeof(OCTREE_PACKET_SEQUENCE); +envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE); + +// pack in timestamp +OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); +OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; +*timeAt = now; +copyAt += sizeof(OCTREE_PACKET_SENT_TIME); +envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME); + + int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); for (int i = 0; i < environmentsToSend; i++) { @@ -53,6 +77,8 @@ int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequence, const Share } NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node)); + sequenceNumber++; + return envPacketLength; } diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h index 8fba2e9d69..b9277fed0c 100644 --- a/assignment-client/src/voxels/VoxelServer.h +++ b/assignment-client/src/voxels/VoxelServer.h @@ -46,7 +46,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequence, const SharedNodePointer& node); + virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); private: bool _sendEnvironments; diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index 1ba2f0501c..c302907cd7 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -160,6 +160,11 @@ bool Environment::findCapsulePenetration(const glm::vec3& start, const glm::vec3 int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray& packet) { // push past the packet header int bytesRead = numBytesForPacketHeader(packet); + +// push past flags, sequence, timestamp +bytesRead += sizeof(OCTREE_PACKET_FLAGS); +bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); +bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); // get the lock for the duration of the call QMutexLocker locker(&_mutex); diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 44f1c60ac7..8b249411ba 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -668,7 +668,6 @@ dataAt += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); -qDebug() << "\t\t\t numberOfIds: " << numberOfIds; dataAt += sizeof(numberOfIds); processedBytes += sizeof(numberOfIds); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index ed5ea579e0..743cbe949a 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -268,7 +268,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { - + /* QByteArray datagram(data, size); qDebug() << "\t writeDatagram()..."; @@ -303,7 +303,7 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share dataAt += sizeof(uint16_t); qDebug() << "\t\t\t ids: " << ids; } - + */ return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 4ca2237b43..3659c8bd24 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -868,13 +868,14 @@ bool OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, } -qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; +//qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; // Guard against possible corrupted packets... with bad timestamps const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive const int MIN_RESONABLE_FLIGHT_TIME = 0; if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime; +qDebug() << "\t sequence:" << QString::number(sequence, 16); qDebug() << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; qDebug() << "\t arrivedAt:" << QString::number(arrivedAt, 16) << " usecs"; qDebug() << "\t nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index a597c76bd9..50f9ea1090 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -633,7 +633,6 @@ dataAt += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); -qDebug() << "\t\t\t numberOfIds: " << numberOfIds; dataAt += sizeof(numberOfIds); processedBytes += sizeof(numberOfIds); From ff77644caa90fd668c4f9093e2ab7be726edc651 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 28 May 2014 18:35:30 -0700 Subject: [PATCH 30/77] Progress on selecting cascades. --- interface/resources/shaders/shadow_map.frag | 14 ++++++++++---- interface/resources/shaders/shadow_map.vert | 14 +++++--------- interface/src/Application.cpp | 5 ++--- interface/src/Application.h | 1 + interface/src/voxels/VoxelSystem.cpp | 2 ++ 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index f53c66b095..f2246fff55 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,11 +13,17 @@ uniform sampler2DShadow shadowMap; +uniform vec3 shadowDistances; + +// the color in shadow varying vec4 shadowColor; +// the interpolated position +varying vec4 position; + void main(void) { - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, gl_TexCoord[0].stp).r * - shadow2D(shadowMap, gl_TexCoord[1].stp).r * - shadow2D(shadowMap, gl_TexCoord[2].stp).r * - shadow2D(shadowMap, gl_TexCoord[3].stp).r); + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index e7efcd7c0f..dcc5324927 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -11,8 +11,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the color in shadow varying vec4 shadowColor; +// the interpolated position +varying vec4 position; + void main(void) { // the shadow color includes only the ambient terms shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); @@ -22,15 +26,7 @@ void main(void) { gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); // generate the shadow texture coordinates using the eye position - vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; - gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), - dot(gl_EyePlaneR[0], eyePosition), 1.0); - gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[1], eyePosition), dot(gl_EyePlaneT[1], eyePosition), - dot(gl_EyePlaneR[1], eyePosition), 1.0); - gl_TexCoord[2] = vec4(dot(gl_EyePlaneS[2], eyePosition), dot(gl_EyePlaneT[2], eyePosition), - dot(gl_EyePlaneR[2], eyePosition), 1.0); - gl_TexCoord[3] = vec4(dot(gl_EyePlaneS[3], eyePosition), dot(gl_EyePlaneT[3], eyePosition), - dot(gl_EyePlaneR[3], eyePosition), 1.0); + position = gl_ModelViewMatrix * gl_Vertex; // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0cae0f3e75..a2892eb003 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2260,7 +2260,6 @@ void Application::updateShadowMap() { glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); - const float MAP_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; @@ -2272,8 +2271,8 @@ void Application::updateShadowMap() { const glm::vec2& coord = MAP_COORDS[i]; glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); - float nearScale = MAP_DISTANCES[i] * frustumScale; - float farScale = MAP_DISTANCES[i + 1] * frustumScale; + float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; + float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; glm::vec3 points[] = { glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), diff --git a/interface/src/Application.h b/interface/src/Application.h index 5d29a9057a..59f9ad4e15 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -127,6 +127,7 @@ static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const int SHADOW_MATRIX_COUNT = 4; +static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; class Application : public QApplication { Q_OBJECT diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 4f1b322455..11bd47b7e4 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -518,6 +518,8 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.bind(); _shadowMapProgram.setUniformValue("shadowMap", 0); + _shadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); _shadowMapProgram.release(); } } From cfe176c60e139c743c6a95018fbc607a2ad7afed Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 28 May 2014 20:50:39 -0700 Subject: [PATCH 31/77] Add locationsMenu.js --- examples/locationsMenu.js | 302 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 examples/locationsMenu.js diff --git a/examples/locationsMenu.js b/examples/locationsMenu.js new file mode 100644 index 0000000000..6f4a28fe38 --- /dev/null +++ b/examples/locationsMenu.js @@ -0,0 +1,302 @@ +// +// locationsMenu.js +// examples +// +// Created by Ryan Huffman on 5/28/14 +// Copyright 2014 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 +// + +var scriptUrl = "https://script.google.com/macros/s/AKfycbwIo4lmF-qUwX1Z-9eA_P-g2gse9oFhNcjVyyksGukyDDEFXgU/exec?action=listOwners&domain=alpha.highfidelity.io"; + +var LocationMenu = function(opts) { + var self = this; + + var pageSize = opts.pageSize || 10; + var menuWidth = opts.menuWidth || 150; + var menuHeight = opts.menuItemHeight || 24; + + var inactiveColor = { red: 51, green: 102, blue: 102 }; + var activeColor = { red: 18, green: 66, blue: 66 }; + var prevNextColor = { red: 192, green: 192, blue: 192 }; + var disabledColor = { red: 64, green: 64, blue: 64}; + var position = { x: 0, y: 0 }; + + var locationIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/location.svg"; + var toolHeight = 50; + var toolWidth = 50; + var visible = false; + var menuItemOffset = { + x: 55, + y: 0, + }; + var menuItemPadding = 5; + var margin = 7; + var fullMenuHeight = (2 * menuItemOffset.y) + (menuHeight * (pageSize + 1)); + var menuOffset = -fullMenuHeight + toolHeight; + + var windowDimensions = Controller.getViewportDimensions(); + + this.locations = []; + this.numPages = 1; + this.page = 0; + + this.menuToggleButton = Overlays.addOverlay("image", { + x: position.x, + y: position.y, + width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: locationIconUrl, + alpha: 0.9 + }); + + this.background = Overlays.addOverlay("text", { + x: 0, + y: 0, + width: menuWidth + 10, + height: (menuHeight * (pageSize + 1)) + 10, + color: { red: 0, green: 0, blue: 0}, + topMargin: 4, + leftMargin: 4, + text: "", + visible: visible, + }); + + this.menuItems = []; + for (var i = 0; i < pageSize; i++) { + var menuItem = Overlays.addOverlay("text", { + x: 0, + y: 0, + width: menuWidth, + height: menuHeight, + color: inactiveColor, + topMargin: margin, + leftMargin: margin, + text: (i == 0) ? "Loading..." : "", + visible: visible, + }); + this.menuItems.push({ overlay: menuItem, location: null }); + } + + this.previousButton = Overlays.addOverlay("text", { + x: 0, + y: 0, + width: menuWidth / 2, + height: menuHeight, + color: disabledColor, + topMargin: margin, + leftMargin: margin, + text: "Previous", + visible: visible, + }); + + this.nextButton = Overlays.addOverlay("text", { + x: 0, + y: 0, + width: menuWidth / 2, + height: menuHeight, + color: disabledColor, + topMargin: margin, + leftMargin: margin, + text: "Next", + visible: visible, + }); + + this.reposition = function(force) { + var newWindowDimensions = Controller.getViewportDimensions(); + if (force || newWindowDimensions.y != windowDimensions.y) { + windowDimensions = newWindowDimensions; + + position.x = 8; + position.y = Math.floor(windowDimensions.y / 2) + 25 + 50 + 8; + + Overlays.editOverlay(self.menuToggleButton, { + x: position.x, + y: position.y, + }); + Overlays.editOverlay(self.background, { + x: position.x + menuItemOffset.x, + y: position.y + menuItemOffset.y - 2 * menuItemPadding + menuOffset, + }); + for (var i = 0; i < pageSize; i++) { + Overlays.editOverlay(self.menuItems[i].overlay, { + x: position.x + menuItemOffset.x + menuItemPadding, + y: position.y + menuItemOffset.y - menuItemPadding + (i * menuHeight) + menuOffset, + }); + } + Overlays.editOverlay(self.previousButton, { + x: position.x + menuItemOffset.x + menuItemPadding, + y: position.y + menuItemOffset.y - menuItemPadding + (pageSize * menuHeight) + menuOffset, + }); + Overlays.editOverlay(self.nextButton, { + x: position.x + menuItemOffset.x + menuItemPadding + (menuWidth / 2), + y: position.y + menuItemOffset.y - menuItemPadding + (pageSize * menuHeight) + menuOffset, + }); + } + } + + this.updateLocations = function(locations) { + this.locations = locations; + this.numPages = Math.ceil(locations.length / pageSize); + this.goToPage(0); + } + + this.setError = function() { + Overlays.editOverlay(this.menuItems[0].overlay, { text: "Error loading data" }); + } + + this.toggleMenu = function() { + visible = !visible; + for (var i = 0; i < this.menuItems.length; i++) { + Overlays.editOverlay(this.menuItems[i].overlay, { visible: visible}); + } + Overlays.editOverlay(this.previousButton, { visible: visible}); + Overlays.editOverlay(this.nextButton, { visible: visible}); + Overlays.editOverlay(this.background, { visible: visible}); + if (visible) { + Overlays.editOverlay(this.menuToggleButton, { subImage: { x: 0, y: 0, width: toolWidth, height: toolHeight } }), + } else { + Overlays.editOverlay(this.menuToggleButton, { subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight } }), + } + } + + this.goToPage = function(pageNumber) { + if (pageNumber < 0 || pageNumber >= this.numPages) { + return; + } + + this.page = pageNumber; + var start = pageNumber * pageSize; + for (var i = 0; i < pageSize; i++) { + var update = {}; + var location = null; + if (start + i < this.locations.length) { + location = this.locations[start + i]; + update.text = (start + i + 1) + ". " + location.username; + update.color = inactiveColor; + } else { + update.text = ""; + update.color = disabledColor; + } + Overlays.editOverlay(this.menuItems[i].overlay, update); + this.menuItems[i].location = location; + } + + this.previousEnabled = pageNumber > 0; + this.nextEnabled = pageNumber < (this.numPages - 1); + + Overlays.editOverlay(this.previousButton, { color: this.previousEnabled ? prevNextColor : disabledColor}); + Overlays.editOverlay(this.nextButton, { color: this.nextEnabled ? prevNextColor : disabledColor }); + } + + this.mousePressEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if (clickedOverlay == self.menuToggleButton) { + self.toggleMenu(); + } else if (clickedOverlay == self.previousButton) { + if (self.previousEnabled) { + Overlays.editOverlay(clickedOverlay, { color: activeColor }); + } + } else if (clickedOverlay == self.nextButton) { + if (self.nextEnabled) { + Overlays.editOverlay(clickedOverlay, { color: activeColor }); + } + } else { + for (var i = 0; i < self.menuItems.length; i++) { + if (clickedOverlay == self.menuItems[i].overlay) { + if (self.menuItems[i].location != null) { + Overlays.editOverlay(clickedOverlay, { color: activeColor }); + } + break; + } + } + } + } + + this.mouseReleaseEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if (clickedOverlay == self.previousButton) { + if (self.previousEnabled) { + Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + self.goToPage(self.page - 1); + } + } else if (clickedOverlay == self.nextButton) { + if (self.nextEnabled) { + Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + self.goToPage(self.page + 1); + } + } else { + for (var i = 0; i < self.menuItems.length; i++) { + if (clickedOverlay == self.menuItems[i].overlay) { + if (self.menuItems[i].location != null) { + Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + var location = self.menuItems[i].location; + Window.location = "hifi://" + location.domain + "/" + + location.x + "," + location.y + "," + location.z; + } + break; + } + } + } + } + + this.cleanup = function() { + for (var i = 0; i < self.menuItems.length; i++) { + Overlays.deleteOverlay(self.menuItems[i].overlay); + } + Overlays.deleteOverlay(self.menuToggleButton); + Overlays.deleteOverlay(self.previousButton); + Overlays.deleteOverlay(self.nextButton); + Overlays.deleteOverlay(self.background); + } + + Controller.mousePressEvent.connect(this.mousePressEvent); + Controller.mouseReleaseEvent.connect(this.mouseReleaseEvent); + Script.update.connect(this.reposition); + Script.scriptEnding.connect(this.cleanup); + + this.reposition(true); +}; + +var locationMenu = new LocationMenu({ pageSize: 8 }); + +print("Loading strip data from " + scriptUrl); + +var req = new XMLHttpRequest(); +req.responseType = 'json'; + +req.onreadystatechange = function() { + if (req.readyState == req.DONE) { + if (req.status == 200 && req.response != null) { + for (var domain in req.response) { + var locations = req.response[domain]; + var users = []; + for (var i = 0; i < locations.length; i++) { + var loc = locations[i]; + var x1 = loc[1], + x2 = loc[2], + y1 = loc[3], + y2 = loc[4]; + users.push({ + domain: domain, + username: loc[0], + x: x1, + y: 300, + z: y1, + }); + } + locationMenu.updateLocations(users); + } + } else { + print("Error loading data: " + req.status + " " + req.statusText + ", " + req.errorCode + ": " + req.responseText); + locationMenu.setError(); + } + } +} + +req.open("GET", scriptUrl); +req.send(); From 425632e072fe64196d7f917f1a0bb30027d31423 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 May 2014 08:48:22 -0700 Subject: [PATCH 32/77] Add 'f' to end of const float to follow coding standard --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a924528c2b..c21214bed5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -73,7 +73,7 @@ const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; const float MUTE_RADIUS = 50; const QString CONSOLE_TITLE = "Scripting Console"; -const float CONSOLE_WINDOW_OPACITY = 0.95; +const float CONSOLE_WINDOW_OPACITY = 0.95f; const int CONSOLE_WIDTH = 800; const int CONSOLE_HEIGHT = 200; From c87c4748771376d6d63cbfb9e0903f03565fa6d3 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 10:39:40 -0700 Subject: [PATCH 33/77] removed debug info, cleaned code for pull req --- .../src/octree/OctreeSendThread.cpp | 1 - assignment-client/src/voxels/VoxelServer.cpp | 38 +++++++++--------- interface/src/Application.cpp | 7 +--- interface/src/Environment.cpp | 8 ++-- interface/src/voxels/VoxelPacketProcessor.cpp | 2 +- libraries/models/src/ModelTree.cpp | 40 +++++++++---------- libraries/networking/src/LimitedNodeList.cpp | 36 ----------------- libraries/octree/src/OctreeSceneStats.cpp | 16 ++------ libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/particles/src/ParticleTree.cpp | 34 ++++++++-------- 10 files changed, 67 insertions(+), 117 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index dca18026a1..b91c4c4761 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -535,7 +535,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets if (_myServer->hasSpecialPacketToSend(_node) && !nodeData->isShuttingDown()) { -qDebug() << "sending special packet..."; trueBytesSent += _myServer->sendSpecialPacket(_sequenceNumber, _node); nodeData->resetOctreePacket(_sequenceNumber); // because _sequenceNumber has changed truePacketsSent++; diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 181a51ebc9..9a4da4d611 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -42,32 +42,32 @@ bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { -unsigned char* copyAt = _tempOutputBuffer; + unsigned char* copyAt = _tempOutputBuffer; int numBytesPacketHeader = populatePacketHeader(reinterpret_cast(_tempOutputBuffer), PacketTypeEnvironmentData); -copyAt += numBytesPacketHeader; + copyAt += numBytesPacketHeader; int envPacketLength = numBytesPacketHeader; -// pack in flags -OCTREE_PACKET_FLAGS flags = 0; -OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; -*flagsAt = flags; -copyAt += sizeof(OCTREE_PACKET_FLAGS); -envPacketLength += sizeof(OCTREE_PACKET_FLAGS); + // pack in flags + OCTREE_PACKET_FLAGS flags = 0; + OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; + *flagsAt = flags; + copyAt += sizeof(OCTREE_PACKET_FLAGS); + envPacketLength += sizeof(OCTREE_PACKET_FLAGS); -// pack in sequence number -OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; -*sequenceAt = sequenceNumber; -copyAt += sizeof(OCTREE_PACKET_SEQUENCE); -envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE); + // pack in sequence number + OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; + *sequenceAt = sequenceNumber; + copyAt += sizeof(OCTREE_PACKET_SEQUENCE); + envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE); -// pack in timestamp -OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); -OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; -*timeAt = now; -copyAt += sizeof(OCTREE_PACKET_SENT_TIME); -envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME); + // pack in timestamp + OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); + OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; + *timeAt = now; + copyAt += sizeof(OCTREE_PACKET_SENT_TIME); + envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME); int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7ad3409f8e..4ee15bc949 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3142,12 +3142,7 @@ void Application::trackIncomingVoxelPacket(const QByteArray& packet, const Share _octreeSceneStatsLock.lockForWrite(); if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - if (stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec())) { - - // DEBUG! unreasonable flight time - qDebug() << " sending node type: " << NodeType::getNodeTypeName(sendingNode->getType()) << "\n"; - //qDebug() << "\t\t clock skew: " << sendingNode->getClockSkewUsec(); - } + stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); } _octreeSceneStatsLock.unlock(); } diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index c302907cd7..67337f963c 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -161,10 +161,10 @@ int Environment::parseData(const HifiSockAddr& senderAddress, const QByteArray& // push past the packet header int bytesRead = numBytesForPacketHeader(packet); -// push past flags, sequence, timestamp -bytesRead += sizeof(OCTREE_PACKET_FLAGS); -bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); -bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); + // push past flags, sequence, timestamp + bytesRead += sizeof(OCTREE_PACKET_FLAGS); + bytesRead += sizeof(OCTREE_PACKET_SEQUENCE); + bytesRead += sizeof(OCTREE_PACKET_SENT_TIME); // get the lock for the duration of the call QMutexLocker locker(&_mutex); diff --git a/interface/src/voxels/VoxelPacketProcessor.cpp b/interface/src/voxels/VoxelPacketProcessor.cpp index 11e62b0fe3..095c378c04 100644 --- a/interface/src/voxels/VoxelPacketProcessor.cpp +++ b/interface/src/voxels/VoxelPacketProcessor.cpp @@ -81,7 +81,7 @@ void VoxelPacketProcessor::processPacket(const SharedNodePointer& sendingNode, c if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { -//if (voxelPacketType != PacketTypeParticleErase) + app->trackIncomingVoxelPacket(mutablePacket, sendingNode, wasStatsPacket); if (sendingNode) { diff --git a/libraries/models/src/ModelTree.cpp b/libraries/models/src/ModelTree.cpp index 279508bf29..e88a969061 100644 --- a/libraries/models/src/ModelTree.cpp +++ b/libraries/models/src/ModelTree.cpp @@ -555,25 +555,25 @@ bool ModelTree::encodeModelsDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, copyAt += numBytesPacketHeader; outputLength = numBytesPacketHeader; -// pack in flags -OCTREE_PACKET_FLAGS flags = 0; -OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; -*flagsAt = flags; -copyAt += sizeof(OCTREE_PACKET_FLAGS); -outputLength += sizeof(OCTREE_PACKET_FLAGS); + // pack in flags + OCTREE_PACKET_FLAGS flags = 0; + OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; + *flagsAt = flags; + copyAt += sizeof(OCTREE_PACKET_FLAGS); + outputLength += sizeof(OCTREE_PACKET_FLAGS); -// pack in sequence number -OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; -*sequenceAt = sequenceNumber; -copyAt += sizeof(OCTREE_PACKET_SEQUENCE); -outputLength += sizeof(OCTREE_PACKET_SEQUENCE); + // pack in sequence number + OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; + *sequenceAt = sequenceNumber; + copyAt += sizeof(OCTREE_PACKET_SEQUENCE); + outputLength += sizeof(OCTREE_PACKET_SEQUENCE); -// pack in timestamp -OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); -OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; -*timeAt = now; -copyAt += sizeof(OCTREE_PACKET_SENT_TIME); -outputLength += sizeof(OCTREE_PACKET_SENT_TIME); + // pack in timestamp + OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); + OCTREE_PACKET_SENT_TIME* timeAt = (OCTREE_PACKET_SENT_TIME*)copyAt; + *timeAt = now; + copyAt += sizeof(OCTREE_PACKET_SENT_TIME); + outputLength += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now unsigned char* numberOfIDsAt = copyAt; @@ -662,9 +662,9 @@ void ModelTree::processEraseMessage(const QByteArray& dataByteArray, const Share size_t processedBytes = numBytesPacketHeader; dataAt += numBytesPacketHeader; -dataAt += sizeof(OCTREE_PACKET_FLAGS); -dataAt += sizeof(OCTREE_PACKET_SEQUENCE); -dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + dataAt += sizeof(OCTREE_PACKET_FLAGS); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 743cbe949a..c0d7941edf 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -268,42 +268,6 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode, const HifiSockAddr& overridenSockAddr) { - /* - QByteArray datagram(data, size); - - qDebug() << "\t writeDatagram()..."; - - int numBytesPacketHeader = numBytesForPacketHeader(datagram); - const unsigned char* dataAt = reinterpret_cast(datagram.data()) + numBytesPacketHeader; - - PacketType type = packetTypeForPacket(datagram); - qDebug() << "\t\t type: " << (unsigned char)type; - - - if (type != PacketTypeOctreeStats) { - - //qDebug() << "\t\t UUID: " << uuidFromPacketHeader(datagram); - //qDebug() << "\t\t MD5: " << hashFromPacketHeader(datagram); - - unsigned char flags = (*(unsigned char*)(dataAt)); - dataAt += sizeof(unsigned char); - qDebug() << "\t\t flags: " << QString::number(flags, 2); - - uint16_t sequence = (*(uint16_t*)dataAt); - dataAt += sizeof(uint16_t); - qDebug() << "\t\t sequence: " << QString::number(sequence, 16); - - quint64 sentAt = (*(quint64*)dataAt); - dataAt += sizeof(quint64); - qDebug() << "\t\t sent at: " << QString::number(sentAt, 16) << "\n"; - } - - if (type == PacketTypeParticleErase || type==PacketTypeModelErase) { - uint16_t ids = *((uint16_t*)dataAt); - dataAt += sizeof(uint16_t); - qDebug() << "\t\t\t ids: " << ids; - } - */ return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr); } diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 3659c8bd24..269b64559f 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -839,7 +839,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { return _itemValueBuffer; } -bool OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, +void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec) { const bool wantExtraDebugging = false; @@ -866,21 +866,13 @@ bool OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, qDebug() << "nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; qDebug() << "flightTime:" << flightTime << " usecs"; } - - -//qDebug() << "\t" << QString::number(sequence, 16) << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; // Guard against possible corrupted packets... with bad timestamps const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive const int MIN_RESONABLE_FLIGHT_TIME = 0; if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime; -qDebug() << "\t sequence:" << QString::number(sequence, 16); -qDebug() << "\t sentAt:" << QString::number(sentAt, 16) << " usecs"; -qDebug() << "\t arrivedAt:" << QString::number(arrivedAt, 16) << " usecs"; -qDebug() << "\t nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; -qDebug() << "\t flightTime:" << flightTime << " usecs"; - return true; // ignore any packets that are unreasonable + return; } // determine our expected sequence number... handle rollover appropriately @@ -892,7 +884,7 @@ qDebug() << "\t flightTime:" << flightTime << " usecs"; int sequenceOffset = (sequence - expected); if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) { qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence; - return false; // ignore any packets that are unreasonable + return; // ignore any packets that are unreasonable } // track packets here... @@ -993,6 +985,6 @@ qDebug() << "\t flightTime:" << flightTime << " usecs"; } } } - return false; + return; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index dd0b31b010..ef22fd7c1c 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -158,7 +158,7 @@ public: quint64 getLastFullTotalBytes() const { return _lastFullTotalBytes; } // Used in client implementations to track individual octree packets - bool trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec); + void trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec); quint32 getIncomingPackets() const { return _incomingPacket; } quint64 getIncomingBytes() const { return _incomingBytes; } diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp index c36e029ce1..cd79ff303e 100644 --- a/libraries/particles/src/ParticleTree.cpp +++ b/libraries/particles/src/ParticleTree.cpp @@ -521,22 +521,22 @@ bool ParticleTree::encodeParticlesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNu copyAt += numBytesPacketHeader; outputLength = numBytesPacketHeader; -// pack in flags -OCTREE_PACKET_FLAGS flags = 0; -memcpy(copyAt, &flags, sizeof(OCTREE_PACKET_FLAGS)); -copyAt += sizeof(OCTREE_PACKET_FLAGS); -outputLength += sizeof(OCTREE_PACKET_FLAGS); + // pack in flags + OCTREE_PACKET_FLAGS flags = 0; + memcpy(copyAt, &flags, sizeof(OCTREE_PACKET_FLAGS)); + copyAt += sizeof(OCTREE_PACKET_FLAGS); + outputLength += sizeof(OCTREE_PACKET_FLAGS); -// pack in sequence number -memcpy(copyAt, &sequenceNumber, sizeof(OCTREE_PACKET_SEQUENCE)); -copyAt += sizeof(OCTREE_PACKET_SEQUENCE); -outputLength += sizeof(OCTREE_PACKET_SEQUENCE); + // pack in sequence number + memcpy(copyAt, &sequenceNumber, sizeof(OCTREE_PACKET_SEQUENCE)); + copyAt += sizeof(OCTREE_PACKET_SEQUENCE); + outputLength += sizeof(OCTREE_PACKET_SEQUENCE); -// pack in timestamp -OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); -memcpy(copyAt, &now, sizeof(OCTREE_PACKET_SENT_TIME)); -copyAt += sizeof(OCTREE_PACKET_SENT_TIME); -outputLength += sizeof(OCTREE_PACKET_SENT_TIME); + // pack in timestamp + OCTREE_PACKET_SENT_TIME now = usecTimestampNow(); + memcpy(copyAt, &now, sizeof(OCTREE_PACKET_SENT_TIME)); + copyAt += sizeof(OCTREE_PACKET_SENT_TIME); + outputLength += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now @@ -627,9 +627,9 @@ void ParticleTree::processEraseMessage(const QByteArray& dataByteArray, const Sh size_t processedBytes = numBytesPacketHeader; dataAt += numBytesPacketHeader; -dataAt += sizeof(OCTREE_PACKET_FLAGS); -dataAt += sizeof(OCTREE_PACKET_SEQUENCE); -dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + dataAt += sizeof(OCTREE_PACKET_FLAGS); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); uint16_t numberOfIds = 0; // placeholder for now memcpy(&numberOfIds, dataAt, sizeof(numberOfIds)); From fe1a0e45654a59beadcf19a8d5c75882734f9b8d Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 11:27:14 -0700 Subject: [PATCH 34/77] removed debug stuff i missed --- assignment-client/src/octree/OctreeQueryNode.cpp | 6 ------ assignment-client/src/octree/OctreeQueryNode.h | 4 ---- assignment-client/src/octree/OctreeSendThread.cpp | 5 ++--- assignment-client/src/voxels/VoxelServer.cpp | 2 -- libraries/octree/src/OctreeSceneStats.cpp | 6 +++--- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index ea15770f9e..f7b293dfa8 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -38,7 +38,6 @@ OctreeQueryNode::OctreeQueryNode() : _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false), - //_sequenceNumber(0), _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), _isShuttingDown(false) @@ -362,8 +361,3 @@ void OctreeQueryNode::dumpOutOfView() { } } } -/* -void OctreeQueryNode::incrementSequenceNumber() { - _sequenceNumber++; -} -*/ diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index af293189a4..eeea98699c 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -99,8 +99,6 @@ public: void nodeKilled(); void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } - - //void incrementSequenceNumber(); private slots: void sendThreadFinished(); @@ -138,8 +136,6 @@ private: bool _lodChanged; bool _lodInitialized; - //OCTREE_PACKET_SEQUENCE _sequenceNumber; - quint64 _lastRootTimestamp; PacketType _myPacketType; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b91c4c4761..a396e1170c 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -143,8 +143,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes } const unsigned char* messageData = nodeData->getPacket(); -//unsigned char messageData[MAX_PACKET_SIZE]; -//memcpy(messageData, nodeData->getPacket(), MAX_PACKET_SIZE); // DEBUG: make copy of message to send int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); const unsigned char* dataAt = messageData + numBytesPacketHeader; @@ -164,7 +162,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes int piggyBackSize = nodeData->getPacketLength() + statsMessageLength; // If the size of the stats message and the voxel message will fit in a packet, then piggyback them -if (piggyBackSize < MAX_PACKET_SIZE && false) { + if (piggyBackSize < MAX_PACKET_SIZE) { // copy voxel message to back of stats message memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); @@ -252,6 +250,7 @@ if (piggyBackSize < MAX_PACKET_SIZE && false) { _sequenceNumber++; nodeData->resetOctreePacket(_sequenceNumber); } + return packetsSent; } diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 9a4da4d611..43d01f1c77 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -48,7 +48,6 @@ int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const copyAt += numBytesPacketHeader; int envPacketLength = numBytesPacketHeader; - // pack in flags OCTREE_PACKET_FLAGS flags = 0; OCTREE_PACKET_FLAGS* flagsAt = (OCTREE_PACKET_FLAGS*)copyAt; @@ -69,7 +68,6 @@ int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const copyAt += sizeof(OCTREE_PACKET_SENT_TIME); envPacketLength += sizeof(OCTREE_PACKET_SENT_TIME); - int environmentsToSend = getSendMinimalEnvironment() ? 1 : getEnvironmentDataCount(); for (int i = 0; i < environmentsToSend; i++) { diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 269b64559f..9580ae6d13 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -857,7 +857,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, //bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); //bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); - OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); // DEBUG!!! + OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); qint64 flightTime = arrivedAt - sentAt + nodeClockSkewUsec; if (wantExtraDebugging) { @@ -872,7 +872,7 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, const int MIN_RESONABLE_FLIGHT_TIME = 0; if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime; - return; + return; // ignore any packets that are unreasonable } // determine our expected sequence number... handle rollover appropriately @@ -985,6 +985,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, } } } - return; + } From 65508b2016d1688a6beba885aa2efed8bc920b15 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 11:42:35 -0700 Subject: [PATCH 35/77] updated packet type version numbers --- libraries/networking/src/PacketHeaders.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 0f0b57635c..c56dba9cf1 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -52,7 +52,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeAvatarIdentity: return 1; case PacketTypeEnvironmentData: - return 1; + return 2; case PacketTypeDomainList: case PacketTypeDomainListRequest: return 3; @@ -66,8 +66,12 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeParticleData: return 1; + case PacketTypeParticleErase: + return 1; case PacketTypeModelData: - return 2; + return 2; + case PacketTypeModelErase: + return 1; default: return 0; } From e6966c2155e0561cf34d343047776f98da7ff35a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 12:12:23 -0700 Subject: [PATCH 36/77] add improved detailed rendering and FPS debugging stats --- interface/src/Application.cpp | 129 ++++++++++++++++++++------ interface/src/Menu.cpp | 9 +- interface/src/Menu.h | 5 + interface/src/renderer/GlowEffect.cpp | 4 + interface/src/ui/Stats.cpp | 73 ++++++++++++++- interface/src/ui/Stats.h | 1 + libraries/shared/src/PerfStat.cpp | 18 ++++ libraries/shared/src/PerfStat.h | 37 ++++++++ 8 files changed, 245 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ee15bc949..db6333acee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -554,6 +554,8 @@ void Application::initializeGL() { } void Application::paintGL() { + PerformanceTimer perfTimer("paintGL"); + PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); @@ -648,7 +650,10 @@ void Application::paintGL() { _rearMirrorTools->render(true); } - _applicationOverlay.renderOverlay(); + { + PerformanceTimer perfTimer("paintGL/renderOverlay"); + _applicationOverlay.renderOverlay(); + } } _frameCount++; @@ -1288,11 +1293,13 @@ void Application::timer() { } void Application::idle() { + PerformanceTimer perfTimer("idle"); + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing // details normally. bool showWarnings = getLogger()->extraDebugging(); - PerformanceWarning warn(showWarnings, "Application::idle()"); + PerformanceWarning warn(showWarnings, "idle()"); // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran @@ -1300,15 +1307,18 @@ void Application::idle() { if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { _lastTimeUpdated.start(); { + PerformanceTimer perfTimer("idle/update"); PerformanceWarning warn(showWarnings, "Application::idle()... update()"); const float BIGGEST_DELTA_TIME_SECS = 0.25f; update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); } { + PerformanceTimer perfTimer("idle/updateGL"); PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()"); _glWidget->updateGL(); } { + PerformanceTimer perfTimer("idle/rest"); PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); _idleLoopStdev.addValue(timeSinceLastUpdate); @@ -1320,14 +1330,16 @@ void Application::idle() { } if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { + PerformanceTimer perfTimer("idle/rest/_buckyBalls"); _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData()); } // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. idleTimer->start(2); - } - if (_numChangedSettings > 0) { - saveSettings(); + + if (_numChangedSettings > 0) { + saveSettings(); + } } } } @@ -1729,6 +1741,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { } void Application::updateLOD() { + PerformanceTimer perfTimer("idle/update/updateLOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) { Menu::getInstance()->autoAdjustLOD(_fps); @@ -1738,6 +1751,7 @@ void Application::updateLOD() { } void Application::updateMouseRay() { + PerformanceTimer perfTimer("idle/update/updateMouseRay"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); @@ -1770,6 +1784,7 @@ void Application::updateMouseRay() { } void Application::updateFaceshift() { + PerformanceTimer perfTimer("idle/update/updateFaceshift"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); @@ -1784,6 +1799,7 @@ void Application::updateFaceshift() { } void Application::updateVisage() { + PerformanceTimer perfTimer("idle/update/updateVisage"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateVisage()"); @@ -1793,6 +1809,7 @@ void Application::updateVisage() { } void Application::updateMyAvatarLookAtPosition() { + PerformanceTimer perfTimer("idle/update/updateMyAvatarLookAtPosition"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); @@ -1858,6 +1875,7 @@ void Application::updateMyAvatarLookAtPosition() { } void Application::updateThreads(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateThreads"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateThreads()"); @@ -1872,6 +1890,7 @@ void Application::updateThreads(float deltaTime) { } void Application::updateMetavoxels(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateMetavoxels"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); @@ -1901,6 +1920,7 @@ void Application::cameraMenuChanged() { } void Application::updateCamera(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateCamera"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCamera()"); @@ -1918,6 +1938,7 @@ void Application::updateCamera(float deltaTime) { } void Application::updateDialogs(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateDialogs"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); @@ -1934,6 +1955,7 @@ void Application::updateDialogs(float deltaTime) { } void Application::updateCursor(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateCursor"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateCursor()"); @@ -1958,41 +1980,66 @@ void Application::updateCursor(float deltaTime) { } void Application::update(float deltaTime) { + //PerformanceTimer perfTimer("idle/update"); // NOTE: we track this above in Application::idle() + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); updateLOD(); - - // check what's under the mouse and update the mouse voxel - updateMouseRay(); - + updateMouseRay(); // check what's under the mouse and update the mouse voxel updateFaceshift(); updateVisage(); - _myAvatar->updateLookAtTargetAvatar(); + + { + PerformanceTimer perfTimer("idle/update/updateLookAtTargetAvatar"); + _myAvatar->updateLookAtTargetAvatar(); + } updateMyAvatarLookAtPosition(); - _sixenseManager.update(deltaTime); - _joystickManager.update(); - _prioVR.update(deltaTime); + { + PerformanceTimer perfTimer("idle/update/sixense,joystick,prioVR"); + _sixenseManager.update(deltaTime); + _joystickManager.update(); + _prioVR.update(deltaTime); + } updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... - _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... + { + PerformanceTimer perfTimer("idle/update/_avatarManager"); + _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... + } updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present updateCursor(deltaTime); // Handle cursor updates - _particles.update(); // update the particles... - _particleCollisionSystem.update(); // collide the particles... + { + PerformanceTimer perfTimer("idle/update/_particles"); + _particles.update(); // update the particles... + } + { + PerformanceTimer perfTimer("idle/update/_particleCollisionSystem"); + _particleCollisionSystem.update(); // collide the particles... + } - _models.update(); // update the models... + { + PerformanceTimer perfTimer("idle/update/_models"); + _models.update(); // update the models... + } - _overlays.update(deltaTime); + { + PerformanceTimer perfTimer("idle/update/_overlays"); + _overlays.update(deltaTime); + } - // let external parties know we're updating - emit simulating(deltaTime); + { + PerformanceTimer perfTimer("idle/update/emit simulating"); + // let external parties know we're updating + emit simulating(deltaTime); + } } void Application::updateMyAvatar(float deltaTime) { + PerformanceTimer perfTimer("idle/update/updateMyAvatar"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()"); @@ -2253,6 +2300,7 @@ glm::vec3 Application::getSunDirection() { } void Application::updateShadowMap() { + PerformanceTimer perfTimer("pintGL/updateShadowMap"); QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject(); fbo->bind(); glEnable(GL_DEPTH_TEST); @@ -2392,6 +2440,7 @@ QImage Application::renderAvatarBillboard() { } void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { + PerformanceTimer perfTimer("paintGL/displaySide"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset @@ -2424,9 +2473,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); // Setup 3D lights (after the camera transform, so that they are positioned in world space) - setupWorldLight(); + { + PerformanceTimer perfTimer("paintGL/displaySide/setupWorldLight"); + setupWorldLight(); + } if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { + PerformanceTimer perfTimer("paintGL/displaySide/stars"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); if (!_stars.isStarsLoaded()) { @@ -2455,6 +2508,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // draw the sky dome if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { + PerformanceTimer perfTimer("paintGL/displaySide/atmosphere"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... atmosphere..."); _environment.renderAtmospheres(whichCamera); @@ -2474,10 +2528,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); // draw the audio reflector overlay - _audioReflector.render(); - + { + PerformanceTimer perfTimer("paintGL/displaySide/audioReflector"); + _audioReflector.render(); + } + // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { + PerformanceTimer perfTimer("paintGL/displaySide/voxels"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels..."); _voxels.render(); @@ -2485,12 +2543,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // also, metavoxels if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { + PerformanceTimer perfTimer("paintGL/displaySide/metavoxels"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... metavoxels..."); _metavoxels.render(); } if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { + PerformanceTimer perfTimer("paintGL/displaySide/buckyBalls"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... bucky balls..."); _buckyBalls.render(); @@ -2498,6 +2558,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render particles... if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) { + PerformanceTimer perfTimer("paintGL/displaySide/particles"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... particles..."); _particles.render(); @@ -2505,6 +2566,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render models... if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + PerformanceTimer perfTimer("paintGL/displaySide/models"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... models..."); _models.render(); @@ -2512,6 +2574,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { + PerformanceTimer perfTimer("paintGL/displaySide/AmbientOcclusion"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... AmbientOcclusion..."); _ambientOcclusionEffect.render(); @@ -2525,16 +2588,21 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR); - _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); + { + PerformanceTimer perfTimer("paintGL/displaySide/renderAvatars"); + _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); + } if (!selfAvatarOnly) { // Render the world box if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + PerformanceTimer perfTimer("paintGL/displaySide/renderWorldBox"); renderWorldBox(); } - // brad's frustum for debugging + // view frustum for debugging if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) { + PerformanceTimer perfTimer("paintGL/displaySide/ViewFrustum"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... renderViewFrustum..."); renderViewFrustum(_viewFrustum); @@ -2542,6 +2610,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // render voxel fades if they exist if (_voxelFades.size() > 0) { + PerformanceTimer perfTimer("paintGL/displaySide/voxel fades"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxel fades..."); _voxelFadesLock.lockForWrite(); @@ -2557,10 +2626,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // give external parties a change to hook in - emit renderingInWorldInterface(); + { + PerformanceTimer perfTimer("paintGL/displaySide/inWorldInterface"); + emit renderingInWorldInterface(); + } // render JS/scriptable overlays - _overlays.render3D(); + { + PerformanceTimer perfTimer("paintGL/displaySide/3dOverlays"); + _overlays.render3D(); + } } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7fd8f26006..25bf65d18e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -386,8 +386,15 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); - + QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); + QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandDisplaySideTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandIdleTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 50e59320b9..c1a9e4274b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -321,10 +321,15 @@ namespace MenuOption { const QString DisplayModelBounds = "Display Model Bounds"; const QString DisplayModelElementProxy = "Display Model Element Bounds"; const QString DisplayModelElementChildProxies = "Display Model Element Children"; + const QString DisplayTimingDetails = "Display Timing Details"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString ExpandDisplaySideTiming = "Expand Display Side Timing"; + const QString ExpandIdleTiming = "Expand Idle Timing"; + const QString ExpandPaintGLTiming = "Expand PaintGL Timing"; + const QString ExpandUpdateTiming = "Expand Update Timing"; const QString Faceplus = "Faceplus"; const QString Faceshift = "Faceshift"; const QString FilterSixense = "Smooth Sixense Movement"; diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 1eceb71752..262a632df0 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -14,6 +14,8 @@ #include +#include + #include "Application.h" #include "GlowEffect.h" #include "ProgramObject.h" @@ -119,6 +121,8 @@ static void maybeRelease(QOpenGLFramebufferObject* fbo) { } QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { + PerformanceTimer perfTimer("paintGL/glowEffect"); + QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index a391ed239c..d7ca0152fd 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include "Stats.h" #include "InterfaceConfig.h" #include "Menu.h" @@ -158,6 +160,33 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh glColor4f(1, 1, 1, 1); } +bool Stats::includeTimingRecord(const QString& name) { + bool included = false; + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + + if (name == "idle/update") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming) || + Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name == "idle/updateGL") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name.startsWith("idle/update")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming); + } else if (name.startsWith("idle/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name == "paintGL/displaySide") { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming) || + Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); + } else if (name.startsWith("paintGL/displaySide/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming); + } else if (name.startsWith("paintGL/")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); + } else { + included = true; // include everything else + } + } + return included; +} + // display expanded or contracted stats void Stats::display( const float* color, @@ -190,6 +219,9 @@ void Stats::display( int totalServers = NodeList::getInstance()->size(); lines = _expanded ? 5 : 3; + + + drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -345,11 +377,25 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); - lines = _expanded ? 12 : 3; + lines = _expanded ? 11 : 3; if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info } + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + // we will also include room for 1 line per timing record and a header + lines += 1; + + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + lines++; + } + } + } + drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -454,8 +500,6 @@ void Stats::display( } } - verticalOffset += (_expanded ? STATS_PELS_PER_LINE : 0); - QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' '); // Server Voxels @@ -508,6 +552,29 @@ void Stats::display( drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } + // TODO: the display of these timing details should all be moved to JavaScript + if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) { + // Timing details... + const int TIMER_OUTPUT_LINE_LENGTH = 300; + char perfLine[TIMER_OUTPUT_LINE_LENGTH]; + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, + "---------------- Function --------------- --msecs- -calls--", color); + + const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); + QMapIterator i(allRecords); + while (i.hasNext()) { + i.next(); + if (includeTimingRecord(i.key())) { + sprintf(perfLine, "%40s: %8.4f [%6llu]", qPrintable(i.key()), + (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC, + i.value().getCount()); + + verticalOffset += STATS_PELS_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color); + } + } + } if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) { verticalOffset += STATS_PELS_PER_LINE; // space one line... diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 1ce0807ee8..66d6ec99f0 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -30,6 +30,7 @@ public: void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset); void resetWidth(int width, int horizontalOffset); void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess); + bool includeTimingRecord(const QString& name); private: static Stats* _sharedInstance; diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 9235cb3f25..4dca3f3d49 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -52,4 +52,22 @@ PerformanceWarning::~PerformanceWarning() { } }; +QMap PerformanceTimer::_records; + +PerformanceTimer::~PerformanceTimer() { + quint64 end = usecTimestampNow(); + quint64 elapsedusec = (end - _start); + PerformanceTimerRecord& namedRecord = _records[_name]; + namedRecord.recordResult(elapsedusec); +} + +void PerformanceTimer::dumpAllTimerRecords() { + QMapIterator i(_records); + while (i.hasNext()) { + i.next(); + qDebug() << i.key() << ": average " << i.value().getAverage() + << " [" << i.value().getMovingAverage() << "]" + << "usecs over" << i.value().getCount() << "calls"; + } +} diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 22cf14f207..f849fb844c 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -17,6 +17,7 @@ #include #include "SharedUtil.h" +#include "SimpleMovingAverage.h" #include #include @@ -49,5 +50,41 @@ public: static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; } }; +class PerformanceTimerRecord { +public: + PerformanceTimerRecord() : _runningTotal(0), _totalCalls(0) {} + + void recordResult(quint64 elapsed) { _runningTotal += elapsed; _totalCalls++; _movingAverage.updateAverage(elapsed); } + quint64 getAverage() const { return (_totalCalls == 0) ? 0 : _runningTotal / _totalCalls; } + quint64 getMovingAverage() const { return (_totalCalls == 0) ? 0 : _movingAverage.getAverage(); } + quint64 getCount() const { return _totalCalls; } + +private: + quint64 _runningTotal; + quint64 _totalCalls; + SimpleMovingAverage _movingAverage; +}; + +class PerformanceTimer { +public: + + PerformanceTimer(const QString& name) : + _start(usecTimestampNow()), + _name(name) { } + + quint64 elapsed() const { return (usecTimestampNow() - _start); }; + + ~PerformanceTimer(); + + static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; }; + static const QMap& getAllTimerRecords() { return _records; }; + static void dumpAllTimerRecords(); + +private: + quint64 _start; + QString _name; + static QMap _records; +}; + #endif // hifi_PerfStat_h From 09231f01f3e96a293ffe6280e200c46b8030a7b8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 12:48:41 -0700 Subject: [PATCH 37/77] Retain "simple" shadows, supply cascaded as option. --- .../shaders/cascaded_shadow_map.frag | 29 ++++++++++++++ .../shaders/cascaded_shadow_map.vert | 33 ++++++++++++++++ interface/resources/shaders/shadow_map.frag | 15 ++++---- interface/resources/shaders/shadow_map.vert | 7 ++-- interface/src/Application.cpp | 34 ++++++++++++++--- interface/src/Application.h | 6 +-- interface/src/Menu.cpp | 15 ++++++-- interface/src/Menu.h | 7 +++- interface/src/renderer/Model.cpp | 10 +---- interface/src/voxels/VoxelSystem.cpp | 38 ++++++++++++------- interface/src/voxels/VoxelSystem.h | 1 + 11 files changed, 146 insertions(+), 49 deletions(-) create mode 100644 interface/resources/shaders/cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/cascaded_shadow_map.vert diff --git a/interface/resources/shaders/cascaded_shadow_map.frag b/interface/resources/shaders/cascaded_shadow_map.frag new file mode 100644 index 0000000000..9b3e8f7cc7 --- /dev/null +++ b/interface/resources/shaders/cascaded_shadow_map.frag @@ -0,0 +1,29 @@ +#version 120 + +// +// cascaded_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +uniform sampler2DShadow shadowMap; + +uniform vec3 shadowDistances; + +// the color in shadow +varying vec4 shadowColor; + +// the interpolated position +varying vec4 position; + +void main(void) { + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); +} diff --git a/interface/resources/shaders/cascaded_shadow_map.vert b/interface/resources/shaders/cascaded_shadow_map.vert new file mode 100644 index 0000000000..68ff95b28a --- /dev/null +++ b/interface/resources/shaders/cascaded_shadow_map.vert @@ -0,0 +1,33 @@ +#version 120 + +// +// cascaded_shadow_map.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +// the color in shadow +varying vec4 shadowColor; + +// the interpolated position +varying vec4 position; + +void main(void) { + // the shadow color includes only the ambient terms + shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); + + // the normal color includes diffuse + vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + + // generate the shadow texture coordinates using the eye position + position = gl_ModelViewMatrix * gl_Vertex; + + // use the fixed function transform + gl_Position = ftransform(); +} diff --git a/interface/resources/shaders/shadow_map.frag b/interface/resources/shaders/shadow_map.frag index f2246fff55..fa79040ce3 100644 --- a/interface/resources/shaders/shadow_map.frag +++ b/interface/resources/shaders/shadow_map.frag @@ -13,17 +13,16 @@ uniform sampler2DShadow shadowMap; -uniform vec3 shadowDistances; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; // the color in shadow varying vec4 shadowColor; -// the interpolated position -varying vec4 position; - void main(void) { - int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); - vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), - dot(gl_EyePlaneR[shadowIndex], position)); - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); + gl_FragColor = mix(shadowColor, gl_Color, 0.25 * + (shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r)); } diff --git a/interface/resources/shaders/shadow_map.vert b/interface/resources/shaders/shadow_map.vert index dcc5324927..5d2affba98 100644 --- a/interface/resources/shaders/shadow_map.vert +++ b/interface/resources/shaders/shadow_map.vert @@ -14,9 +14,6 @@ // the color in shadow varying vec4 shadowColor; -// the interpolated position -varying vec4 position; - void main(void) { // the shadow color includes only the ambient terms shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient); @@ -26,7 +23,9 @@ void main(void) { gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); // generate the shadow texture coordinates using the eye position - position = gl_ModelViewMatrix * gl_Vertex; + vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition), + dot(gl_EyePlaneR[0], eyePosition), 1.0); // use the fixed function transform gl_Position = ftransform(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a2892eb003..af94ddba01 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -616,7 +616,7 @@ void Application::paintGL() { whichCamera = _viewFrustumOffsetCamera; } - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { + if (Menu::getInstance()->getShadowsEnabled()) { updateShadowMap(); } @@ -2263,13 +2263,20 @@ void Application::updateShadowMap() { const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; - int halfSize = fbo->width() / 2; float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); loadViewFrustum(_myCamera, _viewFrustum); - for (int i = 0; i < SHADOW_MATRIX_COUNT; i++) { + int matrixCount = 1; + int targetSize = fbo->width(); + float targetScale = 1.0f; + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + matrixCount = CASCADED_SHADOW_MATRIX_COUNT; + targetSize = fbo->width() / 2; + targetScale = 0.5f; + } + for (int i = 0; i < matrixCount; i++) { const glm::vec2& coord = MAP_COORDS[i]; - glViewport(coord.s * fbo->width(), coord.t * fbo->height(), halfSize, halfSize); + glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize); float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; @@ -2294,7 +2301,7 @@ void Application::updateShadowMap() { center = inverseRotation * center; // to reduce texture "shimmer," move in texel increments - float texelSize = (2.0f * radius) / halfSize; + float texelSize = (2.0f * radius) / targetSize; center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, roundf(center.z / texelSize) * texelSize); @@ -2306,7 +2313,8 @@ void Application::updateShadowMap() { maxima.z += _viewFrustum.getFarClip() * 0.5f; // save the combined matrix for rendering - _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * glm::scale(glm::vec3(0.5f, 0.5f, 1.0f)) * + _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * + glm::scale(glm::vec3(targetScale, targetScale, 1.0f)) * glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); @@ -2433,6 +2441,20 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // Setup 3D lights (after the camera transform, so that they are positioned in world space) setupWorldLight(); + // setup shadow matrices (again, after the camera transform) + int shadowMatrixCount = 0; + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { + shadowMatrixCount = 1; + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + shadowMatrixCount = CASCADED_SHADOW_MATRIX_COUNT; + } + for (int i = shadowMatrixCount - 1; i >= 0; i--) { + glActiveTexture(GL_TEXTURE0 + i); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][0]); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][1]); + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]); + } + if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); diff --git a/interface/src/Application.h b/interface/src/Application.h index 59f9ad4e15..68d437815b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,7 +126,6 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; -static const int SHADOW_MATRIX_COUNT = 4; static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; class Application : public QApplication { @@ -264,8 +263,6 @@ public: /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); - const glm::mat4* getShadowMatrices() const { return _shadowMatrices; } - void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); @@ -494,7 +491,8 @@ private: float _rotateMirror; float _raiseMirror; - glm::mat4 _shadowMatrices[SHADOW_MATRIX_COUNT]; + static const int CASCADED_SHADOW_MATRIX_COUNT = 4; + glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT]; Environment _environment; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 45b4089a11..ef5ffeaaf1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -303,7 +303,12 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); + QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); + QActionGroup* shadowGroup = new QActionGroup(shadowMenu); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); + shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); @@ -666,6 +671,10 @@ void Menu::scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set) { set->endGroup(); } +bool Menu::getShadowsEnabled() const { + return isOptionChecked(MenuOption::SimpleShadows) || isOptionChecked(MenuOption::CascadedShadows); +} + void Menu::handleViewFrustumOffsetKeyModifier(int key) { const float VIEW_FRUSTUM_OFFSET_DELTA = 0.5f; const float VIEW_FRUSTUM_OFFSET_UP_DELTA = 0.05f; @@ -836,8 +845,8 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { } } -bool Menu::isOptionChecked(const QString& menuOption) { - QAction* menu = _actionHash.value(menuOption); +bool Menu::isOptionChecked(const QString& menuOption) const { + const QAction* menu = _actionHash.value(menuOption); if (menu) { return menu->isChecked(); } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 012dc1662c..e973ae88b3 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -102,6 +102,8 @@ public: int getMaxVoxels() const { return _maxVoxels; } QAction* getUseVoxelShader() const { return _useVoxelShader; } + bool getShadowsEnabled() const; + void handleViewFrustumOffsetKeyModifier(int key); // User Tweakable LOD Items @@ -170,7 +172,7 @@ public slots: void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); - bool isOptionChecked(const QString& menuOption); + bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); private slots: @@ -301,6 +303,7 @@ namespace MenuOption { const QString Bandwidth = "Bandwidth Display"; const QString BandwidthDetails = "Bandwidth Details"; const QString BuckyBalls = "Bucky Balls"; + const QString CascadedShadows = "Cascaded"; const QString Chat = "Chat..."; const QString ChatCircling = "Chat Circling"; const QString CollideWithAvatars = "Collide With Avatars"; @@ -376,7 +379,7 @@ namespace MenuOption { const QString ScriptEditor = "Script Editor..."; const QString SettingsExport = "Export Settings"; const QString SettingsImport = "Import Settings"; - const QString Shadows = "Shadows"; + const QString SimpleShadows = "Simple"; const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowBordersModelNodes = "Show Model Nodes"; const QString ShowBordersParticleNodes = "Show Particle Nodes"; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 7c9ba50346..1839e20ef7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -508,7 +508,7 @@ bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5f * alpha); - receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows); + receiveShadows &= Menu::getInstance()->getShadowsEnabled(); renderMeshes(alpha, mode, false, receiveShadows); glDisable(GL_ALPHA_TEST); @@ -1508,14 +1508,6 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); - if (receiveShadows) { - for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { - glActiveTexture(GL_TEXTURE0 + i); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); - } - } for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 11bd47b7e4..3525a086b4 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -518,9 +518,19 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.bind(); _shadowMapProgram.setUniformValue("shadowMap", 0); - _shadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); _shadowMapProgram.release(); + + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/cascaded_shadow_map.vert"); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/cascaded_shadow_map.frag"); + _cascadedShadowMapProgram.link(); + + _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniformValue("shadowMap", 0); + _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapProgram.release(); } } _renderer = new PrimitiveRenderer(_maxVoxels); @@ -1168,6 +1178,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo ProgramObject VoxelSystem::_perlinModulateProgram; ProgramObject VoxelSystem::_shadowMapProgram; +ProgramObject VoxelSystem::_cascadedShadowMapProgram; void VoxelSystem::init() { if (_initialized) { @@ -1488,16 +1499,14 @@ void VoxelSystem::render() { void VoxelSystem::applyScaleAndBindProgram(bool texture) { - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { - _shadowMapProgram.bind(); + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + _cascadedShadowMapProgram.bind(); + } else { + _shadowMapProgram.bind(); + } glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); - for (int i = SHADOW_MATRIX_COUNT - 1; i >= 0; i--) { - glActiveTexture(GL_TEXTURE0 + i); - glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][0]); - glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][1]); - glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrices()[i][2]); - } } else if (texture) { _perlinModulateProgram.bind(); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); @@ -1511,11 +1520,14 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { // scale back down to 1 so heads aren't massive glPopMatrix(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { - _shadowMapProgram.release(); + if (Menu::getInstance()->getShadowsEnabled()) { + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + _cascadedShadowMapProgram.release(); + } else { + _shadowMapProgram.release(); + } glBindTexture(GL_TEXTURE_2D, 0); - } else if (texture) { _perlinModulateProgram.release(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index 15e2b20a75..acd0cd170a 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -233,6 +233,7 @@ private: static ProgramObject _perlinModulateProgram; static ProgramObject _shadowMapProgram; + static ProgramObject _cascadedShadowMapProgram; int _hookID; std::vector _freeIndexes; From f82be105e8056f9835e3cbba34561455e3207393 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 12:54:34 -0700 Subject: [PATCH 38/77] moved _sequenceNumber back to OctreeQueryNode --- assignment-client/src/models/ModelServer.cpp | 6 +++--- assignment-client/src/models/ModelServer.h | 2 +- assignment-client/src/octree/OctreeQueryNode.cpp | 15 ++++++++++++--- assignment-client/src/octree/OctreeQueryNode.h | 8 +++++++- assignment-client/src/octree/OctreeSendThread.cpp | 10 +++++----- assignment-client/src/octree/OctreeServer.h | 2 +- .../src/particles/ParticleServer.cpp | 6 +++--- assignment-client/src/particles/ParticleServer.h | 2 +- assignment-client/src/voxels/VoxelServer.cpp | 6 +++--- assignment-client/src/voxels/VoxelServer.h | 2 +- 10 files changed, 37 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/models/ModelServer.cpp b/assignment-client/src/models/ModelServer.cpp index 8f322e4c82..ff2367ec6e 100644 --- a/assignment-client/src/models/ModelServer.cpp +++ b/assignment-client/src/models/ModelServer.cpp @@ -86,7 +86,7 @@ bool ModelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedModels; } -int ModelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { +int ModelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -100,13 +100,13 @@ int ModelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 models? while (hasMoreToSend) { - hasMoreToSend = tree->encodeModelsDeletedSince(sequenceNumber, deletedModelsSentAt, + hasMoreToSend = tree->encodeModelsDeletedSince(queryNode->getSequenceNumber(), deletedModelsSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); //qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); - sequenceNumber++; + queryNode->incrementSequenceNumber(); } nodeData->setLastDeletedModelsSentAt(deletePacketSentAt); diff --git a/assignment-client/src/models/ModelServer.h b/assignment-client/src/models/ModelServer.h index 35cb79d8cf..7e7f239f2a 100644 --- a/assignment-client/src/models/ModelServer.h +++ b/assignment-client/src/models/ModelServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); + virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f7b293dfa8..30df4373f5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -38,6 +38,7 @@ OctreeQueryNode::OctreeQueryNode() : _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _lodChanged(false), _lodInitialized(false), + _sequenceNumber(0), _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), _isShuttingDown(false) @@ -157,11 +158,11 @@ bool OctreeQueryNode::shouldSuppressDuplicatePacket() { void OctreeQueryNode::init() { _myPacketType = getMyPacketType(); - resetOctreePacket(0); // don't bump sequence + resetOctreePacket(); // don't bump sequence } -void OctreeQueryNode::resetOctreePacket(OCTREE_PACKET_SEQUENCE sequenceNumber) { +void OctreeQueryNode::resetOctreePacket() { // if shutting down, return immediately if (_isShuttingDown) { return; @@ -199,7 +200,7 @@ void OctreeQueryNode::resetOctreePacket(OCTREE_PACKET_SEQUENCE sequenceNumber) { // pack in sequence number OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)_octreePacketAt; - *sequenceAt = sequenceNumber; + *sequenceAt = _sequenceNumber; _octreePacketAt += sizeof(OCTREE_PACKET_SEQUENCE); _octreePacketAvailableBytes -= sizeof(OCTREE_PACKET_SEQUENCE); @@ -361,3 +362,11 @@ void OctreeQueryNode::dumpOutOfView() { } } } + +void OctreeQueryNode::incrementSequenceNumber() { + _sequenceNumber++; +} + +OCTREE_PACKET_SEQUENCE OctreeQueryNode::getSequenceNumber() { + return _sequenceNumber; +} \ No newline at end of file diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index eeea98699c..f60634f33d 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -35,7 +35,7 @@ public: void init(); // called after creation to set up some virtual items virtual PacketType getMyPacketType() const = 0; - void resetOctreePacket(OCTREE_PACKET_SEQUENCE sequenceNumber); // resets octree packet to after "V" header + void resetOctreePacket(); // resets octree packet to after "V" header void writeToPacket(const unsigned char* buffer, unsigned int bytes); // writes to end of packet @@ -99,6 +99,10 @@ public: void nodeKilled(); void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } + + void incrementSequenceNumber(); + + OCTREE_PACKET_SEQUENCE getSequenceNumber(); private slots: void sendThreadFinished(); @@ -136,6 +140,8 @@ private: bool _lodChanged; bool _lodInitialized; + OCTREE_PACKET_SEQUENCE _sequenceNumber; + quint64 _lastRootTimestamp; PacketType _myPacketType; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index a396e1170c..d8aebd0cdf 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -138,7 +138,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about // this rate control savings. if (nodeData->shouldSuppressDuplicatePacket()) { - nodeData->resetOctreePacket(_sequenceNumber); // we still need to reset it though! + nodeData->resetOctreePacket(); // we still need to reset it though! return packetsSent; // without sending... } @@ -248,7 +248,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes truePacketsSent++; packetsSent++; _sequenceNumber++; - nodeData->resetOctreePacket(_sequenceNumber); + nodeData->resetOctreePacket(); } return packetsSent; @@ -288,7 +288,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->isPacketWaiting()) { packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); } else { - nodeData->resetOctreePacket(_sequenceNumber); + nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (wantCompression) { @@ -534,8 +534,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets if (_myServer->hasSpecialPacketToSend(_node) && !nodeData->isShuttingDown()) { - trueBytesSent += _myServer->sendSpecialPacket(_sequenceNumber, _node); - nodeData->resetOctreePacket(_sequenceNumber); // because _sequenceNumber has changed + trueBytesSent += _myServer->sendSpecialPacket(nodeData, _node); + nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed truePacketsSent++; packetsSentThisInterval++; } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index df8519e200..f0db93feb3 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -72,7 +72,7 @@ public: // subclass may implement these method virtual void beforeRun() { }; virtual bool hasSpecialPacketToSend(const SharedNodePointer& node) { return false; } - virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { return 0; } + virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { return 0; } static void attachQueryNodeToNode(Node* newNode); diff --git a/assignment-client/src/particles/ParticleServer.cpp b/assignment-client/src/particles/ParticleServer.cpp index e752900059..1dd65f11f3 100644 --- a/assignment-client/src/particles/ParticleServer.cpp +++ b/assignment-client/src/particles/ParticleServer.cpp @@ -86,7 +86,7 @@ bool ParticleServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendDeletedParticles; } -int ParticleServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { +int ParticleServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { unsigned char outputBuffer[MAX_PACKET_SIZE]; size_t packetLength = 0; @@ -100,13 +100,13 @@ int ParticleServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, co // TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 particles? while (hasMoreToSend) { - hasMoreToSend = tree->encodeParticlesDeletedSince(sequenceNumber, deletedParticlesSentAt, + hasMoreToSend = tree->encodeParticlesDeletedSince(queryNode->getSequenceNumber(), deletedParticlesSentAt, outputBuffer, MAX_PACKET_SIZE, packetLength); //qDebug() << "sending PacketType_PARTICLE_ERASE packetLength:" << packetLength; NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, SharedNodePointer(node)); - sequenceNumber++; + queryNode->incrementSequenceNumber(); } nodeData->setLastDeletedParticlesSentAt(deletePacketSentAt); diff --git a/assignment-client/src/particles/ParticleServer.h b/assignment-client/src/particles/ParticleServer.h index cb8e128475..3066c5fa98 100644 --- a/assignment-client/src/particles/ParticleServer.h +++ b/assignment-client/src/particles/ParticleServer.h @@ -37,7 +37,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); + virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); virtual void particleCreated(const Particle& newParticle, const SharedNodePointer& senderNode); diff --git a/assignment-client/src/voxels/VoxelServer.cpp b/assignment-client/src/voxels/VoxelServer.cpp index 43d01f1c77..8f4a8bab36 100644 --- a/assignment-client/src/voxels/VoxelServer.cpp +++ b/assignment-client/src/voxels/VoxelServer.cpp @@ -40,7 +40,7 @@ bool VoxelServer::hasSpecialPacketToSend(const SharedNodePointer& node) { return shouldSendEnvironments; } -int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node) { +int VoxelServer::sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node) { unsigned char* copyAt = _tempOutputBuffer; @@ -57,7 +57,7 @@ int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const // pack in sequence number OCTREE_PACKET_SEQUENCE* sequenceAt = (OCTREE_PACKET_SEQUENCE*)copyAt; - *sequenceAt = sequenceNumber; + *sequenceAt = queryNode->getSequenceNumber(); copyAt += sizeof(OCTREE_PACKET_SEQUENCE); envPacketLength += sizeof(OCTREE_PACKET_SEQUENCE); @@ -75,7 +75,7 @@ int VoxelServer::sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const } NodeList::getInstance()->writeDatagram((char*) _tempOutputBuffer, envPacketLength, SharedNodePointer(node)); - sequenceNumber++; + queryNode->incrementSequenceNumber(); return envPacketLength; } diff --git a/assignment-client/src/voxels/VoxelServer.h b/assignment-client/src/voxels/VoxelServer.h index b9277fed0c..4e04c48cfd 100644 --- a/assignment-client/src/voxels/VoxelServer.h +++ b/assignment-client/src/voxels/VoxelServer.h @@ -46,7 +46,7 @@ public: // subclass may implement these method virtual void beforeRun(); virtual bool hasSpecialPacketToSend(const SharedNodePointer& node); - virtual int sendSpecialPacket(OCTREE_PACKET_SEQUENCE& sequenceNumber, const SharedNodePointer& node); + virtual int sendSpecialPacket(OctreeQueryNode* queryNode, const SharedNodePointer& node); private: bool _sendEnvironments; From d8b0b03e591f1a1471cf4128e2f4f1beb925cc86 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 13:39:57 -0700 Subject: [PATCH 39/77] removed _sequenceNumber from OctreeSendThread inlined getSequenceNumber and incrementSequenceNumber --- assignment-client/src/octree/OctreeQueryNode.h | 4 ++-- assignment-client/src/octree/OctreeSendThread.cpp | 5 ++--- assignment-client/src/octree/OctreeSendThread.h | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index f60634f33d..eb420039e6 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -100,9 +100,9 @@ public: void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } - void incrementSequenceNumber(); + void incrementSequenceNumber() { _sequenceNumber++; } - OCTREE_PACKET_SEQUENCE getSequenceNumber(); + OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } private slots: void sendThreadFinished(); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d8aebd0cdf..fab9be24d3 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -28,8 +28,7 @@ OctreeSendThread::OctreeSendThread(const SharedAssignmentPointer& myAssignment, _nodeUUID(node->getUUID()), _packetData(), _nodeMissingCount(0), - _isShuttingDown(false), - _sequenceNumber(0) + _isShuttingDown(false) { QString safeServerName("Octree"); if (_myServer) { @@ -247,7 +246,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes trueBytesSent += nodeData->getPacketLength(); truePacketsSent++; packetsSent++; - _sequenceNumber++; + nodeData->incrementSequenceNumber(); nodeData->resetOctreePacket(); } diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 9dcf266cd8..d8eed27802 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -55,8 +55,6 @@ private: int _nodeMissingCount; bool _isShuttingDown; - - OCTREE_PACKET_SEQUENCE _sequenceNumber; }; #endif // hifi_OctreeSendThread_h From bd4d16768440b2c636f48bfca9344078dd6c15af Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 29 May 2014 14:13:02 -0700 Subject: [PATCH 40/77] Make JavaScript audio samples able to be looped Add a "loop" property to AudioInjectorOptions and provide an example JavaScript file. --- examples/playSoundLoop.js | 43 ++++++++++++++++++++ libraries/audio/src/AudioInjector.cpp | 5 +++ libraries/audio/src/AudioInjectorOptions.cpp | 2 + libraries/audio/src/AudioInjectorOptions.h | 5 +++ 4 files changed, 55 insertions(+) create mode 100644 examples/playSoundLoop.js diff --git a/examples/playSoundLoop.js b/examples/playSoundLoop.js new file mode 100644 index 0000000000..86226468bc --- /dev/null +++ b/examples/playSoundLoop.js @@ -0,0 +1,43 @@ +// +// playSoundLoop.js +// examples +// +// Created by David Rowe on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// This example script plays a sound in a continuous loop. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var sound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw"); + +var soundPlaying = false; + +function keyPressEvent(event) { + if (event.text === "1") { + if (!Audio.isInjectorPlaying(soundPlaying)) { + var options = new AudioInjectionOptions(); + options.position = MyAvatar.position; + options.volume = 0.5; + options.loop = true; + soundPlaying = Audio.playSound(sound, options); + print("Started sound loop"); + } else { + Audio.stopInjector(soundPlaying); + print("Stopped sound loop"); + } + } +} + +function scriptEnding() { + if (Audio.isInjectorPlaying(soundPlaying)) { + Audio.stopInjector(soundPlaying); + print("Stopped sound loop"); + } +} + +// Connect a call back that happens every frame +Script.scriptEnding.connect(scriptEnding); +Controller.keyPressEvent.connect(keyPressEvent); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 1fe9f1336f..129dc47bd0 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -88,6 +88,7 @@ void AudioInjector::injectAudio() { int currentSendPosition = 0; int numPreAudioDataBytes = injectAudioPacket.size(); + bool shouldLoop = _options.getLoop(); // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks while (currentSendPosition < soundByteArray.size() && !_shouldStop) { @@ -120,6 +121,10 @@ void AudioInjector::injectAudio() { usleep(usecToSleep); } } + + if (shouldLoop && currentSendPosition == soundByteArray.size()) { + currentSendPosition = 0; + } } } diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp index cd6b08f6c7..49f1571c98 100644 --- a/libraries/audio/src/AudioInjectorOptions.cpp +++ b/libraries/audio/src/AudioInjectorOptions.cpp @@ -15,6 +15,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : QObject(parent), _position(0.0f, 0.0f, 0.0f), _volume(1.0f), + _loop(false), _orientation(glm::vec3(0.0f, 0.0f, 0.0f)), _loopbackAudioInterface(NULL) { @@ -24,6 +25,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) : AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) { _position = other._position; _volume = other._volume; + _loop = other._loop; _orientation = other._orientation; _loopbackAudioInterface = other._loopbackAudioInterface; } diff --git a/libraries/audio/src/AudioInjectorOptions.h b/libraries/audio/src/AudioInjectorOptions.h index bbe3d57b08..b90deb93f1 100644 --- a/libraries/audio/src/AudioInjectorOptions.h +++ b/libraries/audio/src/AudioInjectorOptions.h @@ -26,6 +26,7 @@ class AudioInjectorOptions : public QObject { Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) Q_PROPERTY(float volume READ getVolume WRITE setVolume) + Q_PROPERTY(bool loop READ getLoop WRITE setLoop) public: AudioInjectorOptions(QObject* parent = 0); AudioInjectorOptions(const AudioInjectorOptions& other); @@ -36,6 +37,9 @@ public: float getVolume() const { return _volume; } void setVolume(float volume) { _volume = volume; } + float getLoop() const { return _loop; } + void setLoop(float loop) { _loop = loop; } + const glm::quat& getOrientation() const { return _orientation; } void setOrientation(const glm::quat& orientation) { _orientation = orientation; } @@ -45,6 +49,7 @@ public: private: glm::vec3 _position; float _volume; + bool _loop; glm::quat _orientation; AbstractAudioInterface* _loopbackAudioInterface; }; From b91fd19f39a270761dd1e21520a04fa59e4323c0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 14:30:28 -0700 Subject: [PATCH 41/77] snapped attachment to center and scale them to fit --- interface/src/avatar/Avatar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 55c0830dfb..ac6718dcc8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -378,10 +378,10 @@ void Avatar::simulateAttachments(float deltaTime) { model->setLODDistance(getLODDistance()); } if (_skeletonModel.getJointPosition(jointIndex, jointPosition) && - _skeletonModel.getJointRotation(jointIndex, jointRotation)) { + _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setRotation(jointRotation * attachment.rotation); - model->setScale(_skeletonModel.getScale() * attachment.scale); + model->setScaleToFit(true, _scale * attachment.scale); model->simulate(deltaTime); } } @@ -749,7 +749,6 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // make sure we have as many models as attachments while (_attachmentModels.size() < attachmentData.size()) { Model* model = new Model(this); - model->setSnapModelToCenter(true); model->init(); _attachmentModels.append(model); } @@ -759,6 +758,8 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { // update the urls for (int i = 0; i < attachmentData.size(); i++) { + _attachmentModels[i]->setSnapModelToCenter(true); + _attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale); _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); } } From 4c4ff45f318f8b31079d6b5b2922cd837bbf599e Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 29 May 2014 14:31:40 -0700 Subject: [PATCH 42/77] removed duplicate function bodies --- assignment-client/src/octree/OctreeQueryNode.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 30df4373f5..6acd85bff6 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -362,11 +362,3 @@ void OctreeQueryNode::dumpOutOfView() { } } } - -void OctreeQueryNode::incrementSequenceNumber() { - _sequenceNumber++; -} - -OCTREE_PACKET_SEQUENCE OctreeQueryNode::getSequenceNumber() { - return _sequenceNumber; -} \ No newline at end of file From b34453647b37cee3b0e8ceaf43df716684e23a64 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 14:34:10 -0700 Subject: [PATCH 43/77] editModels click/drag/attach tweaks --- examples/editModels.js | 69 +++++------------------------------------- 1 file changed, 8 insertions(+), 61 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index cf9b9abbdc..7cf78d592e 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,16 +40,7 @@ var modelURLs = [ var toolBar; - var jointList = MyAvatar.getJointNames(); -//print("\n# Joint list start"); -//for (var i = 0; i < jointList.length; i++) { -// Vec3.print("jointIndex = " + jointList[i] + " = " + i, MyAvatar.getJointPosition(jointList[i])); -//} -//print("# Joint list end"); - - - function isLocked(properties) { // special case to lock the ground plane model in hq. @@ -156,6 +147,10 @@ function controller(wichSide) { this.release = function () { if (this.grabbing) { + if (jointList.length <= 0) { + jointList = MyAvatar.getJointNames(); + } + var closestJointIndex = -1; var closestJointDistance = 10; for (var i = 0; i < jointList.length; i++) { @@ -169,22 +164,19 @@ function controller(wichSide) { print("closestJointIndex: " + closestJointIndex); print("closestJointDistance: " + closestJointDistance); - if (closestJointDistance < 0.1) { + if (closestJointDistance < this.oldModelRadius) { print("Attaching to " + jointList[closestJointIndex]); var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - var attachmentOffset = Vec3.multiply(Vec3.subtract(this.oldModelPosition, jointPosition), 2); + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 0.75, + attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, true, false); - Vec3.print("offset: ", attachmentOffset); - Vec3.print("joint: ", Quat.safeEulerAngles(jointRotation)); - Vec3.print("model: ", Quat.safeEulerAngles(this.oldModelRotation)); - Vec3.print("delta: ", Quat.safeEulerAngles(attachmentRotation)); + Models.deleteModel(this.modelID); } } @@ -468,52 +460,7 @@ function checkController(deltaTime) { } moveOverlays(); - - - - leftController.hideLaser(); - rightController.hideLaser(); - var jointPos = MyAvatar.getJointPosition("RightHand"); - var jointRot = MyAvatar.getJointCombinedRotation("RightHand"); - - Overlays.editOverlay(r, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:1, y:0, z:0 })) - }); - Overlays.editOverlay(g, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:1, z:0 })) - }); - Overlays.editOverlay(b, { - position: jointPos, - end: Vec3.sum(jointPos, Vec3.multiplyQbyV(jointRot, { x:0, y:0, z:1 })) - }); } -var r = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 255, green: 0, blue: 0 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); -var g = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 255, blue: 0 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); -var b = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0 }, - end: { x: 0, y: 0, z: 0 }, - color: { red: 0, green: 0, blue: 255 }, - alpha: 1, - visible: true, - lineWidth: LASER_WIDTH - }); - function initToolBar() { toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); From 980e873a1350bd8dac5bc36713ff4f59442eab6d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:02:09 -0700 Subject: [PATCH 44/77] Better prints in editModels --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 7cf78d592e..89be4089a0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -161,8 +161,8 @@ function controller(wichSide) { } } - print("closestJointIndex: " + closestJointIndex); - print("closestJointDistance: " + closestJointDistance); + print("closestJoint: " + jojntList[closestJointIndex]); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); if (closestJointDistance < this.oldModelRadius) { print("Attaching to " + jointList[closestJointIndex]); From 3e207f9452ade9ac88408a73ba1fc7739d0faa30 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:09:42 -0700 Subject: [PATCH 45/77] fixed display error in editVoxels with new boundaries --- examples/editVoxels.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 14bea50bb0..22df8604e1 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -28,8 +28,10 @@ var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; var PIXELS_PER_EXTRUDE_VOXEL = 16; var WHEEL_PIXELS_PER_SCALE_CHANGE = 100; -var MAX_VOXEL_SCALE = 16.0; -var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0); +var MAX_VOXEL_SCALE_POWER = 4; +var MIN_VOXEL_SCALE_POWER = -8; +var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER); +var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER); var WHITE_COLOR = { red: 255, green: 255, blue: 255 }; var MAX_PASTE_VOXEL_SCALE = 256; @@ -330,6 +332,13 @@ function ScaleSelector() { visible: false }); this.setScale = function(scale) { + if (scale > MAX_VOXEL_SCALE) { + scale = MAX_VOXEL_SCALE; + } + if (scale < MIN_VOXEL_SCALE) { + scale = MIN_VOXEL_SCALE; + } + this.scale = scale; this.power = Math.floor(Math.log(scale) / Math.log(2)); rescaleImport(); @@ -391,12 +400,9 @@ function ScaleSelector() { this.incrementScale = function() { copyScale = false; - if (this.power < 13) { + if (this.power < MAX_VOXEL_SCALE_POWER) { ++this.power; this.scale *= 2.0; - if (this.scale > MAX_VOXEL_SCALE) { - this.scale = MAX_VOXEL_SCALE; - } this.update(); rescaleImport(); resizeVoxelSound.play(voxelSizePlus); @@ -405,7 +411,7 @@ function ScaleSelector() { this.decrementScale = function() { copyScale = false; - if (-4 < this.power) { + if (MIN_VOXEL_SCALE_POWER < this.power) { --this.power; this.scale /= 2.0; this.update(); From 391902f79bfdd5ffea0956d1fc525537cbfbf4fa Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 15:30:40 -0700 Subject: [PATCH 46/77] Cascaded shadow maps for models. --- .../shaders/cascaded_shadow_map.frag | 15 +- .../shaders/model_cascaded_shadow_map.frag | 56 ++++++ .../model_cascaded_shadow_normal_map.frag | 69 +++++++ ...l_cascaded_shadow_normal_specular_map.frag | 72 ++++++++ .../model_cascaded_shadow_specular_map.frag | 59 ++++++ interface/src/renderer/Model.cpp | 170 ++++++++++++++++-- interface/src/renderer/Model.h | 16 ++ 7 files changed, 440 insertions(+), 17 deletions(-) create mode 100644 interface/resources/shaders/model_cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_normal_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag create mode 100644 interface/resources/shaders/model_cascaded_shadow_specular_map.frag diff --git a/interface/resources/shaders/cascaded_shadow_map.frag b/interface/resources/shaders/cascaded_shadow_map.frag index 9b3e8f7cc7..337f98a228 100644 --- a/interface/resources/shaders/cascaded_shadow_map.frag +++ b/interface/resources/shaders/cascaded_shadow_map.frag @@ -11,10 +11,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// the shadow texture uniform sampler2DShadow shadowMap; +// the distances to the cascade sections uniform vec3 shadowDistances; +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + // the color in shadow varying vec4 shadowColor; @@ -22,8 +27,14 @@ varying vec4 shadowColor; varying vec4 position; void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); - vec3 texCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), dot(gl_EyePlaneR[shadowIndex], position)); - gl_FragColor = mix(shadowColor, gl_Color, shadow2D(shadowMap, texCoord).r); + + gl_FragColor = mix(shadowColor, gl_Color, 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r)); } diff --git a/interface/resources/shaders/model_cascaded_shadow_map.frag b/interface/resources/shaders/model_cascaded_shadow_map.frag new file mode 100644 index 0000000000..720c43b656 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_map.frag @@ -0,0 +1,56 @@ +#version 120 + +// +// model_cascaded_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_normal_map.frag b/interface/resources/shaders/model_cascaded_shadow_normal_map.frag new file mode 100644 index 0000000000..5758333392 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_normal_map.frag @@ -0,0 +1,69 @@ +#version 120 + +// +// model_cascaded_shadow_normal_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneT[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneR[shadowIndex], interpolatedPosition)); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag b/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag new file mode 100644 index 0000000000..2b949710f3 --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_normal_specular_map.frag @@ -0,0 +1,72 @@ +#version 120 + +// +// model_cascaded_shadow_normal_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the normal map texture +uniform sampler2D normalMap; + +// the specular map texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 interpolatedPosition; + +// the interpolated normal +varying vec4 interpolatedNormal; + +// the interpolated tangent +varying vec4 interpolatedTangent; + +void main(void) { + vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); + vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); + vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); + vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); + + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneT[shadowIndex], interpolatedPosition), + dot(gl_EyePlaneR[shadowIndex], interpolatedPosition)); + + // compute the base color based on OpenGL lighting model + vec4 viewNormal = vec4(normalizedTangent * localNormal.x + + normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); + float diffuse = dot(viewNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - + normalize(vec4(interpolatedPosition.xyz, 0.0))), viewNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/resources/shaders/model_cascaded_shadow_specular_map.frag b/interface/resources/shaders/model_cascaded_shadow_specular_map.frag new file mode 100644 index 0000000000..ba8ba6b85b --- /dev/null +++ b/interface/resources/shaders/model_cascaded_shadow_specular_map.frag @@ -0,0 +1,59 @@ +#version 120 + +// +// model_cascaded_shadow_specular_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/29/14. +// Copyright 2014 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 +// + +// the diffuse texture +uniform sampler2D diffuseMap; + +// the specular texture +uniform sampler2D specularMap; + +// the shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position in view space +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + vec4 normalizedNormal = normalize(normal); + float diffuse = dot(normalizedNormal, gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + + // compute the specular component (sans exponent) + float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), + normalizedNormal)); + + // modulate texture by base color and add specular contribution + gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * + gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0); +} diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1839e20ef7..a550064ef1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -65,6 +65,11 @@ ProgramObject Model::_shadowNormalMapProgram; ProgramObject Model::_shadowSpecularMapProgram; ProgramObject Model::_shadowNormalSpecularMapProgram; +ProgramObject Model::_cascadedShadowMapProgram; +ProgramObject Model::_cascadedShadowNormalMapProgram; +ProgramObject Model::_cascadedShadowSpecularMapProgram; +ProgramObject Model::_cascadedShadowNormalSpecularMapProgram; + ProgramObject Model::_shadowProgram; ProgramObject Model::_skinProgram; @@ -77,12 +82,19 @@ ProgramObject Model::_skinShadowNormalMapProgram; ProgramObject Model::_skinShadowSpecularMapProgram; ProgramObject Model::_skinShadowNormalSpecularMapProgram; +ProgramObject Model::_skinCascadedShadowMapProgram; +ProgramObject Model::_skinCascadedShadowNormalMapProgram; +ProgramObject Model::_skinCascadedShadowSpecularMapProgram; +ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram; + ProgramObject Model::_skinShadowProgram; int Model::_normalMapTangentLocation; int Model::_normalSpecularMapTangentLocation; int Model::_shadowNormalMapTangentLocation; int Model::_shadowNormalSpecularMapTangentLocation; +int Model::_cascadedShadowNormalMapTangentLocation; +int Model::_cascadedShadowNormalSpecularMapTangentLocation; Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; @@ -92,6 +104,10 @@ Model::SkinLocations Model::_skinShadowMapLocations; Model::SkinLocations Model::_skinShadowNormalMapLocations; Model::SkinLocations Model::_skinShadowSpecularMapLocations; Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations; +Model::SkinLocations Model::_skinCascadedShadowMapLocations; +Model::SkinLocations Model::_skinCascadedShadowNormalMapLocations; +Model::SkinLocations Model::_skinCascadedShadowSpecularMapLocations; +Model::SkinLocations Model::_skinCascadedShadowNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; void Model::setScale(const glm::vec3& scale) { @@ -132,6 +148,8 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); + program.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); program.release(); } @@ -229,7 +247,7 @@ void Model::init() { _normalSpecularMapProgram.setUniformValue("diffuseMap", 0); _normalSpecularMapProgram.setUniformValue("normalMap", 1); _normalSpecularMapProgram.setUniformValue("specularMap", 2); - _normalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _normalSpecularMapTangentLocation = _normalSpecularMapProgram.attributeLocation("tangent"); _normalSpecularMapProgram.release(); @@ -279,10 +297,69 @@ void Model::init() { _shadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); _shadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); _shadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); - _shadowNormalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent"); + _shadowNormalSpecularMapTangentLocation = _shadowNormalSpecularMapProgram.attributeLocation("tangent"); _shadowNormalSpecularMapProgram.release(); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/model.vert"); + _cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_cascaded_shadow_map.frag"); + _cascadedShadowMapProgram.link(); + + _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowMapProgram.setUniformValue("shadowMap", 1); + _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapProgram.release(); + + _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); + _cascadedShadowNormalMapProgram.link(); + + _cascadedShadowNormalMapProgram.bind(); + _cascadedShadowNormalMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowNormalMapProgram.setUniformValue("normalMap", 1); + _cascadedShadowNormalMapProgram.setUniformValue("shadowMap", 2); + _cascadedShadowNormalMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalMapTangentLocation = _cascadedShadowNormalMapProgram.attributeLocation("tangent"); + _cascadedShadowNormalMapProgram.release(); + + _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model.vert"); + _cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); + _cascadedShadowSpecularMapProgram.link(); + + _cascadedShadowSpecularMapProgram.bind(); + _cascadedShadowSpecularMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowSpecularMapProgram.setUniformValue("specularMap", 1); + _cascadedShadowSpecularMapProgram.setUniformValue("shadowMap", 2); + _cascadedShadowSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowSpecularMapProgram.release(); + + _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/model_normal_map.vert"); + _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); + _cascadedShadowNormalSpecularMapProgram.link(); + + _cascadedShadowNormalSpecularMapProgram.bind(); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("diffuseMap", 0); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); + _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], + -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalSpecularMapTangentLocation = _cascadedShadowNormalSpecularMapProgram.attributeLocation("tangent"); + _cascadedShadowNormalSpecularMapProgram.release(); + + _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); @@ -353,6 +430,39 @@ void Model::init() { initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3); + _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/skin_model.vert"); + _skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/model_cascaded_shadow_map.frag"); + _skinCascadedShadowMapProgram.link(); + + initSkinProgram(_skinCascadedShadowMapProgram, _skinCascadedShadowMapLocations); + + _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag"); + _skinCascadedShadowNormalMapProgram.link(); + + initSkinProgram(_skinCascadedShadowNormalMapProgram, _skinCascadedShadowNormalMapLocations, 1, 2); + + _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model.vert"); + _skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag"); + _skinCascadedShadowSpecularMapProgram.link(); + + initSkinProgram(_skinCascadedShadowSpecularMapProgram, _skinCascadedShadowSpecularMapLocations, 1, 2); + + _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); + _skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag"); + _skinCascadedShadowNormalSpecularMapProgram.link(); + + initSkinProgram(_skinCascadedShadowNormalSpecularMapProgram, _skinCascadedShadowNormalSpecularMapLocations, 2, 3); + + _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, @@ -1508,6 +1618,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); + bool cascadedShadows = Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows); for (int i = 0; i < networkMeshes.size(); i++) { // exit early if the translucency doesn't match what we're drawing const NetworkMesh& networkMesh = networkMeshes.at(i); @@ -1529,6 +1640,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; + int tangentLocation = _normalMapTangentLocation; GLenum specularTextureUnit = 0; GLenum shadowTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { @@ -1539,21 +1651,38 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re } else if (!mesh.tangents.isEmpty()) { if (mesh.hasSpecularTexture()) { if (receiveShadows) { - program = &_shadowNormalSpecularMapProgram; - skinProgram = &_skinShadowNormalSpecularMapProgram; - skinLocations = &_skinShadowNormalSpecularMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowNormalSpecularMapProgram; + skinProgram = &_skinCascadedShadowNormalSpecularMapProgram; + skinLocations = &_skinCascadedShadowNormalSpecularMapLocations; + tangentLocation = _cascadedShadowNormalSpecularMapTangentLocation; + } else { + program = &_shadowNormalSpecularMapProgram; + skinProgram = &_skinShadowNormalSpecularMapProgram; + skinLocations = &_skinShadowNormalSpecularMapLocations; + tangentLocation = _shadowNormalSpecularMapTangentLocation; + } shadowTextureUnit = GL_TEXTURE3; } else { program = &_normalSpecularMapProgram; skinProgram = &_skinNormalSpecularMapProgram; skinLocations = &_skinNormalSpecularMapLocations; + tangentLocation = _normalSpecularMapTangentLocation; } specularTextureUnit = GL_TEXTURE2; } else if (receiveShadows) { - program = &_shadowNormalMapProgram; - skinProgram = &_skinShadowNormalMapProgram; - skinLocations = &_skinShadowNormalMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowNormalMapProgram; + skinProgram = &_skinCascadedShadowNormalMapProgram; + skinLocations = &_skinCascadedShadowNormalMapLocations; + tangentLocation = _cascadedShadowNormalMapTangentLocation; + } else { + program = &_shadowNormalMapProgram; + skinProgram = &_skinShadowNormalMapProgram; + skinLocations = &_skinShadowNormalMapLocations; + tangentLocation = _shadowNormalMapTangentLocation; + } shadowTextureUnit = GL_TEXTURE2; } else { program = &_normalMapProgram; @@ -1562,9 +1691,15 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re } } else if (mesh.hasSpecularTexture()) { if (receiveShadows) { - program = &_shadowSpecularMapProgram; - skinProgram = &_skinShadowSpecularMapProgram; - skinLocations = &_skinShadowSpecularMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowSpecularMapProgram; + skinProgram = &_skinCascadedShadowSpecularMapProgram; + skinLocations = &_skinCascadedShadowSpecularMapLocations; + } else { + program = &_shadowSpecularMapProgram; + skinProgram = &_skinShadowSpecularMapProgram; + skinLocations = &_skinShadowSpecularMapLocations; + } shadowTextureUnit = GL_TEXTURE2; } else { program = &_specularMapProgram; @@ -1574,15 +1709,20 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re specularTextureUnit = GL_TEXTURE1; } else if (receiveShadows) { - program = &_shadowMapProgram; - skinProgram = &_skinShadowMapProgram; - skinLocations = &_skinShadowMapLocations; + if (cascadedShadows) { + program = &_cascadedShadowMapProgram; + skinProgram = &_skinCascadedShadowMapProgram; + skinLocations = &_skinCascadedShadowMapLocations; + } else { + program = &_shadowMapProgram; + skinProgram = &_skinShadowMapProgram; + skinLocations = &_skinShadowMapLocations; + } shadowTextureUnit = GL_TEXTURE1; } const MeshState& state = _meshStates.at(i); ProgramObject* activeProgram = program; - int tangentLocation = _normalMapTangentLocation; glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index a4e45287dd..5561855afb 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -280,6 +280,11 @@ private: static ProgramObject _shadowSpecularMapProgram; static ProgramObject _shadowNormalSpecularMapProgram; + static ProgramObject _cascadedShadowMapProgram; + static ProgramObject _cascadedShadowNormalMapProgram; + static ProgramObject _cascadedShadowSpecularMapProgram; + static ProgramObject _cascadedShadowNormalSpecularMapProgram; + static ProgramObject _shadowProgram; static ProgramObject _skinProgram; @@ -292,12 +297,19 @@ private: static ProgramObject _skinShadowSpecularMapProgram; static ProgramObject _skinShadowNormalSpecularMapProgram; + static ProgramObject _skinCascadedShadowMapProgram; + static ProgramObject _skinCascadedShadowNormalMapProgram; + static ProgramObject _skinCascadedShadowSpecularMapProgram; + static ProgramObject _skinCascadedShadowNormalSpecularMapProgram; + static ProgramObject _skinShadowProgram; static int _normalMapTangentLocation; static int _normalSpecularMapTangentLocation; static int _shadowNormalMapTangentLocation; static int _shadowNormalSpecularMapTangentLocation; + static int _cascadedShadowNormalMapTangentLocation; + static int _cascadedShadowNormalSpecularMapTangentLocation; class SkinLocations { public: @@ -315,6 +327,10 @@ private: static SkinLocations _skinShadowNormalMapLocations; static SkinLocations _skinShadowSpecularMapLocations; static SkinLocations _skinShadowNormalSpecularMapLocations; + static SkinLocations _skinCascadedShadowMapLocations; + static SkinLocations _skinCascadedShadowNormalMapLocations; + static SkinLocations _skinCascadedShadowSpecularMapLocations; + static SkinLocations _skinCascadedShadowNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; static void initSkinProgram(ProgramObject& program, SkinLocations& locations, From 7e3ef34e6c2ddb053843bc98e8fed8d902c28437 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 15:34:20 -0700 Subject: [PATCH 47/77] CR feedback --- interface/src/ui/Stats.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index d7ca0152fd..42eae260c7 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -219,9 +219,6 @@ void Stats::display( int totalServers = NodeList::getInstance()->size(); lines = _expanded ? 5 : 3; - - - drawBackground(backgroundColor, horizontalOffset, 0, _generalStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; From c7b636365c1ef352d74cc3573b9304a3f6f71f5d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:50:23 -0700 Subject: [PATCH 48/77] Don't attach to joints in range when I grab --- examples/editModels.js | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 89be4089a0..6857ed18cf 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -88,6 +88,8 @@ function controller(wichSide) { this.oldModelPosition; this.oldModelRadius; + this.jointsIntersectingFronStart = []; + this.laser = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 }, @@ -142,6 +144,14 @@ function controller(wichSide) { this.oldModelPosition = properties.position; this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; + + this.jointsIntersectingFronStart = []; + for (var i = 0; i < jointList.length; i++) { + var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); + if (distance < this.oldModelRadius) { + this.jointsIntersectingFronStart.push(i); + } + } } } @@ -161,27 +171,33 @@ function controller(wichSide) { } } - print("closestJoint: " + jojntList[closestJointIndex]); + print("closestJoint: " + jointList[closestJointIndex]); print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); if (closestJointDistance < this.oldModelRadius) { - print("Attaching to " + jointList[closestJointIndex]); - var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); - var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); - var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); - attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); - var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); - - MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, - true, false); - Models.deleteModel(this.modelID); + if (this.jointsIntersectingFronStart.indexOf(closestJointIndex) != -1) { + // Do nothing + } else { + print("Attaching to " + jointList[closestJointIndex]); + var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]); + var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]); + + var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition); + attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset); + var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); + + MyAvatar.attach(this.modelURL, jointList[closestJointIndex], + attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, + true, false); + Models.deleteModel(this.modelID); + } } } this.grabbing = false; this.modelID.isKnownID = false; + this.jointsIntersectingFronStart = []; } this.checkTrigger = function () { From fd0c19513209d2ec40a509d2df68e30d2586c6bb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:55:17 -0700 Subject: [PATCH 49/77] Code cleanup --- examples/editModels.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 6857ed18cf..deada7e1aa 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -305,28 +305,9 @@ function controller(wichSide) { position: newPosition, modelRotation: newRotation }); -// print("Moving " + this.modelID.id); -// Vec3.print("Old Position: ", this.oldModelPosition); -// Vec3.print("Sav Position: ", newPosition); -// Quat.print("Old Rotation: ", this.oldModelRotation); -// Quat.print("New Rotation: ", newRotation); this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; - - - var closestJointIndex = -1; - var closestJointDistance = 10; - for (var i = 0; i < jointList.length; i++) { - var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), newPosition); - if (distance < closestJointDistance) { - closestJointDistance = distance; - closestJointIndex = i; - } - } -// -// print("closestJointIndex: " + closestJointIndex); -// print("closestJointDistance: " + closestJointDistance); } } From b89d0a292cc7a25ae9b0ea4151055ebd7d7a9262 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 15:56:46 -0700 Subject: [PATCH 50/77] code cleanup --- examples/editModels.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index deada7e1aa..d07ca4c282 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -733,10 +733,6 @@ function scriptEnding() { rightController.cleanup(); toolBar.cleanup(); cleanupModelMenus(); - - Overlays.deleteOverlay(r); - Overlays.deleteOverlay(g); - Overlays.deleteOverlay(b); } Script.scriptEnding.connect(scriptEnding); From 0b4484a153ec22e58f7a244d9e0e2bc6fdb14d10 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 16:49:51 -0700 Subject: [PATCH 51/77] Trying a different way of determining the cascade threshold distances. --- interface/src/Application.cpp | 3 +++ interface/src/Application.h | 3 +++ interface/src/voxels/VoxelSystem.cpp | 5 +++-- interface/src/voxels/VoxelSystem.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index af94ddba01..bcb52cfabc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2298,6 +2298,9 @@ void Application::updateShadowMap() { for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { radius = qMax(radius, glm::distance(points[j], center)); } + if (i < 3) { + _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius; + } center = inverseRotation * center; // to reduce texture "shimmer," move in texel increments diff --git a/interface/src/Application.h b/interface/src/Application.h index 68d437815b..3fcf40b95b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -266,6 +266,8 @@ public: void getModelViewMatrix(glm::dmat4* modelViewMatrix); void getProjectionMatrix(glm::dmat4* projectionMatrix); + const glm::vec3& getShadowDistances() const { return _shadowDistances; } + /// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account. void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal, float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const; @@ -493,6 +495,7 @@ private: static const int CASCADED_SHADOW_MATRIX_COUNT = 4; glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT]; + glm::vec3 _shadowDistances; Environment _environment; diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 3525a086b4..2b86a58d9b 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -528,8 +528,7 @@ void VoxelSystem::initVoxelMemory() { _cascadedShadowMapProgram.bind(); _cascadedShadowMapProgram.setUniformValue("shadowMap", 0); - _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _shadowDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances"); _cascadedShadowMapProgram.release(); } } @@ -1179,6 +1178,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo ProgramObject VoxelSystem::_perlinModulateProgram; ProgramObject VoxelSystem::_shadowMapProgram; ProgramObject VoxelSystem::_cascadedShadowMapProgram; +int VoxelSystem::_shadowDistancesLocation; void VoxelSystem::init() { if (_initialized) { @@ -1502,6 +1502,7 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { if (Menu::getInstance()->getShadowsEnabled()) { if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { _cascadedShadowMapProgram.bind(); + _cascadedShadowMapProgram.setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); } else { _shadowMapProgram.bind(); } diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index acd0cd170a..71abc9ca93 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -234,6 +234,7 @@ private: static ProgramObject _perlinModulateProgram; static ProgramObject _shadowMapProgram; static ProgramObject _cascadedShadowMapProgram; + static int _shadowDistancesLocation; int _hookID; std::vector _freeIndexes; From d17eeaf35be7c8a4c98b0bd2722de6e31a16d817 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 29 May 2014 16:50:13 -0700 Subject: [PATCH 52/77] remove old oculus yaw offset, expand limit on head yaw --- interface/src/avatar/MyAvatar.cpp | 43 +++---------------------------- libraries/avatars/src/HeadData.h | 4 +-- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 582a3934d4..569dce044e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -76,8 +76,7 @@ MyAvatar::MyAvatar() : _lastFloorContactPoint(0.0f), _lookAtTargetAvatar(), _shouldRender(true), - _billboardValid(false), - _oculusYawOffset(0.0f) + _billboardValid(false) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; @@ -90,8 +89,7 @@ MyAvatar::~MyAvatar() { void MyAvatar::reset() { _skeletonModel.reset(); - getHead()->reset(); - _oculusYawOffset = 0.0f; + getHead()->reset(); setVelocity(glm::vec3(0.0f)); setThrust(glm::vec3(0.0f)); @@ -828,43 +826,8 @@ void MyAvatar::updateOrientation(float deltaTime) { OculusManager::getEulerAngles(yaw, pitch, roll); // ... so they need to be converted to degrees before we do math... - // The neck is limited in how much it can yaw, so we check its relative - // yaw from the body and yaw the body if necessary. - yaw *= DEGREES_PER_RADIAN; - float bodyToHeadYaw = yaw - _oculusYawOffset; - const float MAX_NECK_YAW = 85.0f; // degrees - if ((fabs(bodyToHeadYaw) > 2.0f * MAX_NECK_YAW) && (yaw * _oculusYawOffset < 0.0f)) { - // We've wrapped around the range for yaw so adjust - // the measured yaw to be relative to _oculusYawOffset. - if (yaw > 0.0f) { - yaw -= 360.0f; - } else { - yaw += 360.0f; - } - bodyToHeadYaw = yaw - _oculusYawOffset; - } - - float delta = fabs(bodyToHeadYaw) - MAX_NECK_YAW; - if (delta > 0.0f) { - yaw = MAX_NECK_YAW; - if (bodyToHeadYaw < 0.0f) { - delta *= -1.0f; - bodyToHeadYaw = -MAX_NECK_YAW; - } else { - bodyToHeadYaw = MAX_NECK_YAW; - } - // constrain _oculusYawOffset to be within range [-180,180] - _oculusYawOffset = fmod((_oculusYawOffset + delta) + 180.0f, 360.0f) - 180.0f; - - // We must adjust the body orientation using a delta rotation (rather than - // doing yaw math) because the body's yaw ranges are not the same - // as what the Oculus API provides. - glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), _worldUpDirection); - orientation = orientation * bodyCorrection; - } Head* head = getHead(); - head->setBaseYaw(bodyToHeadYaw); - + head->setBaseYaw(yaw * DEGREES_PER_RADIAN); head->setBasePitch(pitch * DEGREES_PER_RADIAN); head->setBaseRoll(roll * DEGREES_PER_RADIAN); } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index b76bd189bf..9e2920ae85 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -20,8 +20,8 @@ #include // degrees -const float MIN_HEAD_YAW = -110.f; -const float MAX_HEAD_YAW = 110.f; +const float MIN_HEAD_YAW = -180.f; +const float MAX_HEAD_YAW = 180.f; const float MIN_HEAD_PITCH = -60.f; const float MAX_HEAD_PITCH = 60.f; const float MIN_HEAD_ROLL = -50.f; From 12beef7fec0a8e958c77a82a11b5322696917be4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:08:36 -0700 Subject: [PATCH 53/77] Apply the new shadow distances to the models, too. --- interface/src/renderer/Model.cpp | 32 +++++++++++++++++++++----------- interface/src/renderer/Model.h | 6 ++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a550064ef1..85392bd353 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -96,6 +96,11 @@ int Model::_shadowNormalSpecularMapTangentLocation; int Model::_cascadedShadowNormalMapTangentLocation; int Model::_cascadedShadowNormalSpecularMapTangentLocation; +int Model::_cascadedShadowMapDistancesLocation; +int Model::_cascadedShadowNormalMapDistancesLocation; +int Model::_cascadedShadowSpecularMapDistancesLocation; +int Model::_cascadedShadowNormalSpecularMapDistancesLocation; + Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinSpecularMapLocations; @@ -144,12 +149,11 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati locations.clusterIndices = program.attributeLocation("clusterIndices"); locations.clusterWeights = program.attributeLocation("clusterWeights"); locations.tangent = program.attributeLocation("tangent"); + locations.shadowDistances = program.uniformLocation("shadowDistances"); program.setUniformValue("diffuseMap", 0); program.setUniformValue("normalMap", 1); program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("shadowMap", shadowTextureUnit); - program.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); program.release(); } @@ -310,8 +314,7 @@ void Model::init() { _cascadedShadowMapProgram.bind(); _cascadedShadowMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowMapProgram.setUniformValue("shadowMap", 1); - _cascadedShadowMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowMapDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances"); _cascadedShadowMapProgram.release(); _cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -324,8 +327,7 @@ void Model::init() { _cascadedShadowNormalMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowNormalMapProgram.setUniformValue("normalMap", 1); _cascadedShadowNormalMapProgram.setUniformValue("shadowMap", 2); - _cascadedShadowNormalMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalMapDistancesLocation = _cascadedShadowNormalMapProgram.uniformLocation("shadowDistances"); _cascadedShadowNormalMapTangentLocation = _cascadedShadowNormalMapProgram.attributeLocation("tangent"); _cascadedShadowNormalMapProgram.release(); @@ -339,8 +341,7 @@ void Model::init() { _cascadedShadowSpecularMapProgram.setUniformValue("diffuseMap", 0); _cascadedShadowSpecularMapProgram.setUniformValue("specularMap", 1); _cascadedShadowSpecularMapProgram.setUniformValue("shadowMap", 2); - _cascadedShadowSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowSpecularMapDistancesLocation = _cascadedShadowSpecularMapProgram.uniformLocation("shadowDistances"); _cascadedShadowSpecularMapProgram.release(); _cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -354,8 +355,8 @@ void Model::init() { _cascadedShadowNormalSpecularMapProgram.setUniformValue("normalMap", 1); _cascadedShadowNormalSpecularMapProgram.setUniformValue("specularMap", 2); _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3); - _cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowDistances", -SHADOW_MATRIX_DISTANCES[1], - -SHADOW_MATRIX_DISTANCES[2], -SHADOW_MATRIX_DISTANCES[3]); + _cascadedShadowNormalSpecularMapDistancesLocation = + _cascadedShadowNormalSpecularMapProgram.uniformLocation("shadowDistances"); _cascadedShadowNormalSpecularMapTangentLocation = _cascadedShadowNormalSpecularMapProgram.attributeLocation("tangent"); _cascadedShadowNormalSpecularMapProgram.release(); @@ -1641,6 +1642,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations; int tangentLocation = _normalMapTangentLocation; + int shadowDistancesLocation = _cascadedShadowMapDistancesLocation; GLenum specularTextureUnit = 0; GLenum shadowTextureUnit = 0; if (mode == SHADOW_RENDER_MODE) { @@ -1656,6 +1658,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram = &_skinCascadedShadowNormalSpecularMapProgram; skinLocations = &_skinCascadedShadowNormalSpecularMapLocations; tangentLocation = _cascadedShadowNormalSpecularMapTangentLocation; + shadowDistancesLocation = _cascadedShadowNormalSpecularMapDistancesLocation; } else { program = &_shadowNormalSpecularMapProgram; skinProgram = &_skinShadowNormalSpecularMapProgram; @@ -1677,6 +1680,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram = &_skinCascadedShadowNormalMapProgram; skinLocations = &_skinCascadedShadowNormalMapLocations; tangentLocation = _cascadedShadowNormalMapTangentLocation; + shadowDistancesLocation = _cascadedShadowNormalMapDistancesLocation; } else { program = &_shadowNormalMapProgram; skinProgram = &_skinShadowNormalMapProgram; @@ -1695,6 +1699,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re program = &_cascadedShadowSpecularMapProgram; skinProgram = &_skinCascadedShadowSpecularMapProgram; skinLocations = &_skinCascadedShadowSpecularMapLocations; + shadowDistancesLocation = _cascadedShadowSpecularMapDistancesLocation; } else { program = &_shadowSpecularMapProgram; skinProgram = &_skinShadowSpecularMapProgram; @@ -1740,10 +1745,15 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re skinProgram->enableAttributeArray(skinLocations->clusterWeights); activeProgram = skinProgram; tangentLocation = skinLocations->tangent; - + if (cascadedShadows) { + program->setUniform(skinLocations->shadowDistances, Application::getInstance()->getShadowDistances()); + } } else { glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); program->bind(); + if (cascadedShadows) { + program->setUniform(shadowDistancesLocation, Application::getInstance()->getShadowDistances()); + } } if (mesh.blendshapes.isEmpty()) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 5561855afb..5aa2c2160b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -311,12 +311,18 @@ private: static int _cascadedShadowNormalMapTangentLocation; static int _cascadedShadowNormalSpecularMapTangentLocation; + static int _cascadedShadowMapDistancesLocation; + static int _cascadedShadowNormalMapDistancesLocation; + static int _cascadedShadowSpecularMapDistancesLocation; + static int _cascadedShadowNormalSpecularMapDistancesLocation; + class SkinLocations { public: int clusterMatrices; int clusterIndices; int clusterWeights; int tangent; + int shadowDistances; }; static SkinLocations _skinLocations; From 34091128d8ce1d27a8a0d08ae924f50afc559a71 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:22:59 -0700 Subject: [PATCH 54/77] Distance tweak. --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ba3904d44e..152b780363 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2349,7 +2349,8 @@ void Application::updateShadowMap() { radius = qMax(radius, glm::distance(points[j], center)); } if (i < 3) { - _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius; + const float RADIUS_SCALE = 0.5f; + _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius * RADIUS_SCALE; } center = inverseRotation * center; From ac22cebde1922be01e12b7d95b794afd565d0493 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 17:41:40 -0700 Subject: [PATCH 55/77] more performance stats debugging --- interface/src/Application.cpp | 61 +++++++++++++-------- interface/src/Menu.cpp | 3 ++ interface/src/Menu.h | 3 ++ interface/src/avatar/MyAvatar.cpp | 89 ++++++++++++++++++++++--------- interface/src/ui/Stats.cpp | 10 +++- 5 files changed, 116 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index db6333acee..1cb215ff3d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2001,8 +2001,14 @@ void Application::update(float deltaTime) { _joystickManager.update(); _prioVR.update(deltaTime); } - updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + + { + PerformanceTimer perfTimer("idle/update/updateMyAvatar"); + updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + } + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + { PerformanceTimer perfTimer("idle/update/_avatarManager"); _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... @@ -2039,17 +2045,22 @@ void Application::update(float deltaTime) { } void Application::updateMyAvatar(float deltaTime) { - PerformanceTimer perfTimer("idle/update/updateMyAvatar"); + PerformanceTimer perfTimer("updateMyAvatar"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()"); - _myAvatar->update(deltaTime); + { + PerformanceTimer perfTimer("updateMyAvatar/_myAvatar->update()"); + _myAvatar->update(deltaTime); + } - // send head/hand data to the avatar mixer and voxel server - QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); - packet.append(_myAvatar->toByteArray()); - - controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); + { + // send head/hand data to the avatar mixer and voxel server + PerformanceTimer perfTimer("updateMyAvatar/sendToAvatarMixer"); + QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); + packet.append(_myAvatar->toByteArray()); + controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); + } // Update _viewFrustum with latest camera and view frustum data... // NOTE: we get this from the view frustum, to make it simpler, since the @@ -2057,22 +2068,28 @@ void Application::updateMyAvatar(float deltaTime) { // We could optimize this to not actually load the viewFrustum, since we don't // actually need to calculate the view frustum planes to send these details // to the server. - loadViewFrustum(_myCamera, _viewFrustum); + { + PerformanceTimer perfTimer("updateMyAvatar/loadViewFrustum"); + loadViewFrustum(_myCamera, _viewFrustum); + } // Update my voxel servers with my current voxel query... - quint64 now = usecTimestampNow(); - quint64 sinceLastQuery = now - _lastQueriedTime; - const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; - bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; - bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); + { + PerformanceTimer perfTimer("updateMyAvatar/queryOctree"); + quint64 now = usecTimestampNow(); + quint64 sinceLastQuery = now - _lastQueriedTime; + const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; + bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; + bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); - // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it - if (queryIsDue || viewIsDifferentEnough) { - _lastQueriedTime = now; - queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); - queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); - queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); - _lastQueriedViewFrustum = _viewFrustum; + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it + if (queryIsDue || viewIsDifferentEnough) { + _lastQueriedTime = now; + queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); + queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); + queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); + _lastQueriedViewFrustum = _viewFrustum; + } } } @@ -2300,7 +2317,7 @@ glm::vec3 Application::getSunDirection() { } void Application::updateShadowMap() { - PerformanceTimer perfTimer("pintGL/updateShadowMap"); + PerformanceTimer perfTimer("paintGL/updateShadowMap"); QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject(); fbo->bind(); glEnable(GL_DEPTH_TEST); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 25bf65d18e..72029df2cd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -391,6 +391,9 @@ Menu::Menu() : QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandDisplaySideTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarSimulateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarUpdateTiming, 0, false); + addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMiscAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandIdleTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c1a9e4274b..9b05df910b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -326,6 +326,9 @@ namespace MenuOption { const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString ExpandMiscAvatarTiming = "Expand Misc MyAvatar Timing"; + const QString ExpandAvatarUpdateTiming = "Expand MyAvatar update Timing"; + const QString ExpandAvatarSimulateTiming = "Expand MyAvatar simulate Timing"; const QString ExpandDisplaySideTiming = "Expand Display Side Timing"; const QString ExpandIdleTiming = "Expand Idle Timing"; const QString ExpandPaintGLTiming = "Expand PaintGL Timing"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 582a3934d4..ff8b2b5e91 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -24,9 +24,9 @@ #include #include #include -#include - +#include #include +#include #include "Application.h" #include "Audio.h" @@ -103,10 +103,15 @@ void MyAvatar::reset() { } void MyAvatar::update(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::update/"); Head* head = getHead(); head->relaxLean(deltaTime); - updateFromTrackers(deltaTime); + { + PerformanceTimer perfTimer("MyAvatar::update/updateFromTrackers"); + updateFromTrackers(deltaTime); + } if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { + PerformanceTimer perfTimer("MyAvatar::update/moveWithLean"); // Faceshift drive is enabled, set the avatar drive based on the head position moveWithLean(); } @@ -117,13 +122,18 @@ void MyAvatar::update(float deltaTime) { head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) { + PerformanceTimer perfTimer("MyAvatar::update/gravityWork"); setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition())); } - simulate(deltaTime); + { + PerformanceTimer perfTimer("MyAvatar::update/simulate"); + simulate(deltaTime); + } } void MyAvatar::simulate(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::simulate"); if (_scale != _targetScale) { float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; @@ -134,34 +144,56 @@ void MyAvatar::simulate(float deltaTime) { // no extra movement of the hand here any more ... _handState = HAND_STATE_NULL; - updateOrientation(deltaTime); - updatePosition(deltaTime); - - // update avatar skeleton and simulate hand and head - getHand()->collideAgainstOurself(); - getHand()->simulate(deltaTime, true); - - _skeletonModel.simulate(deltaTime); - simulateAttachments(deltaTime); - - // copy out the skeleton joints from the model - _jointData.resize(_skeletonModel.getJointStateCount()); - for (int i = 0; i < _jointData.size(); i++) { - JointData& data = _jointData[i]; - data.valid = _skeletonModel.getJointState(i, data.rotation); + { + PerformanceTimer perfTimer("MyAvatar::simulate/updateOrientation"); + updateOrientation(deltaTime); + } + { + PerformanceTimer perfTimer("MyAvatar::simulate/updatePosition"); + updatePosition(deltaTime); } - Head* head = getHead(); - glm::vec3 headPosition; - if (!_skeletonModel.getHeadPosition(headPosition)) { - headPosition = _position; + { + PerformanceTimer perfTimer("MyAvatar::simulate/hand Collision,simulate"); + // update avatar skeleton and simulate hand and head + getHand()->collideAgainstOurself(); + getHand()->simulate(deltaTime, true); + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/_skeletonModel.simulate()"); + _skeletonModel.simulate(deltaTime); + } + { + PerformanceTimer perfTimer("MyAvatar::simulate/simulateAttachments"); + simulateAttachments(deltaTime); + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/copy joints"); + // copy out the skeleton joints from the model + _jointData.resize(_skeletonModel.getJointStateCount()); + for (int i = 0; i < _jointData.size(); i++) { + JointData& data = _jointData[i]; + data.valid = _skeletonModel.getJointState(i, data.rotation); + } + } + + { + PerformanceTimer perfTimer("MyAvatar::simulate/head Simulate"); + Head* head = getHead(); + glm::vec3 headPosition; + if (!_skeletonModel.getHeadPosition(headPosition)) { + headPosition = _position; + } + head->setPosition(headPosition); + head->setScale(_scale); + head->simulate(deltaTime, true); } - head->setPosition(headPosition); - head->setScale(_scale); - head->simulate(deltaTime, true); // now that we're done stepping the avatar forward in time, compute new collisions if (_collisionGroups != 0) { + PerformanceTimer perfTimer("MyAvatar::simulate/_collisionGroups"); Camera* myCamera = Application::getInstance()->getCamera(); float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE; @@ -171,14 +203,17 @@ void MyAvatar::simulate(float deltaTime) { } updateShapePositions(); if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithEnvironment"); updateCollisionWithEnvironment(deltaTime, radius); } if (_collisionGroups & COLLISION_GROUP_VOXELS) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithVoxels"); updateCollisionWithVoxels(deltaTime, radius); } else { _trapDuration = 0.0f; } if (_collisionGroups & COLLISION_GROUP_AVATARS) { + PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithAvatars"); updateCollisionWithAvatars(deltaTime); } } @@ -791,6 +826,7 @@ bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode rend } float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) { + PerformanceTimer perfTimer("MyAvatar::computeDistanceToFloor()"); glm::vec3 direction = -_worldUpDirection; OctreeElement* elementHit; // output from findRayIntersection float distance = FLT_MAX; // output from findRayIntersection @@ -876,6 +912,7 @@ void MyAvatar::updateOrientation(float deltaTime) { const float NEARBY_FLOOR_THRESHOLD = 5.0f; void MyAvatar::updatePosition(float deltaTime) { + PerformanceTimer perfTimer("MyAvatar::updatePosition"); float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) + fabsf(_driveKeys[UP] - _driveKeys[DOWN]); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 42eae260c7..fa62ecdb9b 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -173,6 +173,12 @@ bool Stats::includeTimingRecord(const QString& name) { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming); } else if (name.startsWith("idle/")) { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming); + } else if (name.startsWith("MyAvatar::simulate")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarSimulateTiming); + } else if (name.startsWith("MyAvatar::update/") || name.startsWith("updateMyAvatar")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarUpdateTiming); + } else if (name.startsWith("MyAvatar::")) { + included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandMiscAvatarTiming); } else if (name == "paintGL/displaySide") { included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming) || Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming); @@ -556,14 +562,14 @@ void Stats::display( char perfLine[TIMER_OUTPUT_LINE_LENGTH]; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, - "---------------- Function --------------- --msecs- -calls--", color); + "--------------------- Function -------------------- --msecs- -calls--", color); const QMap& allRecords = PerformanceTimer::getAllTimerRecords(); QMapIterator i(allRecords); while (i.hasNext()) { i.next(); if (includeTimingRecord(i.key())) { - sprintf(perfLine, "%40s: %8.4f [%6llu]", qPrintable(i.key()), + sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()), (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC, i.value().getCount()); From 1eace78e4740db99652def5dd70db11f68b5b2ed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 29 May 2014 17:46:25 -0700 Subject: [PATCH 56/77] Hide distances; they no longer need to be publicly visible. --- interface/src/Application.cpp | 1 + interface/src/Application.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 152b780363..b4659cb828 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2310,6 +2310,7 @@ void Application::updateShadowMap() { glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); glm::quat inverseRotation = glm::inverse(rotation); + const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; diff --git a/interface/src/Application.h b/interface/src/Application.h index c89c324ab1..f3d9c0fd27 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -126,8 +126,6 @@ static const float MIRROR_REARVIEW_DISTANCE = 0.65f; static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; static const float MIRROR_FIELD_OF_VIEW = 30.0f; -static const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; - class Application : public QApplication { Q_OBJECT From 17e3bd6110ff95c8f4f77c2733074b2c34fcc9bb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 May 2014 18:24:21 -0700 Subject: [PATCH 57/77] CR comments --- examples/editModels.js | 10 +++++----- interface/src/avatar/Avatar.cpp | 28 ++++++++++++++++++++++++++-- interface/src/renderer/Model.cpp | 4 ++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index d07ca4c282..1db6901e23 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -88,7 +88,7 @@ function controller(wichSide) { this.oldModelPosition; this.oldModelRadius; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; this.laser = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0 }, @@ -145,11 +145,11 @@ function controller(wichSide) { this.oldModelRotation = properties.modelRotation; this.oldModelRadius = properties.radius; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; for (var i = 0; i < jointList.length; i++) { var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); if (distance < this.oldModelRadius) { - this.jointsIntersectingFronStart.push(i); + this.jointsIntersectingFromStart.push(i); } } } @@ -176,7 +176,7 @@ function controller(wichSide) { if (closestJointDistance < this.oldModelRadius) { - if (this.jointsIntersectingFronStart.indexOf(closestJointIndex) != -1) { + if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1) { // Do nothing } else { print("Attaching to " + jointList[closestJointIndex]); @@ -197,7 +197,7 @@ function controller(wichSide) { this.grabbing = false; this.modelID.isKnownID = false; - this.jointsIntersectingFronStart = []; + this.jointsIntersectingFromStart = []; } this.checkTrigger = function () { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ac6718dcc8..870d5b1a53 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -706,24 +706,48 @@ QStringList Avatar::getJointNames() const { } glm::vec3 Avatar::getJointPosition(int index) const { - glm::vec3 position(0,0,0); + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index)); + return position; + } + glm::vec3 position; _skeletonModel.getJointPosition(index, position); return position; } glm::vec3 Avatar::getJointPosition(const QString& name) const { - glm::vec3 position(0,0,0); + if (QThread::currentThread() != thread()) { + glm::vec3 position; + QMetaObject::invokeMethod(const_cast(this), "getJointPosition", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name)); + return position; + } + glm::vec3 position; _skeletonModel.getJointPosition(getJointIndex(name), position); return position; } glm::quat Avatar::getJointCombinedRotation(int index) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const int, index)); + return rotation; + } glm::quat rotation; _skeletonModel.getJointCombinedRotation(index, rotation); return rotation; } glm::quat Avatar::getJointCombinedRotation(const QString& name) const { + if (QThread::currentThread() != thread()) { + glm::quat rotation; + QMetaObject::invokeMethod(const_cast(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const QString&, name)); + return rotation; + } glm::quat rotation; _skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation); return rotation; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b41d440e16..ee774c183a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -634,8 +634,8 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return false; } rotation = _jointStates[jointIndex]._combinedRotation * - (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : - _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); + (fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation : + _geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation); return true; } From e59e25372786fb87a05789dceeb23ae8bd4f4dfe Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 18:32:11 -0700 Subject: [PATCH 58/77] fix ray intersection performance --- libraries/octree/src/Octree.cpp | 1 + libraries/octree/src/OctreeElement.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3ec1871023..6cbce20dbc 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -600,6 +600,7 @@ public: bool found; }; + bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 22320b5969..4e14f603e8 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1308,11 +1308,6 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 keepSearching = true; // assume that we will continue searching after this. - // by default, we only allow intersections with leaves with content - if (!canRayIntersect()) { - return false; // we don't intersect with non-leaves, and we keep searching - } - AACube cube = getAACube(); float localDistance; BoxFace localFace; @@ -1323,6 +1318,11 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 return false; // we did not intersect } + // by default, we only allow intersections with leaves with content + if (!canRayIntersect()) { + return false; // we don't intersect with non-leaves, and we keep searching + } + // we did hit this element, so calculate appropriate distances localDistance *= TREE_SCALE; if (localDistance < distance) { @@ -1346,6 +1346,7 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g if (intersectedObject) { *intersectedObject = this; } + keepSearching = false; return true; // we did intersect } return false; // we did not intersect From 6a57e662ac8655342c7278c43dc8b1f0acdf8394 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 29 May 2014 18:34:11 -0700 Subject: [PATCH 59/77] removed extra line --- libraries/octree/src/Octree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6cbce20dbc..3ec1871023 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -600,7 +600,6 @@ public: bool found; }; - bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); From a7f10798b2b0a88ae575199ec2bc84d1b3b997f1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 10:23:36 -0700 Subject: [PATCH 60/77] Fixed JS parse error --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 30d1e4edf4..a6474609d9 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -306,7 +306,7 @@ function controller(wichSide) { var identify = Models.identifyModel(foundModel); if (!identify.isKnownID) { print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")"); - continue; + return; } foundModel = identify; } @@ -493,7 +493,7 @@ function mousePressEvent(event) { var identify = Models.identifyModel(foundModel); if (!identify.isKnownID) { print("Unknown ID " + identify.id + " (update loop " + foundModel.id + ")"); - continue; + return; } foundModel = identify; } From 0b31971592b1fc243cdb6976aa318969ff65b38c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 10:42:54 -0700 Subject: [PATCH 61/77] Update joints list everytime I try to attach --- examples/editModels.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 1db6901e23..77bc14643f 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -157,9 +157,7 @@ function controller(wichSide) { this.release = function () { if (this.grabbing) { - if (jointList.length <= 0) { - jointList = MyAvatar.getJointNames(); - } + jointList = MyAvatar.getJointNames(); var closestJointIndex = -1; var closestJointDistance = 10; From 9d59251d2794791269f5eee8b28c219bb3b37864 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 30 May 2014 10:47:51 -0700 Subject: [PATCH 62/77] =?UTF-8?q?add=20keyboard=20shortcut=20(=E2=80=9C.?= =?UTF-8?q?=E2=80=9D)=20to=20toggle=20sitting,=20so=20that=20Oculus=20user?= =?UTF-8?q?=20can=20sit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/sit.js | 62 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index 1df877dba6..6ae8a712f1 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -40,6 +40,8 @@ var passedTime = 0.0; var startPosition = null; var animationLenght = 2.0; +var sitting = false; + // This is the pose we would like to end up var pose = [ {joint:"RightUpLeg", rotation: {x:100.0, y:15.0, z:0.0}}, @@ -101,31 +103,41 @@ var standingUpAnimation = function(deltaTime){ } } +function sitDown() { + sitting = true; + passedTime = 0.0; + startPosition = MyAvatar.position; + storeStartPoseAndTransition(); + try{ + Script.update.disconnect(standingUpAnimation); + } catch(e){ + // no need to handle. if it wasn't connected no harm done + } + Script.update.connect(sittingDownAnimation); + Overlays.editOverlay(sitDownButton, { visible: false }); + Overlays.editOverlay(standUpButton, { visible: true }); +} + +function standUp() { + sitting = false; + passedTime = 0.0; + startPosition = MyAvatar.position; + try{ + Script.update.disconnect(sittingDownAnimation); + } catch (e){} + Script.update.connect(standingUpAnimation); + Overlays.editOverlay(standUpButton, { visible: false }); + Overlays.editOverlay(sitDownButton, { visible: true }); +} + Controller.mousePressEvent.connect(function(event){ var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay == sitDownButton) { - passedTime = 0.0; - startPosition = MyAvatar.position; - storeStartPoseAndTransition(); - try{ - Script.update.disconnect(standingUpAnimation); - } catch(e){ - // no need to handle. if it wasn't connected no harm done - } - Script.update.connect(sittingDownAnimation); - Overlays.editOverlay(sitDownButton, { visible: false }); - Overlays.editOverlay(standUpButton, { visible: true }); + sitDown(); } else if (clickedOverlay == standUpButton) { - passedTime = 0.0; - startPosition = MyAvatar.position; - try{ - Script.update.disconnect(sittingDownAnimation); - } catch (e){} - Script.update.connect(standingUpAnimation); - Overlays.editOverlay(standUpButton, { visible: false }); - Overlays.editOverlay(sitDownButton, { visible: true }); + standUp(); } }) @@ -140,7 +152,19 @@ function update(deltaTime){ } } +function keyPressEvent(event) { + if (event.text === ".") { + if (sitting) { + standUp(); + } else { + sitDown(); + } + } +} + + Script.update.connect(update); +Controller.keyPressEvent.connect(keyPressEvent); Script.scriptEnding.connect(function() { From 164192fb508bb356b13928a4a76b941cf5e0175f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 30 May 2014 11:03:46 -0700 Subject: [PATCH 63/77] If the skeleton doesn't have eye joints (as with the Fuse models), make up some positions based on the head and neck joints. --- interface/src/avatar/SkeletonModel.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 3586e525ae..ef5fc3d34b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -427,7 +427,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco return false; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - return getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && - getJointPosition(geometry.rightEyeJointIndex, secondEyePosition); + if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) { + return true; + } + // no eye joints; try to estimate based on head/neck joints + glm::vec3 neckPosition, headPosition; + if (getJointPosition(geometry.neckJointIndex, neckPosition) && + getJointPosition(geometry.headJointIndex, headPosition)) { + const float EYE_PROPORTION = 0.6f; + glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); + glm::quat headRotation; + getJointRotation(geometry.headJointIndex, headRotation); + const float EYES_FORWARD = 0.25f; + const float EYE_SEPARATION = 0.1f; + float headHeight = glm::distance(neckPosition, headPosition); + firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight; + secondEyePosition = baseEyePosition + headRotation * glm::vec3(-EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight; + return true; + } + return false; } From 8a4955d75bee591d3d4ed4689a36ea525226f2f1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 30 May 2014 11:13:37 -0700 Subject: [PATCH 64/77] temporarily disable the model aligned box picking --- libraries/models/src/ModelTreeElement.cpp | 37 +++++++++++++++-------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index c655a45b57..e5116e316c 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -192,21 +192,34 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons // if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) { + + // This is experimental code that doesn't quite work, so I'm disabling it by default, but + // leaving it in because I need to work on it and fix it to work properly. + bool pickAgainstModelAlignedBox = false; + + if (pickAgainstModelAlignedBox) { + // extents is the model relative, scaled, centered extents of the model + glm::mat4 rotation = glm::mat4_cast(model.getModelRotation()); + glm::mat4 translation = glm::translate(model.getPosition()); + glm::mat4 modelToWorldMatrix = translation * rotation; + glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); - // extents is the model relative, scaled, centered extents of the model - glm::mat4 rotation = glm::mat4_cast(model.getModelRotation()); - glm::mat4 translation = glm::translate(model.getPosition()); - glm::mat4 modelToWorldMatrix = translation * rotation; - glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); + AABox modelFrameBox(extents.minimum, (extents.maximum - extents.minimum)); - AABox modelFrameBox(extents.minimum, (extents.maximum - extents.minimum)); + glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 1.0f)); - glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); - glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 1.0f)); - - // we can use the AABox's ray intersection by mapping our origin and direction into the model frame - // and testing intersection there. - if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, localDistance, localFace)) { + // we can use the AABox's ray intersection by mapping our origin and direction into the model frame + // and testing intersection there. + if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, localDistance, localFace)) { + if (localDistance < distance) { + distance = localDistance; + face = localFace; + *intersectedObject = (void*)(&model); + somethingIntersected = true; + } + } + } else { if (localDistance < distance) { distance = localDistance; face = localFace; From d48a5dd3059d97283dca186d1470f7a880d5cf30 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 30 May 2014 14:54:25 -0700 Subject: [PATCH 65/77] don't force OAuthWebViewHandler to stay on top --- interface/src/ui/OAuthWebViewHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/OAuthWebViewHandler.cpp b/interface/src/ui/OAuthWebViewHandler.cpp index e93321212c..5415d5d9c3 100644 --- a/interface/src/ui/OAuthWebViewHandler.cpp +++ b/interface/src/ui/OAuthWebViewHandler.cpp @@ -82,7 +82,7 @@ void OAuthWebViewHandler::displayWebviewForAuthorizationURL(const QUrl& authoriz _activeWebView = new QWebView; // keep the window on top and delete it when it closes - _activeWebView->setWindowFlags(Qt::Sheet | Qt::WindowStaysOnTopHint); + _activeWebView->setWindowFlags(Qt::Sheet); _activeWebView->setAttribute(Qt::WA_DeleteOnClose); qDebug() << "Displaying QWebView for OAuth authorization at" << authorizationURL.toString(); From b212f9edca896abdc1a6cb8c9d42222b0f7b1a26 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 30 May 2014 15:07:54 -0700 Subject: [PATCH 66/77] fix ray picking at distances --- libraries/models/src/ModelTreeElement.cpp | 35 +++++++---------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index e5116e316c..b87557d073 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -193,33 +193,20 @@ bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, cons // if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) { - // This is experimental code that doesn't quite work, so I'm disabling it by default, but - // leaving it in because I need to work on it and fix it to work properly. - bool pickAgainstModelAlignedBox = false; - - if (pickAgainstModelAlignedBox) { - // extents is the model relative, scaled, centered extents of the model - glm::mat4 rotation = glm::mat4_cast(model.getModelRotation()); - glm::mat4 translation = glm::translate(model.getPosition()); - glm::mat4 modelToWorldMatrix = translation * rotation; - glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); + // extents is the model relative, scaled, centered extents of the model + glm::mat4 rotation = glm::mat4_cast(model.getModelRotation()); + glm::mat4 translation = glm::translate(model.getPosition()); + glm::mat4 modelToWorldMatrix = translation * rotation; + glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); - AABox modelFrameBox(extents.minimum, (extents.maximum - extents.minimum)); + AABox modelFrameBox(extents.minimum, (extents.maximum - extents.minimum)); - glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); - glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 1.0f)); + glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); - // we can use the AABox's ray intersection by mapping our origin and direction into the model frame - // and testing intersection there. - if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, localDistance, localFace)) { - if (localDistance < distance) { - distance = localDistance; - face = localFace; - *intersectedObject = (void*)(&model); - somethingIntersected = true; - } - } - } else { + // we can use the AABox's ray intersection by mapping our origin and direction into the model frame + // and testing intersection there. + if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, localDistance, localFace)) { if (localDistance < distance) { distance = localDistance; face = localFace; From 9ca80cf4b3b5bf46896b10b25a2f5663baca1298 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 17:18:26 -0700 Subject: [PATCH 67/77] Added script that lists the current JS API --- examples/currentAPI.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/currentAPI.js diff --git a/examples/currentAPI.js b/examples/currentAPI.js new file mode 100644 index 0000000000..f926b4a02c --- /dev/null +++ b/examples/currentAPI.js @@ -0,0 +1,31 @@ +// +// currentAPI.js +// examples +// +// Created by Clément Brisset on 5/30/14. +// Copyright 2014 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 +// + + +function listKeys(string, object) { + if (typeof(object) != "object") { + print(typeof(object) + " " + string); + return; + } + + var keys = Object.keys(object); + for (var i = 0; i < keys.length; ++i) { + if (string == "listKeys") { + return; + } else if (string == "") { + listKeys(keys[i], object[keys[i]]); + } else { + listKeys(string + "." + keys[i], object[keys[i]]); + } + } +} + +listKeys("", this); \ No newline at end of file From 2514906bd7374270f4d2f22e1819f82c54211c13 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 17:25:42 -0700 Subject: [PATCH 68/77] Fixed minor issue in currentAPI.js --- examples/currentAPI.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/currentAPI.js b/examples/currentAPI.js index f926b4a02c..fe562887f9 100644 --- a/examples/currentAPI.js +++ b/examples/currentAPI.js @@ -11,6 +11,10 @@ function listKeys(string, object) { + if (string == "listKeys") { + return; + } + if (typeof(object) != "object") { print(typeof(object) + " " + string); return; @@ -18,9 +22,7 @@ function listKeys(string, object) { var keys = Object.keys(object); for (var i = 0; i < keys.length; ++i) { - if (string == "listKeys") { - return; - } else if (string == "") { + if (string == "") { listKeys(keys[i], object[keys[i]]); } else { listKeys(string + "." + keys[i], object[keys[i]]); From a661ea317973dbed94998d94b56106f6d6d70c1c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 17:40:04 -0700 Subject: [PATCH 69/77] Made API listing alphabetical, more clean and faster to print out. --- examples/currentAPI.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/currentAPI.js b/examples/currentAPI.js index fe562887f9..eb5dc3191e 100644 --- a/examples/currentAPI.js +++ b/examples/currentAPI.js @@ -9,14 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - +var array = []; +var buffer = ""; function listKeys(string, object) { - if (string == "listKeys") { + if (string == "listKeys" || string == "array" || string == "buffer" || string == "i") { return; } if (typeof(object) != "object") { - print(typeof(object) + " " + string); + array.push(string + " " + typeof(object)); return; } @@ -30,4 +31,11 @@ function listKeys(string, object) { } } -listKeys("", this); \ No newline at end of file +listKeys("", this); +array.sort(); + +for (var i = 0; i < array.length; ++i) { + buffer = buffer + "\n" + array[i]; +} + +print(buffer); From 2e5b45cfa14b825eafb714b47a87714daaaceb0d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 17:48:35 -0700 Subject: [PATCH 70/77] print dressing --- examples/currentAPI.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/currentAPI.js b/examples/currentAPI.js index eb5dc3191e..30b24910f9 100644 --- a/examples/currentAPI.js +++ b/examples/currentAPI.js @@ -10,7 +10,7 @@ // var array = []; -var buffer = ""; +var buffer = "\n\n\n\n\n======= JS API list ======="; function listKeys(string, object) { if (string == "listKeys" || string == "array" || string == "buffer" || string == "i") { return; @@ -37,5 +37,6 @@ array.sort(); for (var i = 0; i < array.length; ++i) { buffer = buffer + "\n" + array[i]; } +buffer = buffer + "\n========= API END =========\n\n\n\n\n"; print(buffer); From 4ffd51d9c44953c8ea935d9067f5bbcd7bde20d5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 May 2014 18:40:50 -0700 Subject: [PATCH 71/77] First pass at grabbing attachment --- examples/editModels.js | 62 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 8259994118..0e249f3200 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -308,6 +308,18 @@ function controller(wichSide) { this.oldModelRotation = newRotation; this.oldModelPosition = newPosition; + + var indicesToRemove = []; + for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) { + var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition); + if (distance >= this.oldModelRadius) { + indicesToRemove.push(this.jointsIntersectingFromStart[i]); + } + + } + for (var i = 0; i < indicesToRemove.length; ++i) { + this.jointsIntersectingFromStart.splice(this.jointsIntersectingFromStart.indexOf(indicesToRemove[i], 1)); + } } } @@ -341,6 +353,43 @@ function controller(wichSide) { } if (this.pressing) { + // Checking for attachments intersecting + var attachments = MyAvatar.getAttachmentData(); + var attachmentIndex = -1; + var attachmentX = LASER_LENGTH_FACTOR; + + for (var i = 0; i < attachments.length; ++i) { + var position = Vec3.sum(MyAvatar.getJointPosition(attachments[i].jointName), attachments[i].translation); + var scale = attachments[i].scale; + + var A = this.palmPosition; + var B = this.front; + var P = position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + + if (d < scale / 2.0 && 0 < x && x < attachmentX) { + attachmentIndex = i; + attachmentX = d; + } + } + + if (attachmentIndex != -1) { + MyAvatar.detachOne(attachments[attachmentIndex].modelURL, attachments[attachmentIndex].jointName); + Models.addModel({ + position: Vec3.sum(MyAvatar.getJointPosition(attachments[attachmentIndex].jointName), + attachments[attachmentIndex].translation), + modelRotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), + attachments[attachmentIndex].rotation), + radius: attachments[attachmentIndex].scale / 2.0, + modelURL: attachments[attachmentIndex].modelURL + }); + } + + // There is none so ... + // Checking model tree Vec3.print("Looking at: ", this.palmPosition); var pickRay = { origin: this.palmPosition, direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; @@ -521,10 +570,15 @@ function mousePressEvent(event) { } var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); - Models.addModel({ position: position, - radius: radiusDefault, - modelURL: url - }); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + Models.addModel({ position: position, + radius: radiusDefault, + modelURL: url + }); + } else { + print("Can't create model: Model would be out of bounds."); + } } else { var pickRay = Camera.computePickRay(event.x, event.y); From 22a8f88195da522a270d649d7d44c68d0e7a8ade Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 31 May 2014 13:24:07 -0700 Subject: [PATCH 72/77] add support for Menu.menuExists() and menu.menuItemExists() --- examples/menuExample.js | 130 +++++++++++------- interface/src/Menu.cpp | 21 ++- interface/src/Menu.h | 2 + .../src/scripting/MenuScriptingInterface.cpp | 17 +++ .../src/scripting/MenuScriptingInterface.h | 2 + 5 files changed, 118 insertions(+), 54 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index 00c6418269..c459a8d73d 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -13,68 +13,88 @@ function setupMenus() { - Menu.addMenu("Foo"); - Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); - Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); - Menu.addMenuItem("Foo","Foo item 3", "META+F" ); - Menu.addMenuItem({ - menuName: "Foo", - menuItemName: "Foo item 4", - isCheckable: true, - isChecked: true - }); + if (!Menu.menuExists("Foo")) { + Window.alert("Adding Menu Foo!"); + Menu.addMenu("Foo"); + Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); + Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); + Menu.addMenuItem("Foo","Foo item 3", "META+F" ); - Menu.addMenuItem({ - menuName: "Foo", - menuItemName: "Foo item 5", - shortcutKey: "ALT+F", - isCheckable: true - }); + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Foo item 4", + isCheckable: true, + isChecked: true + }); + + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Foo item 5", + shortcutKey: "ALT+F", + isCheckable: true + }); - Menu.addSeparator("Foo","Removable Tools"); - Menu.addMenuItem("Foo","Remove Foo item 4"); - Menu.addMenuItem("Foo","Remove Foo"); - Menu.addMenuItem("Foo","Remove Bar-Spam"); - Menu.addMenu("Bar"); + Menu.addSeparator("Foo","Removable Tools"); + Menu.addMenuItem("Foo","Remove Foo item 4"); + Menu.addMenuItem("Foo","Remove Foo"); + Menu.addMenuItem("Foo","Remove Bar-Spam"); - Menu.addMenuItem("Bar","Bar item 1", "b"); - Menu.addMenuItem({ - menuName: "Bar", - menuItemName: "Bar item 2", - shortcutKeyEvent: { text: "B", isControl: true } - }); + Menu.addMenuItem("Foo","Remove Spam item 2"); - Menu.addMenu("Bar > Spam"); - Menu.addMenuItem("Bar > Spam","Spam item 1"); - Menu.addMenuItem({ - menuName: "Bar > Spam", - menuItemName: "Spam item 2", - isCheckable: true, - isChecked: false - }); + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Remove Spam item 2" + }); + } else { + Window.alert("Menu Foo already exists!"); + } + + if (!Menu.menuExists("Bar")) { + Window.alert("Adding Menu Bar!"); + Menu.addMenu("Bar"); + Menu.addMenuItem("Bar","Bar item 1", "b"); + Menu.addMenuItem({ + menuName: "Bar", + menuItemName: "Bar item 2", + shortcutKeyEvent: { text: "B", isControl: true } + }); + + Menu.addMenu("Bar > Spam"); + Menu.addMenuItem("Bar > Spam","Spam item 1"); + Menu.addMenuItem({ + menuName: "Bar > Spam", + menuItemName: "Spam item 2", + isCheckable: true, + isChecked: false + }); - Menu.addSeparator("Bar > Spam","Other Items"); - Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); - Menu.addMenuItem("Foo","Remove Spam item 2"); + Menu.addSeparator("Bar > Spam","Other Items"); + Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); + } - Menu.addMenuItem({ - menuName: "Foo", - menuItemName: "Remove Spam item 2" - }); - Menu.addMenuItem({ - menuName: "Edit", - menuItemName: "before Cut", - beforeItem: "Cut" - }); - - Menu.addMenuItem({ - menuName: "Edit", - menuItemName: "after Nudge", - afterItem: "Nudge" - }); + if (Menu.menuItemExists("Edit","Cut")) { + Window.alert("Menu Item Cut exist adding 'before Cut'."); + Menu.addMenuItem({ + menuName: "Edit", + menuItemName: "before Cut", + beforeItem: "Cut" + }); + } else { + Window.alert("Menu Item Cut doesn't exist!"); + } + if (Menu.menuItemExists("Edit","Nudge")) { + Window.alert("Menu Item Nudge exist adding 'after Nudge'."); + Menu.addMenuItem({ + menuName: "Edit", + menuItemName: "after Nudge", + afterItem: "Nudge" + }); + } else { + Window.alert("Menu Item Nudge doesn't exist!"); + } } function scriptEnding() { @@ -82,6 +102,10 @@ function scriptEnding() { Menu.removeMenu("Foo"); Menu.removeMenu("Bar"); + + Menu.removeMenuItem("Edit", "before Cut"); + Menu.removeMenuItem("Edit", "after Nudge"); + } function menuItemEvent(menuItem) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c865f9c6ef..6121e5c458 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1650,6 +1650,16 @@ void Menu::removeMenu(const QString& menuName) { } } +bool Menu::menuExists(const QString& menuName) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + return true; + } + return false; +} + void Menu::addSeparator(const QString& menuName, const QString& separatorName) { QMenu* menuObj = getMenu(menuName); if (menuObj) { @@ -1725,8 +1735,17 @@ void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { QMenu* menuObj = getMenu(menu); if (menuObj) { removeAction(menuObj, menuitem); + QMenuBar::repaint(); } - QMenuBar::repaint(); +}; + +bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { + QMenu* menuObj = getMenu(menu); + QAction* menuItemAction = _actionHash.value(menuitem); + if (menuObj && menuItemAction) { + return true; + } + return false; }; QString Menu::getSnapshotsLocation() const { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 18d6fbfda0..020cd651d2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -169,10 +169,12 @@ public slots: QMenu* addMenu(const QString& menuName); void removeMenu(const QString& menuName); + bool menuExists(const QString& menuName); void addSeparator(const QString& menuName, const QString& separatorName); void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); + bool menuItemExists(const QString& menuName, const QString& menuitem); bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 11d681bfc7..277c611f04 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -35,6 +35,14 @@ void MenuScriptingInterface::removeMenu(const QString& menu) { QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); } +bool MenuScriptingInterface::menuExists(const QString& menu) { + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menu)); + return result; +} + void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", Q_ARG(const QString&, menuName), @@ -67,6 +75,15 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& Q_ARG(const QString&, menuitem)); }; +bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) { + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); + return result; +} + bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { bool result; QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection, diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index d127bd6edc..fda8207780 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -33,6 +33,7 @@ private slots: public slots: void addMenu(const QString& menuName); void removeMenu(const QString& menuName); + bool menuExists(const QString& menuName); void addSeparator(const QString& menuName, const QString& separatorName); void removeSeparator(const QString& menuName, const QString& separatorName); @@ -42,6 +43,7 @@ public slots: void addMenuItem(const QString& menuName, const QString& menuitem); void removeMenuItem(const QString& menuName, const QString& menuitem); + bool menuItemExists(const QString& menuName, const QString& menuitem); bool isOptionChecked(const QString& menuOption); void setIsOptionChecked(const QString& menuOption, bool isChecked); From 30a5048840f7876cbc9e426beabe7e4132ef748c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 31 May 2014 13:24:23 -0700 Subject: [PATCH 73/77] add editModels to defaultScripts --- examples/defaultScripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index b3f9649883..18d518d49d 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -10,6 +10,7 @@ Script.include("lookWithTouch.js"); Script.include("editVoxels.js"); +Script.include("editModels.js"); Script.include("selectAudioDevice.js"); Script.include("hydraMove.js"); Script.include("inspect.js"); \ No newline at end of file From f92facea769b13c6584d507ffa374ab6ab46ca9e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 31 May 2014 13:30:45 -0700 Subject: [PATCH 74/77] changed Models/Delete and Voxels/Delete to both use same menu item name of 'Delete' so that either option will correctly delete either. --- examples/editModels.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 266811f4cc..f0827338e9 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -771,13 +771,13 @@ function mouseReleaseEvent(event) { function setupModelMenus() { // add our menuitems Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete Model", shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); } function cleanupModelMenus() { // delete our menuitems Menu.removeSeparator("Edit", "Models"); - Menu.removeMenuItem("Edit", "Delete Model"); + Menu.removeMenuItem("Edit", "Delete"); } function scriptEnding() { @@ -797,7 +797,7 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent); setupModelMenus(); Menu.menuItemEvent.connect(function(menuItem){ print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == "Delete Model") { + if (menuItem == "Delete") { if (leftController.grabbing) { print(" Delete Model.... leftController.modelID="+ leftController.modelID); Models.deleteModel(leftController.modelID); From 8b51cd0d8a48282f51f4feba45642424c26b56e2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 31 May 2014 14:04:33 -0700 Subject: [PATCH 75/77] fix bug in Menu::removeAction() where we weren't removing the action key from the hash, memory leak, and other problems --- interface/src/Menu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6121e5c458..deb052e595 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -858,6 +858,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, void Menu::removeAction(QMenu* menu, const QString& actionName) { menu->removeAction(_actionHash.value(actionName)); + _actionHash.remove(actionName); } void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { From cad5e12aad95b2149f39bf321720cc76ee75c3e5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 31 May 2014 14:05:05 -0700 Subject: [PATCH 76/77] make editVoxels.js and editModels.js play nice together with the delete menu item --- examples/editModels.js | 26 +++++++++++++++++++------- examples/editVoxels.js | 21 +++++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index f0827338e9..24ab7da1a1 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -766,18 +766,30 @@ function mouseReleaseEvent(event) { glowedModelID.isKnownID = false; } - - +// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already +// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that +// added it. +var modelMenuAddedDelete = false; function setupModelMenus() { + print("setupModelMenus()"); // add our menuitems - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); + if (!Menu.menuItemExists("Edit","Delete")) { + print("no delete... adding ours"); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", + shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); + modelMenuAddedDelete = true; + } else { + print("delete exists... don't add ours"); + } } function cleanupModelMenus() { - // delete our menuitems - Menu.removeSeparator("Edit", "Models"); - Menu.removeMenuItem("Edit", "Delete"); + if (modelMenuAddedDelete) { + // delete our menuitems + Menu.removeSeparator("Edit", "Models"); + Menu.removeMenuItem("Edit", "Delete"); + } } function scriptEnding() { diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 22df8604e1..cff0d65743 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -1117,7 +1117,12 @@ function keyReleaseEvent(event) { trackKeyReleaseEvent(event); // used by preview support } -function setupMenus() { + +// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already +// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that +// added it. +var voxelMenuAddedDelete = false; +function setupVoxelMenus() { // hook up menus Menu.menuItemEvent.connect(menuItemEvent); @@ -1127,7 +1132,13 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); + + + if (!Menu.menuItemExists("Edit","Delete")) { + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", + shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); + voxelMenuAddedDelete = true; + } Menu.addMenuItem({ menuName: "File", menuItemName: "Voxels", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); @@ -1141,7 +1152,9 @@ function cleanupMenus() { Menu.removeMenuItem("Edit", "Copy"); Menu.removeMenuItem("Edit", "Paste"); Menu.removeMenuItem("Edit", "Nudge"); - Menu.removeMenuItem("Edit", "Delete"); + if (voxelMenuAddedDelete) { + Menu.removeMenuItem("Edit", "Delete"); + } Menu.removeSeparator("File", "Voxels"); Menu.removeMenuItem("File", "Export Voxels"); Menu.removeMenuItem("File", "Import Voxels"); @@ -1482,4 +1495,4 @@ Script.scriptEnding.connect(scriptEnding); Script.update.connect(update); -setupMenus(); +setupVoxelMenus(); From 758df4f58ba625c4a55ccfe3fb0809c1fc7c49e7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 2 Jun 2014 10:43:50 -0700 Subject: [PATCH 77/77] silence some unused variable warnings and move some debug code to only execute in debug mode --- .../src/octree/OctreeSendThread.cpp | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index fab9be24d3..9e4dbcd347 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -141,18 +141,6 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes return packetsSent; // without sending... } - const unsigned char* messageData = nodeData->getPacket(); - - int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); - const unsigned char* dataAt = messageData + numBytesPacketHeader; - dataAt += sizeof(OCTREE_PACKET_FLAGS); - OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); - dataAt += sizeof(OCTREE_PACKET_SEQUENCE); - - OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); - dataAt += sizeof(OCTREE_PACKET_SENT_TIME); - - // If we've got a stats message ready to send, then see if we can piggyback them together if (nodeData->stats.isReadyToSend() && !nodeData->isShuttingDown()) { // Send the stats message to the client @@ -174,7 +162,17 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { + const unsigned char* messageData = nodeData->getPacket(); + int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); + const unsigned char* dataAt = messageData + numBytesPacketHeader; + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + qDebug() << "Adding stats to packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence << + " timestamp: " << timestamp << " statsMessageLength: " << statsMessageLength << " original size: " << nodeData->getPacketLength() << " [" << _totalBytes << "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]"; @@ -196,7 +194,17 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes _totalBytes += statsMessageLength; _totalPackets++; if (debug) { + const unsigned char* messageData = nodeData->getPacket(); + int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); + const unsigned char* dataAt = messageData + numBytesPacketHeader; + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + qDebug() << "Sending separate stats packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence << + " timestamp: " << timestamp << " size: " << statsMessageLength << " [" << _totalBytes << "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]"; } @@ -215,7 +223,17 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { + const unsigned char* messageData = nodeData->getPacket(); + int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); + const unsigned char* dataAt = messageData + numBytesPacketHeader; + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence << + " timestamp: " << timestamp << " size: " << nodeData->getPacketLength() << " [" << _totalBytes << "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]"; } @@ -234,7 +252,17 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes _totalBytes += nodeData->getPacketLength(); _totalPackets++; if (debug) { + const unsigned char* messageData = nodeData->getPacket(); + int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast(messageData)); + const unsigned char* dataAt = messageData + numBytesPacketHeader; + dataAt += sizeof(OCTREE_PACKET_FLAGS); + OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); + OCTREE_PACKET_SENT_TIME timestamp = (*(OCTREE_PACKET_SENT_TIME*)dataAt); + dataAt += sizeof(OCTREE_PACKET_SENT_TIME); + qDebug() << "Sending packet at " << now << " [" << _totalPackets <<"]: sequence: " << sequence << + " timestamp: " << timestamp << " size: " << nodeData->getPacketLength() << " [" << _totalBytes << "] wasted bytes:" << thisWastedBytes << " [" << _totalWastedBytes << "]"; }