From cde36dc70d0b1c791cdbf89690c6a1b6149ded30 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Jun 2014 16:06:28 -0700 Subject: [PATCH 01/80] Add user locations --- interface/src/UserLocationsModel.cpp | 229 +++++++++++++++++++++++ interface/src/UserLocationsModel.h | 81 ++++++++ interface/src/ui/UserLocationsWindow.cpp | 76 ++++++++ interface/src/ui/UserLocationsWindow.h | 35 ++++ interface/ui/userLocationsWindow.ui | 130 +++++++++++++ 5 files changed, 551 insertions(+) create mode 100644 interface/src/UserLocationsModel.cpp create mode 100644 interface/src/UserLocationsModel.h create mode 100644 interface/src/ui/UserLocationsWindow.cpp create mode 100644 interface/src/ui/UserLocationsWindow.h create mode 100644 interface/ui/userLocationsWindow.ui diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp new file mode 100644 index 0000000000..4ad91bed73 --- /dev/null +++ b/interface/src/UserLocationsModel.cpp @@ -0,0 +1,229 @@ +// +// UserLocationsModel.cpp +// interface/src +// +// Created by Ryan Huffman on 06/24/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 + +#include "AccountManager.h" +#include "Application.h" +#include "UserLocationsModel.h" + +static const QString PLACES_GET = "/api/v1/places"; +static const QString PLACES_UPDATE = "/api/v1/places/%1"; +static const QString PLACES_DELETE= "/api/v1/places/%1"; + +UserLocation::UserLocation(QString id, QString name, QString location) : + _id(id), + _name(name), + _location(location), + _previousName(name), + _updating(false) { +} + +void UserLocation::requestRename(const QString& newName) { + _updating = true; + + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "handleRenameResponse"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "handleRenameError"; + QJsonObject jsonNameObject; + jsonNameObject.insert("name", QJsonValue(newName)); + QJsonDocument jsonDocument(jsonNameObject); + AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id), + QNetworkAccessManager::PutOperation, + callbackParams, + jsonDocument.toJson()); + _previousName = _name; + _name = newName; + + emit updated(_name); +} + +void UserLocation::handleRenameResponse(const QJsonObject& responseData) { + _updating = false; + + qDebug() << responseData; + QJsonValue status = responseData["status"]; + if (status.isUndefined() || status.toString() != "success") { + _name = _previousName; + qDebug() << "There was an error renaming location '" + _name + "'"; + } + + emit updated(_name); +} + +void UserLocation::handleRenameError(QNetworkReply::NetworkError error, const QString& errorString) { + _updating = false; + + QString msg = "There was an error renaming location '" + _name + "': " + errorString; + qDebug() << msg; + QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); + + emit updated(_name); +} + +void UserLocation::requestDelete() { + _updating = true; + + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "handleDeleteResponse"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "handleDeleteError"; + AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id), + QNetworkAccessManager::DeleteOperation, + callbackParams); +} + +void UserLocation::handleDeleteResponse(const QJsonObject& responseData) { + _updating = false; + + QJsonValue status = responseData["status"]; + if (!status.isUndefined() && status.toString() == "success") { + emit deleted(_name); + } else { + qDebug() << "There was an error deleting location '" + _name + "'"; + } +} + +void UserLocation::handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString) { + _updating = false; + + QString msg = "There was an error deleting location '" + _name + "': " + errorString; + qDebug() << msg; + QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); +} + +UserLocationsModel::UserLocationsModel(QObject* parent) : + QAbstractListModel(parent), + _updating(false) { + + refresh(); +} + +void UserLocationsModel::update() { + beginResetModel(); + endResetModel(); +} + +void UserLocationsModel::deleteLocation(const QModelIndex& index) { + UserLocation* location = _locations[index.row()]; + location->requestDelete(); +} + +void UserLocationsModel::renameLocation(const QModelIndex& index, const QString& newName) { + UserLocation* location = _locations[index.row()]; + location->requestRename(newName); +} + +void UserLocationsModel::refresh() { + if (!_updating) { + beginResetModel(); + _locations.clear(); + _updating = true; + endResetModel(); + + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "handleLocationsResponse"; + AccountManager::getInstance().authenticatedRequest(PLACES_GET, + QNetworkAccessManager::GetOperation, + callbackParams); + } +} + +void UserLocationsModel::handleLocationsResponse(const QJsonObject& responseData) { + _updating = false; + + QJsonValue status = responseData["status"]; + if (!status.isUndefined() && status.toString() == "success") { + beginResetModel(); + QJsonArray locations = responseData["data"].toObject()["places"].toArray(); + for (QJsonArray::const_iterator it = locations.constBegin(); it != locations.constEnd(); it++) { + QJsonObject location = (*it).toObject(); + QJsonObject address = location["address"].toObject(); + UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(), + "hifi://" + address["domain"].toString() + "/" + address["position"].toString() + "/" + address["orientation"].toString()); + _locations.append(userLocation); + connect(userLocation, &UserLocation::deleted, this, &UserLocationsModel::removeLocation); + connect(userLocation, &UserLocation::updated, this, &UserLocationsModel::update); + } + endResetModel(); + } else { + qDebug() << "Error loading location data"; + } +} + +void UserLocationsModel::removeLocation(const QString& name) { + beginResetModel(); + for (QList::iterator it = _locations.begin(); it != _locations.end(); it++) { + if ((*it)->name() == name) { + _locations.erase(it); + break; + } + } + endResetModel(); +} + +int UserLocationsModel::rowCount(const QModelIndex& parent) const { + if (parent.isValid()) { + return 0; + } + + if (_updating) { + return 1; + } + + return _locations.length(); +} + +QVariant UserLocationsModel::data(const QModelIndex& index, int role) const { + if (role == Qt::DisplayRole) { + if (_updating) { + return QVariant("Updating..."); + } else if (index.row() > _locations.length()) { + return QVariant(); + } else if (index.column() == NameColumn) { + return _locations[index.row()]->name(); + } else if (index.column() == LocationColumn) { + return QVariant(_locations[index.row()]->location()); + } + } + + return QVariant(); + +} +QVariant UserLocationsModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case NameColumn: return "Name"; + case LocationColumn: return "Location"; + default: return QVariant(); + } + } + + return QVariant(); +} + +Qt::ItemFlags UserLocationsModel::flags(const QModelIndex& index) const { + if (index.row() < _locations.length()) { + UserLocation* ul = _locations[index.row()]; + if (ul->isUpdating()) { + return Qt::NoItemFlags; + } + } + + return QAbstractListModel::flags(index); +} diff --git a/interface/src/UserLocationsModel.h b/interface/src/UserLocationsModel.h new file mode 100644 index 0000000000..7cf984a8ac --- /dev/null +++ b/interface/src/UserLocationsModel.h @@ -0,0 +1,81 @@ +// +// UserLocationsModel.h +// interface/src +// +// Created by Ryan Huffman on 06/24/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_UserLocationsModel_h +#define hifi_UserLocationsModel_h + +#include +#include +#include + + +class UserLocation : public QObject { + Q_OBJECT +public: + UserLocation(QString id, QString name, QString location); + bool isUpdating() { return _updating; } + void requestRename(const QString& newName); + void requestDelete(); + + QString id() { return _id; } + QString name() { return _name; } + QString location() { return _location; } + +public slots: + void handleRenameResponse(const QJsonObject& responseData); + void handleRenameError(QNetworkReply::NetworkError error, const QString& errorString); + void handleDeleteResponse(const QJsonObject& responseData); + void handleDeleteError(QNetworkReply::NetworkError error, const QString& errorString); + +signals: + void updated(const QString& name); + void deleted(const QString& name); + +private: + QString _id; + QString _name; + QString _location; + QString _previousName; + bool _updating; + +}; + +class UserLocationsModel : public QAbstractListModel { + Q_OBJECT +public: + UserLocationsModel(QObject* parent = NULL); + + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + virtual int columnCount(const QModelIndex& parent = QModelIndex()) const { return 2; }; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + + void deleteLocation(const QModelIndex& index); + void renameLocation(const QModelIndex& index, const QString& newName); + + enum Columns { + NameColumn = 0, + LocationColumn + }; + +public slots: + void refresh(); + void update(); + void handleLocationsResponse(const QJsonObject& responseData); + void removeLocation(const QString& name); + +private: + bool _updating; + QList _locations; +}; + +#endif // hifi_UserLocationsModel_h diff --git a/interface/src/ui/UserLocationsWindow.cpp b/interface/src/ui/UserLocationsWindow.cpp new file mode 100644 index 0000000000..7e4cc57248 --- /dev/null +++ b/interface/src/ui/UserLocationsWindow.cpp @@ -0,0 +1,76 @@ +// +// UserLocationsWindow.cpp +// interface/src/ui +// +// Created by Ryan Huffman on 06/24/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 "Menu.h" +#include "UserLocationsWindow.h" + +UserLocationsWindow::UserLocationsWindow(QWidget* parent) : + QWidget(parent, Qt::Window), + _ui(), + _proxyModel(this), + _userLocationsModel(this) { + + _ui.setupUi(this); + + _proxyModel.setSourceModel(&_userLocationsModel); + _proxyModel.setDynamicSortFilter(true); + + _ui.locationsTreeView->setModel(&_proxyModel); + _ui.locationsTreeView->setSortingEnabled(true); + + connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, + this, &UserLocationsWindow::updateEnabled); + connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsWindow::updateEnabled); + connect(&_userLocationsModel, &UserLocationsModel::modelReset, &_proxyModel, &QSortFilterProxyModel::invalidate); + connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsWindow::goToModelIndex); + + connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsWindow::deleteSelection); + connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsWindow::renameSelection); + connect(_ui.refreshButton, &QPushButton::clicked, &_userLocationsModel, &UserLocationsModel::refresh); + + this->setWindowTitle("My Locations"); +} + +void UserLocationsWindow::updateEnabled() { + bool enabled = _ui.locationsTreeView->selectionModel()->hasSelection(); + _ui.renameButton->setEnabled(enabled); + _ui.deleteButton->setEnabled(enabled); +} + +void UserLocationsWindow::goToModelIndex(const QModelIndex& index) { + QVariant location = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::LocationColumn)); + Menu::getInstance()->goToURL(location.toString()); +} + +void UserLocationsWindow::deleteSelection() { + QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); + selection = _proxyModel.mapToSource(selection); + if (selection.isValid()) { + _userLocationsModel.deleteLocation(selection); + } +} + +void UserLocationsWindow::renameSelection() { + QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); + selection = _proxyModel.mapToSource(selection); + if (selection.isValid()) { + bool ok; + QString name = _userLocationsModel.data(selection.sibling(selection.row(), UserLocationsModel::NameColumn)).toString(); + QString newName = QInputDialog::getText(this, "Rename '" + name + "'", "Set name to:", QLineEdit::Normal, name, &ok); + if (ok && !newName.isEmpty()) { + _userLocationsModel.renameLocation(selection, newName); + } + } +} diff --git a/interface/src/ui/UserLocationsWindow.h b/interface/src/ui/UserLocationsWindow.h new file mode 100644 index 0000000000..6188f396a2 --- /dev/null +++ b/interface/src/ui/UserLocationsWindow.h @@ -0,0 +1,35 @@ +// +// UserLocationsWindow.h +// interface/src/ui +// +// Created by Ryan Huffman on 06/24/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_UserLocationsWindow_h +#define hifi_UserLocationsWindow_h + +#include "ui_userLocationsWindow.h" +#include "UserLocationsModel.h" + +class UserLocationsWindow : public QWidget { + Q_OBJECT +public: + UserLocationsWindow(QWidget* parent = NULL); + +protected slots: + void updateEnabled(); + void goToModelIndex(const QModelIndex& index); + void deleteSelection(); + void renameSelection(); + +private: + Ui::UserLocationsWindow _ui; + QSortFilterProxyModel _proxyModel; + UserLocationsModel _userLocationsModel; +}; + +#endif // hifi_UserLocationsWindow_h diff --git a/interface/ui/userLocationsWindow.ui b/interface/ui/userLocationsWindow.ui new file mode 100644 index 0000000000..61bb0149f8 --- /dev/null +++ b/interface/ui/userLocationsWindow.ui @@ -0,0 +1,130 @@ + + + UserLocationsWindow + + + + 0 + 0 + 929 + 633 + + + + Form + + + + -1 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + + + + font-size: 16px + + + My Locations + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Refresh + + + + + + + + + + 0 + + + false + + + + + + + + -1 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Rename + + + + + + + Delete + + + + + + + + + + + From 33e11be3e077b72427101bacf5a25a5ea7a53c61 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Jun 2014 16:06:49 -0700 Subject: [PATCH 02/80] Add user locations to menu --- interface/src/Menu.cpp | 11 +++++++++++ interface/src/Menu.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fa30e0382b..7c9356045c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,6 +45,7 @@ #include "ui/ModelsBrowser.h" #include "ui/LoginDialog.h" #include "ui/NodeBounds.h" +#include "ui/UserLocationsWindow.h" #include "devices/OculusManager.h" @@ -165,6 +166,11 @@ Menu::Menu() : Qt::CTRL | Qt::Key_N, this, SLOT(nameLocation())); + addActionToQMenuAndActionHash(fileMenu, + MenuOption::MyLocations, + Qt::CTRL | Qt::Key_L, + this, + SLOT(showLocationList())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, @@ -1179,6 +1185,11 @@ void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse res msgBox.exec(); } +void Menu::showLocationList() { + UserLocationsWindow* window = new UserLocationsWindow(); + window->show(); +} + void Menu::nameLocation() { // check if user is logged in or show login dialog if not diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 4d2174a448..e353b420dd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -193,6 +193,7 @@ private slots: void goToDomainDialog(); void goToLocation(); void nameLocation(); + void showLocationList(); void bandwidthDetailsClosed(); void octreeStatsDetailsClosed(); void lodToolsClosed(); @@ -387,6 +388,7 @@ namespace MenuOption { const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; + const QString MyLocations = "My Locations..."; const QString NameLocation = "Name this location"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString OctreeStats = "Voxel and Particle Statistics"; From 50e77be406195c50392a5aea1335386bda2f348b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 26 Jun 2014 16:07:02 -0700 Subject: [PATCH 03/80] Add DELETE to AccountManager --- libraries/networking/src/AccountManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 918261a953..8800686178 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -204,6 +204,9 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: } } + break; + case QNetworkAccessManager::DeleteOperation: + networkReply = _networkAccessManager->sendCustomRequest(authenticatedRequest, "DELETE"); break; default: // other methods not yet handled From f13bbdfae60e8d13b225ee2699e54e9cb513ad7c Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 30 Jun 2014 01:28:35 +0200 Subject: [PATCH 04/80] Compile fix for non-standard Qt5 install. When Qt5 5.2.1 is compiled from source, configured with -developer-build, and used without being installed; then compiling interface results in the following compile error: libraries/shared/src/RegisteredMetaTypes.h:17:34: fatal error: QtScript/QScriptEngine: No such file or directory This commit fixes this by explicitely adding the include directory for QtScript/QScriptEngine to libraries/shared/CMakeLists.txt Likewise we get the compile error: In file included from /opt/highfidelity/hifi/hifi/animation-server/../libraries/voxels/src/VoxelEditPacketSender.h:18:0, from /opt/highfidelity/hifi/hifi/animation-server/src/AnimationServer.cpp:26: /opt/highfidelity/hifi/hifi/animation-server/../libraries/voxels/src/VoxelDetail.h:15:34: fatal error: QtScript/QScriptEngine: No such file or directory which is fixed by added the include directory for QtScript/QScriptEngine to animation-server/CMakeLists.txt Finally, compile errors like In file included from /opt/highfidelity/hifi/hifi/libraries/audio/src/AudioInjectorOptions.h:20:0, from /opt/highfidelity/hifi/hifi/libraries/audio/src/AudioInjector.h:21, from /opt/highfidelity/hifi/hifi/libraries/audio/src/AudioInjector.cpp:22: /opt/highfidelity/hifi/hifi/assignment-client/../libraries/shared/src/RegisteredMetaTypes.h:17:34: fatal error: QtScript/QScriptEngine: No such file or directory that requires to do the same in libraries/audio/CMakeLists.txt --- animation-server/CMakeLists.txt | 5 ++++- libraries/audio/CMakeLists.txt | 5 ++++- libraries/shared/CMakeLists.txt | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt index 42516d2f86..31ed5d98df 100644 --- a/animation-server/CMakeLists.txt +++ b/animation-server/CMakeLists.txt @@ -12,6 +12,9 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") # setup for find modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") +find_package(Qt5 COMPONENTS Script) +include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") + # set up the external glm library include("${MACRO_DIR}/IncludeGLM.cmake") include_glm(${TARGET_NAME} "${ROOT_DIR}") @@ -35,4 +38,4 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +endif () diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index 60636ba051..fafdfc7e6c 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -12,6 +12,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME audio) +find_package(Qt5 COMPONENTS Script) +include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") + # set up the external glm library include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -26,4 +29,4 @@ link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") # add a definition for ssize_t so that windows doesn't bail if (WIN32) add_definitions(-Dssize_t=long) -endif () \ No newline at end of file +endif () diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 7f9a34492d..560546473c 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -10,7 +10,7 @@ set(MACRO_DIR "${ROOT_DIR}/cmake/macros") set(TARGET_NAME shared) project(${TARGET_NAME}) -find_package(Qt5 COMPONENTS Network Widgets Xml) +find_package(Qt5 COMPONENTS Network Widgets Xml Script) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) @@ -32,4 +32,8 @@ if (UNIX AND NOT APPLE) target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") endif (UNIX AND NOT APPLE) -target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets) \ No newline at end of file +# There is something special (bug) about Qt5Scripts, that we have to explicitly add its include +# directory when Qt5 (5.2.1) is compiled from source and is not in a standard place. +include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") + +target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets) From 37f0635024ed56e5533ab672a37b2040569bb820 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 30 Jun 2014 02:07:26 +0200 Subject: [PATCH 05/80] Fix a (possible) crash in QObject::disconnect This is https://worklist.net/19827 --- interface/src/Audio.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 65912f83e8..5a16cd80bd 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -1327,8 +1327,10 @@ bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { // cleanup any previously initialized device if (_audioInput) { + // The call to stop() causes _inputDevice to be destructed. + // That in turn causes it to be disconnected (see for example + // http://stackoverflow.com/questions/9264750/qt-signals-and-slots-object-disconnect). _audioInput->stop(); - disconnect(_inputDevice); _inputDevice = NULL; delete _audioInput; From 9ca1bfdfe504cc2630b825a0ce59acbc476c8917 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 30 Jun 2014 18:05:22 -0700 Subject: [PATCH 06/80] add AngularConstraint.* with some unit tests more unit tests to follow --- interface/src/renderer/JointState.cpp | 9 +- interface/src/renderer/JointState.h | 4 + libraries/shared/src/AngularConstraint.cpp | 176 ++++++++++++ libraries/shared/src/AngularConstraint.h | 53 ++++ tests/shared/src/AngularConstraintTests.cpp | 291 ++++++++++++++++++++ tests/shared/src/AngularConstraintTests.h | 21 ++ 6 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 libraries/shared/src/AngularConstraint.cpp create mode 100644 libraries/shared/src/AngularConstraint.h create mode 100644 tests/shared/src/AngularConstraintTests.cpp create mode 100644 tests/shared/src/AngularConstraintTests.h diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index e66a2f44e9..3b3c135eb5 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -11,6 +11,7 @@ #include +#include //#include #include @@ -18,7 +19,13 @@ JointState::JointState() : _animationPriority(0.0f), - _fbxJoint(NULL) { + _fbxJoint(NULL), + _constraint(NULL) { +} + +JointState::~JointState() { + delete _constraint; + _constraint = NULL; } void JointState::setFBXJoint(const FBXJoint* joint) { diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index b1a584d4ec..4eadc51f7c 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -18,9 +18,12 @@ #include +class AngularConstraint; + class JointState { public: JointState(); + ~JointState(); void setFBXJoint(const FBXJoint* joint); const FBXJoint& getFBXJoint() const { return *_fbxJoint; } @@ -61,6 +64,7 @@ private: glm::quat _rotation; // joint- to model-frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint + AngularConstraint* _constraint; }; #endif // hifi_JointState_h diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp new file mode 100644 index 0000000000..bf565d586e --- /dev/null +++ b/libraries/shared/src/AngularConstraint.cpp @@ -0,0 +1,176 @@ +// +// AngularConstraint.cpp +// interface/src/renderer +// +// Created by Andrew Meadows on 2014.05.30 +// 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 // adebug +#include + +#include "AngularConstraint.h" +#include "SharedUtil.h" +#include "StreamUtils.h" // adebug + +// helper function +/// \param angle radian angle to be clamped within angleMin and angleMax +/// \param angleMin minimum value +/// \param angleMax maximum value +/// \return value between minAngle and maxAngle closest to angle +float clampAngle(float angle, float angleMin, float angleMax) { + float minDistance = angle - angleMin; + float maxDistance = angle - angleMax; + if (maxDistance > 0.0f) { + minDistance = glm::min(minDistance, angleMin + TWO_PI - angle); + angle = (minDistance < maxDistance) ? angleMin : angleMax; + } else if (minDistance < 0.0f) { + maxDistance = glm::max(maxDistance, angleMax - TWO_PI - angle); + angle = (minDistance > maxDistance) ? angleMin : angleMax; + } + return angle; +} + +// static +AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minAngles, const glm::vec3& maxAngles) { + float minDistance2 = glm::distance2(minAngles, glm::vec3(-PI, -PI, -PI)); + float maxDistance2 = glm::distance2(maxAngles, glm::vec3(PI, PI, PI)); + if (minDistance2 < EPSILON && maxDistance2 < EPSILON) { + // no constraint + return NULL; + } + // count the zero length elements + glm::vec3 rangeAngles = maxAngles - minAngles; + int pivotIndex = -1; + int numZeroes = 0; + for (int i = 0; i < 3; ++i) { + if (rangeAngles[i] < EPSILON) { + ++numZeroes; + } else { + pivotIndex = i; + } + } + if (numZeroes == 2) { + // this is a hinge + int forwardIndex = (pivotIndex + 1) % 3; + glm::vec3 forwardAxis(0.0f); + forwardAxis[forwardIndex] = 1.0f; + glm::vec3 rotationAxis(0.0f); + rotationAxis[pivotIndex] = 1.0f; + return new HingeConstraint(forwardAxis, rotationAxis, minAngles[pivotIndex], maxAngles[pivotIndex]); + } else if (numZeroes == 0) { + // approximate the angular limits with a cone roller + // we assume the roll is about z + glm::vec3 middleAngles = 0.5f * (maxAngles - minAngles); + glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); + glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 coneAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); + // the coneAngle is half of the average range of the two non-roll rotations + float coneAngle = 0.25f * (middleAngles[0] + middleAngles[1]); + + return new ConeRollerConstraint(coneAngle, coneAxis, minAngles.z, maxAngles.z); + } + return NULL; +} + +HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle) + : _minAngle(minAngle), _maxAngle(maxAngle) { + assert(_minAngle < _maxAngle); + // we accept the rotationAxis direction + assert(glm::length(rotationAxis) > EPSILON); + _rotationAxis = glm::normalize(rotationAxis); + // but we compute the final _forwardAxis + glm::vec3 otherAxis = glm::cross(_rotationAxis, forwardAxis); + assert(glm::length(otherAxis) > EPSILON); + _forwardAxis = glm::normalize(glm::cross(otherAxis, _rotationAxis)); +} + +// virtual +bool HingeConstraint::applyTo(glm::quat& rotation) const { + glm::vec3 forward = rotation * _forwardAxis; + forward -= glm::dot(forward, _rotationAxis) * _rotationAxis; + float length = glm::length(forward); + if (length < EPSILON) { + // infinite number of solutions ==> choose the middle of the contrained range + rotation = glm::angleAxis(0.5f * (_minAngle + _maxAngle), _rotationAxis); + return true; + } + forward /= length; + float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); + //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); + float angle = sign * acos(glm::dot(forward, _forwardAxis)); +// std::cout << "adebug forward = " << forward << " _forwardAxis = " << _forwardAxis << " angle = " << angle << std::endl; // adebug + glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); + if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { + rotation = newRotation; + return true; + } + return false; +} + +ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll) + : _coneAngle(coneAngle), _minRoll(minRoll), _maxRoll(maxRoll) { + assert(_maxRoll >= _minRoll); + float axisLength = glm::length(coneAxis); + assert(axisLength > EPSILON); + _coneAxis = coneAxis / axisLength; +} + +// virtual +bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { + bool applied = false; + glm::vec3 rotatedAxis = rotation * _coneAxis; + glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); + float perpAxisLength = glm::length(perpAxis); + + // enforce the cone + float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); + if (angle > _coneAngle && perpAxisLength > EPSILON) { + perpAxis /= perpAxisLength; + rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; + rotatedAxis = rotation * _coneAxis; + applied = true; + } + + // enforce the roll + if (perpAxisLength < EPSILON) { + // there is no obvious perp axis so we must pick one + perpAxis = rotatedAxis; + // find the first non-zero element: + float value = 0.0f; + int i = 0; + for (i = 0; i < 3; ++i) { + if (fabsf(perpAxis[i]) > EPSILON) { + value = perpAxis[i]; + break; + } + } + assert(i != 3); + // swap or negate the next element + int j = (i + 1) % 3; + float value2 = perpAxis[j]; + if (fabsf(value2 - value) > EPSILON) { + perpAxis[i] = value2; + perpAxis[j] = value; + } else { + perpAxis[i] = -value; + } + perpAxis = glm::cross(perpAxis, rotatedAxis); + perpAxisLength = glm::length(perpAxis); + assert(perpAxisLength > EPSILON); + } + perpAxis /= perpAxisLength; + glm::vec3 rotatedPerpAxis = rotation * perpAxis; + float roll = angleBetween(rotatedPerpAxis, perpAxis); + if (roll < _minRoll || roll > _maxRoll) { + float newRoll = clampAngle(roll, _minRoll, _maxRoll); + rotation = glm::angleAxis(newRoll - roll, rotatedAxis) * rotation; + applied = true; + } + return applied; +} + + diff --git a/libraries/shared/src/AngularConstraint.h b/libraries/shared/src/AngularConstraint.h new file mode 100644 index 0000000000..8003e4c9a3 --- /dev/null +++ b/libraries/shared/src/AngularConstraint.h @@ -0,0 +1,53 @@ +// +// AngularConstraint.h +// interface/src/renderer +// +// Created by Andrew Meadows on 2014.05.30 +// Copyright 2013 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_AngularConstraint_h +#define hifi_AngularConstraint_h + +#include + + +class AngularConstraint { +public: + /// \param minAngles minumum euler angles for the constraint + /// \param maxAngles minumum euler angles for the constraint + /// \return pointer to new AngularConstraint of the right type or NULL if none could be made + static AngularConstraint* newAngularConstraint(const glm::vec3& minAngles, const glm::vec3& maxAngles); + + AngularConstraint() {} + virtual ~AngularConstraint() {} + virtual bool applyTo(glm::quat& rotation) const = 0; +protected: +}; + +class HingeConstraint : public AngularConstraint { +public: + HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle); + virtual bool applyTo(glm::quat& rotation) const; +protected: + glm::vec3 _forwardAxis; + glm::vec3 _rotationAxis; + float _minAngle; + float _maxAngle; +}; + +class ConeRollerConstraint : public AngularConstraint { +public: + ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll); + virtual bool applyTo(glm::quat& rotation) const; +private: + float _coneAngle; + glm::vec3 _coneAxis; + float _minRoll; + float _maxRoll; +}; + +#endif // hifi_AngularConstraint_h diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp new file mode 100644 index 0000000000..4c087821c5 --- /dev/null +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -0,0 +1,291 @@ +// +// AngularConstraintTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.05.30 +// 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 + +#include "AngularConstraintTests.h" + + +void AngularConstraintTests::testHingeConstraint() { + float minAngle = -PI; + float maxAngle = 0.0f; + glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + glm::vec3 minAngles(0.0f, -PI, 0.0f); + glm::vec3 maxAngles(0.0f, 0.0f, 0.0f); + + AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles); + if (!c) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: newAngularConstraint() should make a constraint" << std::endl; + } + + { // test in middle of constraint + float angle = 0.5f * (minAngle + maxAngle); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just inside min edge of constraint + float angle = minAngle + 10.f * EPSILON; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just inside max edge of constraint + float angle = maxAngle - 10.f * EPSILON; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should not change rotation" << std::endl; + } + } + { // test just outside min edge of constraint + float angle = minAngle - 0.001f; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test just outside max edge of constraint + float angle = maxAngle + 0.001f; + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside min edge of constraint (wraps around to max) + float angle = minAngle - 0.75f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside max edge of constraint (wraps around to min) + float angle = maxAngle + 0.75f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + + float ACCEPTABLE_ERROR = 1.0e-4f; + { // test nearby but off-axis rotation + float offAngle = 0.1f; + glm::quat offRotation(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = 0.5f * (maxAngle + minAngle); + glm::quat rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(angle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation > maxAngle + float offAngle = 0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = maxAngle + 0.2f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation < minAngle + float offAngle = 0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = minAngle - 0.2f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation > maxAngle with wrap over to minAngle + float offAngle = -0.5f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = maxAngle + 0.6f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test way off rotation < minAngle with wrap over to maxAngle + float offAngle = -0.6f; + glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f)); + float angle = minAngle - 0.7f * (TWO_PI - (maxAngle - minAngle)); + glm::quat rotation = glm::angleAxis(angle, yAxis); + rotation = offRotation * glm::angleAxis(angle, yAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis); + float qDot = glm::dot(expectedRotation, newRotation); + if (fabsf(qDot - 1.0f) > ACCEPTABLE_ERROR) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } +} + +void AngularConstraintTests::testConeRollerConstraint() { +} + +void AngularConstraintTests::runAllTests() { + testHingeConstraint(); +} diff --git a/tests/shared/src/AngularConstraintTests.h b/tests/shared/src/AngularConstraintTests.h new file mode 100644 index 0000000000..f0994f08c9 --- /dev/null +++ b/tests/shared/src/AngularConstraintTests.h @@ -0,0 +1,21 @@ +// +// AngularConstraintTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.05.30 +// 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_AngularConstraintTests_h +#define hifi_AngularConstraintTests_h + +namespace AngularConstraintTests { + void testHingeConstraint(); + void testConeRollerConstraint(); + void runAllTests(); +} + +#endif // hifi_AngularConstraintTests_h From 51e42221be651a6a504a48b162965c14b2d7ef08 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 22:24:27 -0700 Subject: [PATCH 07/80] Update menu to toggle User Locations Menu --- interface/src/Menu.cpp | 18 ++++++++++++------ interface/src/Menu.h | 4 +++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7c9356045c..ae3cc1b77c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -45,7 +45,6 @@ #include "ui/ModelsBrowser.h" #include "ui/LoginDialog.h" #include "ui/NodeBounds.h" -#include "ui/UserLocationsWindow.h" #include "devices/OculusManager.h" @@ -92,6 +91,7 @@ Menu::Menu() : _jsConsole(NULL), _octreeStatsDialog(NULL), _lodToolsDialog(NULL), + _userLocationsWindow(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), @@ -168,9 +168,9 @@ Menu::Menu() : SLOT(nameLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::MyLocations, - Qt::CTRL | Qt::Key_L, + Qt::CTRL | Qt::Key_K, this, - SLOT(showLocationList())); + SLOT(toggleLocationList())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, @@ -1185,9 +1185,15 @@ void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse res msgBox.exec(); } -void Menu::showLocationList() { - UserLocationsWindow* window = new UserLocationsWindow(); - window->show(); +void Menu::toggleLocationList() { + if (!_userLocationsWindow) { + _userLocationsWindow = new UserLocationsWindow(); + } + if (_userLocationsWindow->isVisible()) { + _userLocationsWindow->hide(); + } else { + _userLocationsWindow->show(); + } } void Menu::nameLocation() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e353b420dd..9a5e2f9d43 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -29,6 +29,7 @@ #include "ui/JSConsole.h" #include "ui/LoginDialog.h" #include "ui/ScriptEditorWindow.h" +#include "ui/UserLocationsWindow.h" const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -193,7 +194,7 @@ private slots: void goToDomainDialog(); void goToLocation(); void nameLocation(); - void showLocationList(); + void toggleLocationList(); void bandwidthDetailsClosed(); void octreeStatsDetailsClosed(); void lodToolsClosed(); @@ -260,6 +261,7 @@ private: QDialog* _jsConsole; OctreeStatsDialog* _octreeStatsDialog; LodToolsDialog* _lodToolsDialog; + UserLocationsWindow* _userLocationsWindow; int _maxVoxels; float _voxelSizeScale; float _oculusUIAngularSize; From 15d60df4203f97b442c9df442fa9216194e3b441 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 22:25:00 -0700 Subject: [PATCH 08/80] Update User Locations window to update name when it changes on update --- interface/src/UserLocationsModel.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 4ad91bed73..051b04eb95 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -56,9 +56,14 @@ void UserLocation::handleRenameResponse(const QJsonObject& responseData) { qDebug() << responseData; QJsonValue status = responseData["status"]; - if (status.isUndefined() || status.toString() != "success") { + if (!status.isUndefined() && status.toString() == "success") { + QString updatedName = responseData["data"].toObject()["name"].toString(); + _name = updatedName; + } else { _name = _previousName; - qDebug() << "There was an error renaming location '" + _name + "'"; + QString msg = "There was an error renaming location '" + _name + "'"; + qDebug() << msg; + QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); } emit updated(_name); @@ -94,7 +99,9 @@ void UserLocation::handleDeleteResponse(const QJsonObject& responseData) { if (!status.isUndefined() && status.toString() == "success") { emit deleted(_name); } else { - qDebug() << "There was an error deleting location '" + _name + "'"; + QString msg = "There was an error deleting location '" + _name + "'"; + qDebug() << msg; + QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); } } From a566f90820389d3a5443042f7266de01f9240b6e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 22:37:13 -0700 Subject: [PATCH 09/80] Update User Location update/delete to not work simultaneously --- interface/src/UserLocationsModel.cpp | 54 +++++++++++++++------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 051b04eb95..539f9197a4 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -31,24 +31,26 @@ UserLocation::UserLocation(QString id, QString name, QString location) : } void UserLocation::requestRename(const QString& newName) { - _updating = true; + if (!_updating) { + _updating = true; - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "handleRenameResponse"; - callbackParams.errorCallbackReceiver = this; - callbackParams.errorCallbackMethod = "handleRenameError"; - QJsonObject jsonNameObject; - jsonNameObject.insert("name", QJsonValue(newName)); - QJsonDocument jsonDocument(jsonNameObject); - AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id), - QNetworkAccessManager::PutOperation, - callbackParams, - jsonDocument.toJson()); - _previousName = _name; - _name = newName; + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "handleRenameResponse"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "handleRenameError"; + QJsonObject jsonNameObject; + jsonNameObject.insert("name", QJsonValue(newName)); + QJsonDocument jsonDocument(jsonNameObject); + AccountManager::getInstance().authenticatedRequest(PLACES_UPDATE.arg(_id), + QNetworkAccessManager::PutOperation, + callbackParams, + jsonDocument.toJson()); + _previousName = _name; + _name = newName; - emit updated(_name); + emit updated(_name); + } } void UserLocation::handleRenameResponse(const QJsonObject& responseData) { @@ -80,16 +82,18 @@ void UserLocation::handleRenameError(QNetworkReply::NetworkError error, const QS } void UserLocation::requestDelete() { - _updating = true; + if (!_updating) { + _updating = true; - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "handleDeleteResponse"; - callbackParams.errorCallbackReceiver = this; - callbackParams.errorCallbackMethod = "handleDeleteError"; - AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id), - QNetworkAccessManager::DeleteOperation, - callbackParams); + JSONCallbackParameters callbackParams; + callbackParams.jsonCallbackReceiver = this; + callbackParams.jsonCallbackMethod = "handleDeleteResponse"; + callbackParams.errorCallbackReceiver = this; + callbackParams.errorCallbackMethod = "handleDeleteError"; + AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id), + QNetworkAccessManager::DeleteOperation, + callbackParams); + } } void UserLocation::handleDeleteResponse(const QJsonObject& responseData) { From bfde24fe121621ea22c3c0df51aa1aea96e68345 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 22:37:32 -0700 Subject: [PATCH 10/80] Update MyLocations sort order --- interface/src/ui/UserLocationsWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/UserLocationsWindow.cpp b/interface/src/ui/UserLocationsWindow.cpp index 7e4cc57248..523d32f930 100644 --- a/interface/src/ui/UserLocationsWindow.cpp +++ b/interface/src/ui/UserLocationsWindow.cpp @@ -29,6 +29,7 @@ UserLocationsWindow::UserLocationsWindow(QWidget* parent) : _ui.locationsTreeView->setModel(&_proxyModel); _ui.locationsTreeView->setSortingEnabled(true); + _ui.locationsTreeView->sortByColumn(UserLocationsModel::NameColumn, Qt::AscendingOrder); connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &UserLocationsWindow::updateEnabled); From 50b13c99a7e3486a200ee245692f25a09fafba45 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 22:44:04 -0700 Subject: [PATCH 11/80] Update UserLocationsWindow derive from QDialog --- interface/src/ui/UserLocationsWindow.cpp | 2 +- interface/src/ui/UserLocationsWindow.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/UserLocationsWindow.cpp b/interface/src/ui/UserLocationsWindow.cpp index 523d32f930..f7e684fc64 100644 --- a/interface/src/ui/UserLocationsWindow.cpp +++ b/interface/src/ui/UserLocationsWindow.cpp @@ -17,7 +17,7 @@ #include "UserLocationsWindow.h" UserLocationsWindow::UserLocationsWindow(QWidget* parent) : - QWidget(parent, Qt::Window), + QDialog(parent), _ui(), _proxyModel(this), _userLocationsModel(this) { diff --git a/interface/src/ui/UserLocationsWindow.h b/interface/src/ui/UserLocationsWindow.h index 6188f396a2..215c1957f3 100644 --- a/interface/src/ui/UserLocationsWindow.h +++ b/interface/src/ui/UserLocationsWindow.h @@ -15,7 +15,7 @@ #include "ui_userLocationsWindow.h" #include "UserLocationsModel.h" -class UserLocationsWindow : public QWidget { +class UserLocationsWindow : public QDialog { Q_OBJECT public: UserLocationsWindow(QWidget* parent = NULL); From 5934ee5b22bf06fcaae13ed79555dda21a86ff71 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Jul 2014 09:35:47 -0700 Subject: [PATCH 12/80] added tests for ConeRollerConstraint --- libraries/shared/src/AngularConstraint.cpp | 59 +++---- tests/shared/src/AngularConstraintTests.cpp | 183 ++++++++++++++++++++ tests/shared/src/main.cpp | 2 + 3 files changed, 215 insertions(+), 29 deletions(-) diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp index bf565d586e..48649450e1 100644 --- a/libraries/shared/src/AngularConstraint.cpp +++ b/libraries/shared/src/AngularConstraint.cpp @@ -9,12 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include // adebug #include #include "AngularConstraint.h" #include "SharedUtil.h" -#include "StreamUtils.h" // adebug // helper function /// \param angle radian angle to be clamped within angleMin and angleMax @@ -64,13 +62,13 @@ AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minA } else if (numZeroes == 0) { // approximate the angular limits with a cone roller // we assume the roll is about z - glm::vec3 middleAngles = 0.5f * (maxAngles - minAngles); + glm::vec3 middleAngles = 0.5f * (maxAngles + minAngles); glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); glm::vec3 coneAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); - // the coneAngle is half of the average range of the two non-roll rotations - float coneAngle = 0.25f * (middleAngles[0] + middleAngles[1]); - + // the coneAngle is half the average range of the two non-roll rotations + glm::vec3 range = maxAngles - minAngles; + float coneAngle = 0.25f * (range[0] + range[1]); return new ConeRollerConstraint(coneAngle, coneAxis, minAngles.z, maxAngles.z); } return NULL; @@ -102,7 +100,6 @@ bool HingeConstraint::applyTo(glm::quat& rotation) const { float sign = (glm::dot(glm::cross(_forwardAxis, forward), _rotationAxis) > 0.0f ? 1.0f : -1.0f); //float angle = sign * acos(glm::dot(forward, _forwardAxis) / length); float angle = sign * acos(glm::dot(forward, _forwardAxis)); -// std::cout << "adebug forward = " << forward << " _forwardAxis = " << _forwardAxis << " angle = " << angle << std::endl; // adebug glm::quat newRotation = glm::angleAxis(clampAngle(angle, _minAngle, _maxAngle), _rotationAxis); if (fabsf(1.0f - glm::dot(newRotation, rotation)) > EPSILON * EPSILON) { rotation = newRotation; @@ -125,49 +122,53 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { glm::vec3 rotatedAxis = rotation * _coneAxis; glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); float perpAxisLength = glm::length(perpAxis); - - // enforce the cone - float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); - if (angle > _coneAngle && perpAxisLength > EPSILON) { + if (perpAxisLength > EPSILON) { perpAxis /= perpAxisLength; - rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; - rotatedAxis = rotation * _coneAxis; - applied = true; + // enforce the cone + float angle = acosf(glm::dot(rotatedAxis, _coneAxis)); + if (angle > _coneAngle) { + rotation = glm::angleAxis(angle - _coneAngle, perpAxis) * rotation; + rotatedAxis = rotation * _coneAxis; + applied = true; + } } - - // enforce the roll - if (perpAxisLength < EPSILON) { + else { + // the rotation is 100% roll // there is no obvious perp axis so we must pick one perpAxis = rotatedAxis; // find the first non-zero element: - float value = 0.0f; + float iValue = 0.0f; int i = 0; for (i = 0; i < 3; ++i) { if (fabsf(perpAxis[i]) > EPSILON) { - value = perpAxis[i]; + iValue = perpAxis[i]; break; } } assert(i != 3); // swap or negate the next element int j = (i + 1) % 3; - float value2 = perpAxis[j]; - if (fabsf(value2 - value) > EPSILON) { - perpAxis[i] = value2; - perpAxis[j] = value; + float jValue = perpAxis[j]; + if (fabsf(jValue - iValue) > EPSILON) { + perpAxis[i] = jValue; + perpAxis[j] = iValue; } else { - perpAxis[i] = -value; + perpAxis[i] = -iValue; } perpAxis = glm::cross(perpAxis, rotatedAxis); perpAxisLength = glm::length(perpAxis); assert(perpAxisLength > EPSILON); + perpAxis /= perpAxisLength; } - perpAxis /= perpAxisLength; - glm::vec3 rotatedPerpAxis = rotation * perpAxis; - float roll = angleBetween(rotatedPerpAxis, perpAxis); + // measure the roll + // NOTE: perpAxis is perpendicular to both _coneAxis and rotatedConeAxis, so we can + // rotate it again and we'll end up with an something that has only been rolled. + glm::vec3 rolledPerpAxis = rotation * perpAxis; + float sign = glm::dot(rotatedAxis, glm::cross(perpAxis, rolledPerpAxis)) > 0.0f ? 1.0f : -1.0f; + float roll = sign * angleBetween(rolledPerpAxis, perpAxis); if (roll < _minRoll || roll > _maxRoll) { - float newRoll = clampAngle(roll, _minRoll, _maxRoll); - rotation = glm::angleAxis(newRoll - roll, rotatedAxis) * rotation; + float clampedRoll = clampAngle(roll, _minRoll, _maxRoll); + rotation = glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation; applied = true; } return applied; diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 4c087821c5..22762ea524 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -284,8 +284,191 @@ void AngularConstraintTests::testHingeConstraint() { } void AngularConstraintTests::testConeRollerConstraint() { + float minAngleX = -PI / 5.0f; + float minAngleY = -PI / 5.0f; + float minAngleZ = -PI / 8.0f; + + float maxAngleX = PI / 4.0f; + float maxAngleY = PI / 3.0f; + float maxAngleZ = PI / 4.0f; + + glm::vec3 minAngles(minAngleX, minAngleY, minAngleZ); + glm::vec3 maxAngles(maxAngleX, maxAngleY, maxAngleZ); + AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles); + + float expectedConeAngle = 0.25 * (maxAngleX - minAngleX + maxAngleY - minAngleY); + glm::vec3 middleAngles = 0.5f * (maxAngles + minAngles); + glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f)); + glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 expectedConeAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f); + + glm::vec3 xAxis(1.0f, 0.0f, 0.0f); + glm::vec3 perpAxis = glm::normalize(xAxis - glm::dot(xAxis, expectedConeAxis) * expectedConeAxis); + + if (!c) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: newAngularConstraint() should make a constraint" << std::endl; + } + { // test in middle of constraint + glm::vec3 angles(PI/20.0f, 0.0f, PI/10.0f); + glm::quat rotation(angles); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + float deltaAngle = 0.001f; + { // test just inside edge of cone + glm::quat rotation = glm::angleAxis(expectedConeAngle - deltaAngle, perpAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just outside edge of cone + glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + } + { // test just inside min edge of roll + glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just inside max edge of roll + glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + } + if (rotation != newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should not change rotation" << std::endl; + } + } + { // test just outside min edge of roll + glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(minAngleZ, expectedConeAxis); + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test just outside max edge of roll + glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRotation = glm::angleAxis(maxAngleZ, expectedConeAxis); + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + deltaAngle = 0.25f * expectedConeAngle; + { // test far outside cone and min roll + glm::quat roll = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); + glm::quat pitchYaw = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); + glm::quat rotation = pitchYaw * roll; + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRoll = glm::angleAxis(minAngleZ, expectedConeAxis); + glm::quat expectedPitchYaw = glm::angleAxis(expectedConeAngle, perpAxis); + glm::quat expectedRotation = expectedPitchYaw * expectedRoll; + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } + { // test far outside cone and max roll + glm::quat roll = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); + glm::quat pitchYaw = glm::angleAxis(- expectedConeAngle - deltaAngle, perpAxis); + glm::quat rotation = pitchYaw * roll; + + glm::quat newRotation = rotation; + bool constrained = c->applyTo(newRotation); + if (!constrained) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + } + if (rotation == newRotation) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: ConeRollerConstraint should change rotation" << std::endl; + } + glm::quat expectedRoll = glm::angleAxis(maxAngleZ, expectedConeAxis); + glm::quat expectedPitchYaw = glm::angleAxis(- expectedConeAngle, perpAxis); + glm::quat expectedRotation = expectedPitchYaw * expectedRoll; + if (fabsf(1.0f - glm::dot(newRotation, expectedRotation)) > EPSILON) { + std::cout << __FILE__ << ":" << __LINE__ + << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; + } + } } void AngularConstraintTests::runAllTests() { testHingeConstraint(); + testConeRollerConstraint(); } diff --git a/tests/shared/src/main.cpp b/tests/shared/src/main.cpp index 3ae1b7b34d..6215d394a8 100644 --- a/tests/shared/src/main.cpp +++ b/tests/shared/src/main.cpp @@ -8,9 +8,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "AngularConstraintTests.h" #include "MovingPercentileTests.h" int main(int argc, char** argv) { MovingPercentileTests::runAllTests(); + AngularConstraintTests::runAllTests(); return 0; } From 5ba4a4dbb58018fe460a5ed327352447b5ca2b1c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Jul 2014 09:53:18 -0700 Subject: [PATCH 13/80] initial pass of MIDI implementation that bubbles events to JS --- .gitignore | 4 + cmake/modules/FindRtMidi.cmake | 33 +++++++ interface/CMakeLists.txt | 94 ++++++++++++-------- interface/external/rtmidi/readme.txt | 41 +++++++++ interface/src/Application.cpp | 6 ++ interface/src/devices/MIDIManager.cpp | 64 +++++++++++++ interface/src/devices/MIDIManager.h | 46 ++++++++++ libraries/script-engine/src/MIDIEvent.cpp | 37 ++++++++ libraries/script-engine/src/MIDIEvent.h | 32 +++++++ libraries/script-engine/src/ScriptEngine.cpp | 2 + 10 files changed, 321 insertions(+), 38 deletions(-) create mode 100644 cmake/modules/FindRtMidi.cmake create mode 100644 interface/external/rtmidi/readme.txt create mode 100644 interface/src/devices/MIDIManager.cpp create mode 100644 interface/src/devices/MIDIManager.h create mode 100644 libraries/script-engine/src/MIDIEvent.cpp create mode 100644 libraries/script-engine/src/MIDIEvent.h diff --git a/.gitignore b/.gitignore index 8d537b993f..4176dcc652 100644 --- a/.gitignore +++ b/.gitignore @@ -50,5 +50,9 @@ interface/external/faceplus/* interface/external/priovr/* !interface/external/priovr/readme.txt +# Ignore RtMidi +interface/external/rtmidi/* +!interface/external/rtmidi/readme.txt + # Ignore interfaceCache for Linux users interface/interfaceCache/ diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake new file mode 100644 index 0000000000..a54cc483e1 --- /dev/null +++ b/cmake/modules/FindRtMidi.cmake @@ -0,0 +1,33 @@ +# +# FindRtMidd.cmake +# +# Try to find the RtMidi library +# +# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# RTMIDI_FOUND - system found RtMidi +# RTMIDI_INCLUDE_DIRS - the RtMidi include directory +# RTMIDI_CPP - Include this with src to use RtMidi +# +# Created on 6/30/2014 by Stephen Birarda +# 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 +# + +if (RTMIDI_LIBRARIES AND RTMIDI_INCLUDE_DIRS) + # in cache already + set(RTMIDI_FOUND TRUE) +else () + + set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi") + + find_path(RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS}) + find_file(RTMIDI_CPP NAMES RtMidi.cpp PATH_SUFFIXES src HINTS ${RTMIDI_SEARCH_DIRS}) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP) +endif () \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index cf203c41d9..35272ad22d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -18,6 +18,7 @@ set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus") set(PRIOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/priovr") set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense") set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage") +set(RTMIDI_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/rtmidi") find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) @@ -110,6 +111,16 @@ if (APPLE) SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns") endif() +# RtMidi for scripted MIDI control +find_package(RtMidi) + +if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI) + add_definitions(-DHAVE_RTMIDI) + include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR}) + + set(INTERFACE_SRCS ${INTERFACE_SRCS} "${RTMIDI_CPP}") +endif () + # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) @@ -143,71 +154,78 @@ find_package(Qxmpp) # include the Sixense library for Razer Hydra if available if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) - add_definitions(-DHAVE_SIXENSE) - include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}") - if (APPLE OR UNIX) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}") - endif (APPLE OR UNIX) - target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}") + add_definitions(-DHAVE_SIXENSE) + include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}") + if (APPLE OR UNIX) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}") + endif (APPLE OR UNIX) + target_link_libraries(${TARGET_NAME} "${SIXENSE_LIBRARIES}") endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) # likewise with Visage library for webcam feature tracking if (VISAGE_FOUND AND NOT DISABLE_VISAGE) - add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC) - include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}") - if (APPLE) - add_definitions(-DMAC_OS_X) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment") - include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}") - find_library(AVFoundation AVFoundation) - find_library(CoreMedia CoreMedia) - find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/) - target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY}) - endif (APPLE) - target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}") + add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC) + include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}") + if (APPLE) + add_definitions(-DMAC_OS_X) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment") + include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}") + find_library(AVFoundation AVFoundation) + find_library(CoreMedia CoreMedia) + find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/) + target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY}) + endif (APPLE) + target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}") endif (VISAGE_FOUND AND NOT DISABLE_VISAGE) # and with Faceplus library, also for webcam feature tracking if (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS) - add_definitions(-DHAVE_FACEPLUS) - include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}") - target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}") + add_definitions(-DHAVE_FACEPLUS) + include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}") + target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}") endif (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS) # and with LibOVR for Oculus Rift if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR) - add_definitions(-DHAVE_LIBOVR) - include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}") - - if (APPLE OR UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}") - endif () - - target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}") + add_definitions(-DHAVE_LIBOVR) + include_directories(SYSTEM "${LIBOVR_INCLUDE_DIRS}") + + if (APPLE OR UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_INCLUDE_DIRS}") + endif () + + target_link_libraries(${TARGET_NAME} "${LIBOVR_LIBRARIES}") endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR) # and with PrioVR library if (PRIOVR_FOUND AND NOT DISABLE_PRIOVR) - add_definitions(-DHAVE_PRIOVR) - include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}") - target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}") + add_definitions(-DHAVE_PRIOVR) + include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}") + target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}") endif (PRIOVR_FOUND AND NOT DISABLE_PRIOVR) # and with SDL for joysticks if (SDL_FOUND AND NOT DISABLE_SDL) - add_definitions(-DHAVE_SDL) - include_directories(SYSTEM "${SDL_INCLUDE_DIR}") - target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}") + add_definitions(-DHAVE_SDL) + include_directories(SYSTEM "${SDL_INCLUDE_DIR}") + target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}") endif (SDL_FOUND AND NOT DISABLE_SDL) # and with qxmpp for chat if (QXMPP_FOUND AND NOT DISABLE_QXMPP) - add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC) - include_directories(SYSTEM ${QXMPP_INCLUDE_DIR}) + add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC) + include_directories(SYSTEM ${QXMPP_INCLUDE_DIR}) - target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}") + target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}") endif (QXMPP_FOUND AND NOT DISABLE_QXMPP) +# link CoreMIDI if we're using RtMidi +if (RTMIDI_FOUND AND APPLE) + find_library(CoreMIDI CoreMIDI) + add_definitions(-D__MACOSX_CORE__) + target_link_libraries(${TARGET_NAME} ${CoreMIDI}) +endif() + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt new file mode 100644 index 0000000000..d83d0c293e --- /dev/null +++ b/interface/external/rtmidi/readme.txt @@ -0,0 +1,41 @@ + +Instructions for adding the RtMidi library to Interface +Stephen Birarda, June 30, 2014 + +1. Download the RtMidi tarball from High Fidelity S3. + http://highfidelity-public.s3.amazonaws.com/dependencies/rtmidi-2.1.0.tar.gz + +2. Copy RtMidi.h to externals/rtmidi/include. + +3. Copy RtMidi.cpp to externals/rtmidi/src + +4. Delete your build directory, run cmake and build, and you should be all set. + +========================= + +RtMidi: realtime MIDI i/o C++ classes
+Copyright (c) 2003-2014 Gary P. Scavone + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +Any person wishing to distribute modifications to the Software is +asked to send the modifications to the original developer so that +they can be incorporated into the canonical version. This is, +however, not a binding provision of this license. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9bc08aa188..d0a8bb15dd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -69,6 +69,7 @@ #include "Menu.h" #include "ModelUploader.h" #include "Util.h" +#include "devices/MIDIManager.h" #include "devices/OculusManager.h" #include "devices/TV3DManager.h" #include "renderer/ProgramObject.h" @@ -393,6 +394,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig(); _trayIcon->show(); + + // setup the MIDIManager + MIDIManager& midiManagerInstance = MIDIManager::getInstance(); + midiManagerInstance.openDefaultPort(); } Application::~Application() { @@ -3600,6 +3605,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); QThread* workerThread = new QThread(this); diff --git a/interface/src/devices/MIDIManager.cpp b/interface/src/devices/MIDIManager.cpp new file mode 100644 index 0000000000..f88bcd1d3d --- /dev/null +++ b/interface/src/devices/MIDIManager.cpp @@ -0,0 +1,64 @@ +// +// MIDIManager.cpp +// +// +// Created by Stephen Birarda on 2014-06-30. +// 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 "MIDIManager.h" + +MIDIManager& MIDIManager::getInstance() { + static MIDIManager sharedInstance; + return sharedInstance; +} + +void MIDIManager::midiCallback(double deltaTime, std::vector* message, void* userData) { + + MIDIEvent callbackEvent; + callbackEvent.deltaTime = deltaTime; + + callbackEvent.type = message->at(0); + + if (message->size() > 1) { + callbackEvent.data1 = message->at(1); + } + + if (message->size() > 2) { + callbackEvent.data2 = message->at(2); + } + + emit getInstance().midiEvent(callbackEvent); +} + +MIDIManager::~MIDIManager() { + delete _midiInput; +} + +const int DEFAULT_MIDI_PORT = 0; + +void MIDIManager::openDefaultPort() { + if (!_midiInput) { + _midiInput = new RtMidiIn(); + + if (_midiInput->getPortCount() > 0) { + qDebug() << "MIDIManager opening port" << DEFAULT_MIDI_PORT; + + _midiInput->openPort(DEFAULT_MIDI_PORT); + + // don't ignore sysex, timing, or active sensing messages + _midiInput->ignoreTypes(false, false, false); + + _midiInput->setCallback(&MIDIManager::midiCallback); + } else { + qDebug() << "MIDIManager openDefaultPort called but there are no ports available."; + delete _midiInput; + _midiInput = NULL; + } + } +} \ No newline at end of file diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h new file mode 100644 index 0000000000..da41050216 --- /dev/null +++ b/interface/src/devices/MIDIManager.h @@ -0,0 +1,46 @@ +// +// MIDIManager.h +// interface/src/devices +// +// Created by Stephen Birarda on 2014-06-30. +// 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_MIDIManager_h +#define hifi_MIDIManager_h + +#include +#include + +#include + +#include + +class MIDIManager : public QObject { + Q_OBJECT + + Q_PROPERTY(unsigned int NoteOn READ NoteOn) + Q_PROPERTY(unsigned int NoteOff READ NoteOff) +public: + static MIDIManager& getInstance(); + static void midiCallback(double deltaTime, std::vector* message, void* userData); + + ~MIDIManager(); + + void openDefaultPort(); + bool hasDevice() const { return !!_midiInput; } +public slots: + unsigned int NoteOn() const { return 144; } + unsigned int NoteOff() const { return 128; } +signals: + void midiEvent(const MIDIEvent& event); + +private: + RtMidiIn* _midiInput; +}; + + +#endif // hifi_MIDIManager_h \ No newline at end of file diff --git a/libraries/script-engine/src/MIDIEvent.cpp b/libraries/script-engine/src/MIDIEvent.cpp new file mode 100644 index 0000000000..b32c5d9d87 --- /dev/null +++ b/libraries/script-engine/src/MIDIEvent.cpp @@ -0,0 +1,37 @@ +// +// MIDIEvent.cpp +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2014-06-30. +// 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 "MIDIEvent.h" + +void registerMIDIMetaTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, midiEventToScriptValue, midiEventFromScriptValue); +} + +const QString MIDI_DELTA_TIME_PROP_NAME = "deltaTime"; +const QString MIDI_EVENT_TYPE_PROP_NAME = "type"; +const QString MIDI_DATA_1_PROP_NAME = "data1"; +const QString MIDI_DATA_2_PROP_NAME = "data2"; + +QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event) { + QScriptValue obj = engine->newObject(); + obj.setProperty(MIDI_DELTA_TIME_PROP_NAME, event.deltaTime); + obj.setProperty(MIDI_EVENT_TYPE_PROP_NAME, event.type); + obj.setProperty(MIDI_DATA_1_PROP_NAME, event.data1); + obj.setProperty(MIDI_DATA_2_PROP_NAME, event.data2); + return obj; +} + +void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event) { + event.deltaTime = object.property(MIDI_DELTA_TIME_PROP_NAME).toVariant().toDouble(); + event.type = object.property(MIDI_EVENT_TYPE_PROP_NAME).toVariant().toUInt(); + event.data1 = object.property(MIDI_DATA_1_PROP_NAME).toVariant().toUInt(); + event.data2 = object.property(MIDI_DATA_2_PROP_NAME).toVariant().toUInt(); +} \ No newline at end of file diff --git a/libraries/script-engine/src/MIDIEvent.h b/libraries/script-engine/src/MIDIEvent.h new file mode 100644 index 0000000000..6bf4a4b72b --- /dev/null +++ b/libraries/script-engine/src/MIDIEvent.h @@ -0,0 +1,32 @@ +// +// MIDIEvent.h +// libraries/script-engine/src +// +// Created by Stephen Birarda on 2014-06-30. +// 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 + +#ifndef hifi_MIDIEvent_h +#define hifi_MIDIEvent_h + +class MIDIEvent { +public: + double deltaTime; + unsigned int type; + unsigned int data1; + unsigned int data2; +}; + +Q_DECLARE_METATYPE(MIDIEvent) + +void registerMIDIMetaTypes(QScriptEngine* engine); + +QScriptValue midiEventToScriptValue(QScriptEngine* engine, const MIDIEvent& event); +void midiEventFromScriptValue(const QScriptValue &object, MIDIEvent& event); + +#endif // hifi_MIDIEvent_h \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 350473cc87..630e585d07 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -33,6 +33,7 @@ #include "AnimationObject.h" #include "MenuItemProperties.h" +#include "MIDIEvent.h" #include "LocalVoxels.h" #include "ScriptEngine.h" #include "XMLHttpRequestClass.h" @@ -217,6 +218,7 @@ void ScriptEngine::init() { // register various meta-types registerMetaTypes(&_engine); + registerMIDIMetaTypes(&_engine); registerVoxelMetaTypes(&_engine); registerEventTypes(&_engine); registerMenuItemProperties(&_engine); From bc1660cdeb20e4114445b5dfe28ff9d6f0f4aa4a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 1 Jul 2014 09:57:23 -0700 Subject: [PATCH 14/80] Configure multi-processor building on Windows --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7fa55d4a2..2451ab240a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ add_definitions(-DGLM_FORCE_RADIANS) if (WIN32) add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1 ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic") #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas") From de463642c01406a84e4298a0631d0744cdfec9f2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Jul 2014 11:00:17 -0700 Subject: [PATCH 15/80] add the ModWheel property to the MIDIManager --- interface/src/devices/MIDIManager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h index da41050216..a3633298a5 100644 --- a/interface/src/devices/MIDIManager.h +++ b/interface/src/devices/MIDIManager.h @@ -24,6 +24,7 @@ class MIDIManager : public QObject { Q_PROPERTY(unsigned int NoteOn READ NoteOn) Q_PROPERTY(unsigned int NoteOff READ NoteOff) + Q_PROPERTY(unsigned int ModWheel READ ModWheel) public: static MIDIManager& getInstance(); static void midiCallback(double deltaTime, std::vector* message, void* userData); @@ -35,6 +36,7 @@ public: public slots: unsigned int NoteOn() const { return 144; } unsigned int NoteOff() const { return 128; } + unsigned int ModWheel() const { return 176; } signals: void midiEvent(const MIDIEvent& event); From fd051310daa4006acb98412971a49def62f38a72 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 1 Jul 2014 12:01:51 -0700 Subject: [PATCH 16/80] prune missing set before constructing nack packets; make MAX_REASONALBE_SEQUENCE_GAP global and sentPacketHistory to use that value as the default history size --- .../src/octree/OctreeInboundPacketProcessor.cpp | 6 +++++- .../src/octree/OctreeInboundPacketProcessor.h | 1 + assignment-client/src/octree/OctreeQueryNode.cpp | 2 +- interface/src/Application.cpp | 8 ++++---- libraries/networking/src/SentPacketHistory.h | 4 +++- libraries/networking/src/SequenceNumberStats.cpp | 1 - libraries/networking/src/SequenceNumberStats.h | 6 +++--- libraries/octree/src/OctreeSceneStats.h | 1 + 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 3d2ca6ddc3..7716f9e2aa 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -216,9 +216,13 @@ int OctreeInboundPacketProcessor::sendNackPackets() { } const SharedNodePointer& destinationNode = NodeList::getInstance()->getNodeHash().value(nodeUUID); - const QSet& missingSequenceNumbers = nodeStats.getIncomingEditSequenceNumberStats().getMissingSet(); + + // retrieve sequence number stats of node, prune its missing set + SequenceNumberStats& sequenceNumberStats = nodeStats.getIncomingEditSequenceNumberStats(); + sequenceNumberStats.pruneMissingSet(); // construct nack packet(s) for this node + const QSet& missingSequenceNumbers = sequenceNumberStats.getMissingSet(); int numSequenceNumbersAvailable = missingSequenceNumbers.size(); QSet::const_iterator missingSequenceNumberIterator = missingSequenceNumbers.constBegin(); while (numSequenceNumbersAvailable > 0) { diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 960282384b..2fb83123c4 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -35,6 +35,7 @@ public: { return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; } const SequenceNumberStats& getIncomingEditSequenceNumberStats() const { return _incomingEditSequenceNumberStats; } + SequenceNumberStats& getIncomingEditSequenceNumberStats() { return _incomingEditSequenceNumberStats; } void trackInboundPacket(unsigned short int incomingSequence, quint64 transitTime, int editsInPacket, quint64 processTime, quint64 lockWaitTime); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 3531c3f9cb..11783fe7d2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -42,7 +42,7 @@ OctreeQueryNode::OctreeQueryNode() : _lastRootTimestamp(0), _myPacketType(PacketTypeUnknown), _isShuttingDown(false), - _sentPacketHistory(1000) + _sentPacketHistory() { } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 72ac7ba62a..c17c669149 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2179,11 +2179,11 @@ int Application::sendNackPackets() { _octreeSceneStatsLock.unlock(); continue; } - OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - // make copy of missing sequence numbers from stats - const QSet missingSequenceNumbers = - stats.getIncomingOctreeSequenceNumberStats().getMissingSet(); + // get sequence number stats of node, prune its missing set, and make a copy of the missing set + SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats(); + sequenceNumberStats.pruneMissingSet(); + const QSet missingSequenceNumbers = sequenceNumberStats.getMissingSet(); _octreeSceneStatsLock.unlock(); diff --git a/libraries/networking/src/SentPacketHistory.h b/libraries/networking/src/SentPacketHistory.h index 53a6919c42..325f973f7e 100644 --- a/libraries/networking/src/SentPacketHistory.h +++ b/libraries/networking/src/SentPacketHistory.h @@ -15,10 +15,12 @@ #include #include +#include "SequenceNumberStats.h" + class SentPacketHistory { public: - SentPacketHistory(int size = 1000); + SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP); void packetSent(uint16_t sequenceNumber, const QByteArray& packet); const QByteArray* getPacket(uint16_t sequenceNumber) const; diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 15d3c0542e..5bdeedf39d 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -39,7 +39,6 @@ void SequenceNumberStats::reset() { } static const int UINT16_RANGE = std::numeric_limits::max() + 1; -static const int MAX_REASONABLE_SEQUENCE_GAP = 1000; // this must be less than UINT16_RANGE / 2 for rollover handling to work void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) { diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index b2561552ef..88c8748b03 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -15,13 +15,15 @@ #include "SharedUtil.h" #include +const int MAX_REASONABLE_SEQUENCE_GAP = 1000; + class SequenceNumberStats { public: SequenceNumberStats(); void reset(); - void sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); + void pruneMissingSet(const bool wantExtraDebugging = false); quint32 getNumReceived() const { return _numReceived; } quint32 getNumUnreasonable() const { return _numUnreasonable; } @@ -34,8 +36,6 @@ public: const QSet& getMissingSet() const { return _missingSet; } private: - void pruneMissingSet(const bool wantExtraDebugging); - quint16 _lastReceived; QSet _missingSet; diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index d7b65c63be..cefaaa5764 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -168,6 +168,7 @@ public: float getIncomingFlightTimeAverage() { return _incomingFlightTimeAverage.getAverage(); } const SequenceNumberStats& getIncomingOctreeSequenceNumberStats() const { return _incomingOctreeSequenceNumberStats; } + SequenceNumberStats& getIncomingOctreeSequenceNumberStats() { return _incomingOctreeSequenceNumberStats; } private: From 1a1050cb06b360e1f201027dc60a5d199762b79c Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 12:31:48 -0700 Subject: [PATCH 17/80] Added back _raiseMirror usage for mirror mode. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7fb3ded0d8..f21fedabea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -592,7 +592,7 @@ void Application::paintGL() { _myCamera.setTightness(0.0f); _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); + _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); } // Update camera position From af30dc27223dd9e0a240890c95e1d65f822834be Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 12:33:54 -0700 Subject: [PATCH 18/80] Updated oculus readme.txt for windows users --- interface/external/oculus/readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/external/oculus/readme.txt b/interface/external/oculus/readme.txt index f689f81478..f68818d1ee 100644 --- a/interface/external/oculus/readme.txt +++ b/interface/external/oculus/readme.txt @@ -10,4 +10,7 @@ You can download the Oculus SDK from https://developer.oculusvr.com/ (account cr You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'oculus' that contains the three folders mentioned above. -2. Clear your build directory, run cmake and build, and you should be all set. \ No newline at end of file + NOTE: For Windows users, you should copy libovr.lib and libovrd.lib from the \oculus\Lib\Win32\VS2010 directory to the \oculus\Lib\Win32\ directory. + +2. Clear your build directory, run cmake and build, and you should be all set. + From 3730be980413c9813f5fd6b7f84da577f8bce668 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 1 Jul 2014 14:03:26 -0700 Subject: [PATCH 19/80] nacked edit packets are not resent if NACKs are disabled in menu --- interface/src/DatagramProcessor.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index a159af7be5..6c39994bf3 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -149,13 +149,19 @@ void DatagramProcessor::processDatagrams() { break; } case PacketTypeVoxelEditNack: - application->_voxelEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_voxelEditSender.processNackPacket(incomingPacket); + } break; case PacketTypeParticleEditNack: - application->_particleEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_particleEditSender.processNackPacket(incomingPacket); + } break; case PacketTypeModelEditNack: - application->_modelEditSender.processNackPacket(incomingPacket); + if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { + application->_modelEditSender.processNackPacket(incomingPacket); + } break; default: nodeList->processNodeData(senderSockAddr, incomingPacket); From 9953fd6d2bdcbd31f9722a14ced4296717b221d7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 15:29:13 -0700 Subject: [PATCH 20/80] Update MyLocations to not send rename request if unchanged --- interface/src/UserLocationsModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 539f9197a4..000ab34703 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -31,7 +31,7 @@ UserLocation::UserLocation(QString id, QString name, QString location) : } void UserLocation::requestRename(const QString& newName) { - if (!_updating) { + if (!_updating && newName.toLower() != _name) { _updating = true; JSONCallbackParameters callbackParams; From e7e7bef5064ae18442b2b29c0d469a391c03a891 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 15:37:10 -0700 Subject: [PATCH 21/80] Add error string on rename failure --- interface/src/UserLocationsModel.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 000ab34703..824c1269bd 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -63,7 +63,16 @@ void UserLocation::handleRenameResponse(const QJsonObject& responseData) { _name = updatedName; } else { _name = _previousName; + QString msg = "There was an error renaming location '" + _name + "'"; + + QJsonValue data = responseData["data"]; + if (!data.isUndefined()) { + QJsonValue nameError = data.toObject()["name"]; + if (!nameError.isUndefined()) { + msg += ": " + nameError.toString(); + } + } qDebug() << msg; QMessageBox::warning(Application::getInstance()->getWindow(), "Error", msg); } From a5943e3608d039059c1ad8a298e0b5b518f6f252 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 1 Jul 2014 16:24:31 -0700 Subject: [PATCH 22/80] made AudioRingBuffer frames capacity variable --- assignment-client/src/Agent.cpp | 4 +++- .../src/audio/AudioMixerClientData.cpp | 6 ++++-- .../src/audio/AvatarAudioRingBuffer.cpp | 4 ++-- assignment-client/src/audio/AvatarAudioRingBuffer.h | 2 +- interface/src/Audio.cpp | 6 ++++-- libraries/audio/src/AudioRingBuffer.cpp | 13 ++++++++----- libraries/audio/src/AudioRingBuffer.h | 5 ++--- libraries/audio/src/InjectedAudioRingBuffer.cpp | 4 ++-- libraries/audio/src/InjectedAudioRingBuffer.h | 2 +- libraries/audio/src/MixedAudioRingBuffer.cpp | 4 ++-- libraries/audio/src/MixedAudioRingBuffer.h | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 7 ++++--- libraries/audio/src/PositionalAudioRingBuffer.h | 3 ++- tests/audio/src/AudioRingBufferTests.cpp | 2 +- 14 files changed, 37 insertions(+), 27 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5720ecaaf5..25c775f14b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -31,12 +31,14 @@ #include "Agent.h" +static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 10; + Agent::Agent(const QByteArray& packet) : ThreadedAssignment(packet), _voxelEditSender(), _particleEditSender(), _modelEditSender(), - _receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), + _receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, AUDIO_RING_BUFFER_CAPACITY_FRAMES), _avatarHashMap() { // be the parent of the script engine so it gets moved when we do diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9b14ecfd19..b8f4d18b1d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -19,6 +19,8 @@ #include "AudioMixer.h" #include "AudioMixerClientData.h" +static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 100; + AudioMixerClientData::AudioMixerClientData() : _ringBuffers(), _outgoingMixedAudioSequenceNumber(0), @@ -76,7 +78,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { if (!avatarRingBuffer) { // we don't have an AvatarAudioRingBuffer yet, so add it - avatarRingBuffer = new AvatarAudioRingBuffer(isStereo, AudioMixer::getUseDynamicJitterBuffers()); + avatarRingBuffer = new AvatarAudioRingBuffer(AUDIO_RING_BUFFER_CAPACITY_FRAMES, isStereo, AudioMixer::getUseDynamicJitterBuffers()); _ringBuffers.push_back(avatarRingBuffer); } @@ -101,7 +103,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { if (!matchingInjectedRingBuffer) { // we don't have a matching injected audio ring buffer, so add it - matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, + matchingInjectedRingBuffer = new InjectedAudioRingBuffer(AUDIO_RING_BUFFER_CAPACITY_FRAMES, streamIdentifier, AudioMixer::getUseDynamicJitterBuffers()); _ringBuffers.push_back(matchingInjectedRingBuffer); } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index 9c6cc32f57..ec08471e26 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -13,8 +13,8 @@ #include "AvatarAudioRingBuffer.h" -AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone, isStereo, dynamicJitterBuffer) { +AvatarAudioRingBuffer::AvatarAudioRingBuffer(int numFramesCapacity, bool isStereo, bool dynamicJitterBuffer) : + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone, numFramesCapacity, isStereo, dynamicJitterBuffer) { } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index e227e70958..816fd937a6 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -18,7 +18,7 @@ class AvatarAudioRingBuffer : public PositionalAudioRingBuffer { public: - AvatarAudioRingBuffer(bool isStereo = false, bool dynamicJitterBuffer = false); + AvatarAudioRingBuffer(int numFramesCapacity, bool isStereo = false, bool dynamicJitterBuffer = false); int parseData(const QByteArray& packet); private: diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index f5f148969c..1ae3b5b8e6 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -48,6 +48,8 @@ static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_ static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; +static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 10; + // Mute icon configration static const int MUTE_ICON_SIZE = 24; @@ -66,8 +68,8 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _loopbackOutputDevice(NULL), _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), - _inputRingBuffer(0), - _ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL), + _inputRingBuffer(0, AUDIO_RING_BUFFER_CAPACITY_FRAMES), + _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, AUDIO_RING_BUFFER_CAPACITY_FRAMES), _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 6ae3b19541..56b6725745 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -19,10 +19,11 @@ #include "AudioRingBuffer.h" -AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode) : +AudioRingBuffer::AudioRingBuffer(int numFrameSamples, int numFramesCapacity, bool randomAccessMode) : NodeData(), _overflowCount(0), - _sampleCapacity(numFrameSamples * RING_BUFFER_LENGTH_FRAMES), + _frameCapacity(numFramesCapacity), + _sampleCapacity(numFrameSamples * numFramesCapacity), _isFull(false), _numFrameSamples(numFrameSamples), _isStarved(true), @@ -48,6 +49,8 @@ AudioRingBuffer::~AudioRingBuffer() { } void AudioRingBuffer::reset() { + _overflowCount = 0; + _isFull = false; _endOfLastWrite = _buffer; _nextOutput = _buffer; _isStarved = true; @@ -55,13 +58,13 @@ void AudioRingBuffer::reset() { void AudioRingBuffer::resizeForFrameSize(qint64 numFrameSamples) { delete[] _buffer; - _sampleCapacity = numFrameSamples * RING_BUFFER_LENGTH_FRAMES; + _sampleCapacity = numFrameSamples * _frameCapacity; + _numFrameSamples = numFrameSamples; _buffer = new int16_t[_sampleCapacity]; if (_randomAccessMode) { memset(_buffer, 0, _sampleCapacity * sizeof(int16_t)); } - _nextOutput = _buffer; - _endOfLastWrite = _buffer; + reset(); } int AudioRingBuffer::parseData(const QByteArray& packet) { diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 8d19f9c0bb..0bf5e2d1d6 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -31,15 +31,13 @@ const int NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL = NETWORK_BUFFER_LENGTH_BYTE const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE) * 1000 * 1000); -const short RING_BUFFER_LENGTH_FRAMES = 10; - const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); class AudioRingBuffer : public NodeData { Q_OBJECT public: - AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false); + AudioRingBuffer(int numFrameSamples, int numFramesCapacity, bool randomAccessMode = false); ~AudioRingBuffer(); void reset(); @@ -84,6 +82,7 @@ protected: int _overflowCount; /// how many times has the ring buffer has overwritten old data + int _frameCapacity; int _sampleCapacity; bool _isFull; int _numFrameSamples; diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 0d7cea356b..aab86c1e26 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -19,8 +19,8 @@ #include "InjectedAudioRingBuffer.h" -InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, /* isStereo=*/ false , dynamicJitterBuffer), +InjectedAudioRingBuffer::InjectedAudioRingBuffer(int numFramesCapacity, const QUuid& streamIdentifier, bool dynamicJitterBuffer) : + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, numFramesCapacity, false, dynamicJitterBuffer), _streamIdentifier(streamIdentifier), _radius(0.0f), _attenuationRatio(0) diff --git a/libraries/audio/src/InjectedAudioRingBuffer.h b/libraries/audio/src/InjectedAudioRingBuffer.h index 4e3fea672b..64862b6963 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.h +++ b/libraries/audio/src/InjectedAudioRingBuffer.h @@ -18,7 +18,7 @@ class InjectedAudioRingBuffer : public PositionalAudioRingBuffer { public: - InjectedAudioRingBuffer(const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false); + InjectedAudioRingBuffer(int numFramesCapacity, const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false); int parseData(const QByteArray& packet); diff --git a/libraries/audio/src/MixedAudioRingBuffer.cpp b/libraries/audio/src/MixedAudioRingBuffer.cpp index c975d7b68e..fb414ee387 100644 --- a/libraries/audio/src/MixedAudioRingBuffer.cpp +++ b/libraries/audio/src/MixedAudioRingBuffer.cpp @@ -11,8 +11,8 @@ #include "MixedAudioRingBuffer.h" -MixedAudioRingBuffer::MixedAudioRingBuffer(int numFrameSamples) : - AudioRingBuffer(numFrameSamples), +MixedAudioRingBuffer::MixedAudioRingBuffer(int numFrameSamples, int numFramesCapacity) : + AudioRingBuffer(numFrameSamples, numFramesCapacity), _lastReadFrameAverageLoudness(0.0f) { diff --git a/libraries/audio/src/MixedAudioRingBuffer.h b/libraries/audio/src/MixedAudioRingBuffer.h index 25574a3ea6..4ebe4d577e 100644 --- a/libraries/audio/src/MixedAudioRingBuffer.h +++ b/libraries/audio/src/MixedAudioRingBuffer.h @@ -17,7 +17,7 @@ class MixedAudioRingBuffer : public AudioRingBuffer { Q_OBJECT public: - MixedAudioRingBuffer(int numFrameSamples); + MixedAudioRingBuffer(int numFrameSamples, int numFramesCapacity); float getLastReadFrameAverageLoudness() const { return _lastReadFrameAverageLoudness; } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 546ed97fe2..edb76cce69 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -85,10 +85,11 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() { } -PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, +PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, int numFramesCapacity, bool isStereo, bool dynamicJitterBuffers) : - AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL), + AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, + numFramesCapacity), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), @@ -261,7 +262,7 @@ void PositionalAudioRingBuffer::updateDesiredJitterBufferFrames() { if (_desiredJitterBufferFrames < 1) { _desiredJitterBufferFrames = 1; } - const int maxDesired = RING_BUFFER_LENGTH_FRAMES - 1; + const int maxDesired = _frameCapacity - 1; if (_desiredJitterBufferFrames > maxDesired) { _desiredJitterBufferFrames = maxDesired; } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index b204dc766b..53f4d942fc 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -50,7 +50,8 @@ public: Injector }; - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false, bool dynamicJitterBuffers = false); + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, int numFramesCapacity, + bool isStereo = false, bool dynamicJitterBuffers = false); int parseData(const QByteArray& packet); int parsePositionalData(const QByteArray& positionalByteArray); diff --git a/tests/audio/src/AudioRingBufferTests.cpp b/tests/audio/src/AudioRingBufferTests.cpp index 506e81e13e..1c312d8323 100644 --- a/tests/audio/src/AudioRingBufferTests.cpp +++ b/tests/audio/src/AudioRingBufferTests.cpp @@ -29,7 +29,7 @@ void AudioRingBufferTests::runAllTests() { int readIndexAt; - AudioRingBuffer ringBuffer(10); // makes buffer of 100 int16_t samples + AudioRingBuffer ringBuffer(10, 10); // makes buffer of 100 int16_t samples for (int T = 0; T < 300; T++) { writeIndexAt = 0; From 29976d7861f041322f11ccdf29b92bab26470c30 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:17:34 -0700 Subject: [PATCH 23/80] Created base for wrapper singleton class NetworkAccessManager --- .../networking/src/NetworkAccessManager.cpp | 20 ++++++++++++++ .../networking/src/NetworkAccessManager.h | 27 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 libraries/networking/src/NetworkAccessManager.cpp create mode 100644 libraries/networking/src/NetworkAccessManager.h diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp new file mode 100644 index 0000000000..a33817b50d --- /dev/null +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -0,0 +1,20 @@ +// +// NetworkAccessManager.cpp +// +// +// Created by Clement on 7/1/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 "NetworkAccessManager.h" + +NetworkAccessManager& NetworkAccessManager::getInstance() { + static NetworkAccessManager sharedInstance; + return sharedInstance; +} + +NetworkAccessManager::NetworkAccessManager() { +} \ No newline at end of file diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h new file mode 100644 index 0000000000..c7cc74340a --- /dev/null +++ b/libraries/networking/src/NetworkAccessManager.h @@ -0,0 +1,27 @@ +// +// NetworkAccessManager.h +// +// +// Created by Clement on 7/1/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_NetworkAccessManager_h +#define hifi_NetworkAccessManager_h + +#include + +class NetworkAccessManager : public QNetworkAccessManager { + Q_OBJECT +public: + static NetworkAccessManager& getInstance(); + + +private: + NetworkAccessManager(); +}; + +#endif // hifi_NetworkAccessManager_h \ No newline at end of file From ab503583dd8497be6baadf26822fc1c382e716f9 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 1 Jul 2014 17:33:38 -0700 Subject: [PATCH 24/80] switched order of args in PositionalAudioRingBuffer --- assignment-client/src/audio/AvatarAudioRingBuffer.cpp | 2 +- libraries/audio/src/InjectedAudioRingBuffer.cpp | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 2 +- libraries/audio/src/PositionalAudioRingBuffer.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index ec08471e26..a3e15c7f9e 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -14,7 +14,7 @@ #include "AvatarAudioRingBuffer.h" AvatarAudioRingBuffer::AvatarAudioRingBuffer(int numFramesCapacity, bool isStereo, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone, numFramesCapacity, isStereo, dynamicJitterBuffer) { + PositionalAudioRingBuffer(numFramesCapacity, PositionalAudioRingBuffer::Microphone, isStereo, dynamicJitterBuffer) { } diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index aab86c1e26..77688506dd 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -20,7 +20,7 @@ #include "InjectedAudioRingBuffer.h" InjectedAudioRingBuffer::InjectedAudioRingBuffer(int numFramesCapacity, const QUuid& streamIdentifier, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, numFramesCapacity, false, dynamicJitterBuffer), + PositionalAudioRingBuffer(numFramesCapacity, PositionalAudioRingBuffer::Injector, false, dynamicJitterBuffer), _streamIdentifier(streamIdentifier), _radius(0.0f), _attenuationRatio(0) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index edb76cce69..e1e85721f0 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -85,7 +85,7 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() { } -PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, int numFramesCapacity, +PositionalAudioRingBuffer::PositionalAudioRingBuffer(int numFramesCapacity, PositionalAudioRingBuffer::Type type, bool isStereo, bool dynamicJitterBuffers) : AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 53f4d942fc..ac56d8487c 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -50,7 +50,7 @@ public: Injector }; - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, int numFramesCapacity, + PositionalAudioRingBuffer(int numFramesCapacity, PositionalAudioRingBuffer::Type type, bool isStereo = false, bool dynamicJitterBuffers = false); int parseData(const QByteArray& packet); From 231557a12c2c9a61ff6f94633811a2119b6f72e8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:35:34 -0700 Subject: [PATCH 25/80] Switched Agent to NetworkAccessManager --- assignment-client/src/Agent.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5720ecaaf5..1805a414b5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -13,13 +13,13 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -208,12 +208,12 @@ void Agent::run() { scriptURL = QUrl(_payload); } - QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); - QNetworkReply *reply = networkManager->get(QNetworkRequest(scriptURL)); - QNetworkDiskCache* cache = new QNetworkDiskCache(networkManager); + NetworkAccessManager& networkManager = NetworkAccessManager::getInstance(); + QNetworkReply *reply = networkManager.get(QNetworkRequest(scriptURL)); + QNetworkDiskCache* cache = new QNetworkDiskCache(&networkManager); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache"); - networkManager->setCache(cache); + networkManager.setCache(cache); qDebug() << "Downloading script at" << scriptURL.toString(); @@ -222,10 +222,6 @@ void Agent::run() { loop.exec(); - // let the AvatarData and ResourceCache classes use our QNetworkAccessManager - AvatarData::setNetworkAccessManager(networkManager); - ResourceCache::setNetworkAccessManager(networkManager); - QString scriptContents(reply->readAll()); qDebug() << "Downloaded script:" << scriptContents; From d6a2cea756ce33e22d35e9faca3028ccc03f0bfe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:39:45 -0700 Subject: [PATCH 26/80] Switched AudioMixer to NetworkAccessManager --- assignment-client/src/audio/AudioMixer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 663aef81a7..1c3046b9b1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -38,11 +38,11 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -482,8 +482,8 @@ void AudioMixer::run() { nodeList->linkedDataCreateCallback = attachNewBufferToNode; - // setup a QNetworkAccessManager to ask the domain-server for our settings - QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + // setup a NetworkAccessManager to ask the domain-server for our settings + NetworkAccessManager& networkManager = NetworkAccessManager::getInstance(); QUrl settingsJSONURL; settingsJSONURL.setScheme("http"); @@ -500,7 +500,7 @@ void AudioMixer::run() { qDebug() << "Requesting settings for assignment from domain-server at" << settingsJSONURL.toString(); while (!reply || reply->error() != QNetworkReply::NoError) { - reply = networkManager->get(QNetworkRequest(settingsJSONURL)); + reply = networkManager.get(QNetworkRequest(settingsJSONURL)); QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); From c5a997a56721cebc3428cb930a805fde253c9493 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:43:25 -0700 Subject: [PATCH 27/80] Switched Application to NetworkAccessManager --- interface/src/Application.cpp | 18 ++++++++---------- interface/src/Application.h | 3 --- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f8fbbae56..10b6fc8165 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -53,17 +52,18 @@ #include #include +#include #include #include +#include #include +#include #include #include #include #include #include #include -#include -#include #include "Application.h" #include "InterfaceVersion.h" @@ -314,12 +314,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - _networkAccessManager = new QNetworkAccessManager(this); - QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); - _networkAccessManager->setCache(cache); + networkAccessManager.setCache(cache); - ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); _window->setCentralWidget(_glWidget); @@ -441,8 +440,6 @@ Application::~Application() { _myAvatar = NULL; delete _glWidget; - - AccountManager::getInstance().destroy(); } void Application::saveSettings() { @@ -3802,7 +3799,8 @@ void Application::initAvatarAndViewFrustum() { void Application::checkVersion() { QNetworkRequest latestVersionRequest((QUrl(CHECK_VERSION_URL))); latestVersionRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - connect(Application::getInstance()->getNetworkAccessManager()->get(latestVersionRequest), SIGNAL(finished()), SLOT(parseVersionXml())); + QNetworkReply* reply = NetworkAccessManager::getInstance().get(latestVersionRequest); + connect(reply, SIGNAL(finished()), SLOT(parseVersionXml())); } void Application::parseVersionXml() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 56b6f673ae..11f406abf0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -97,7 +97,6 @@ class QActionGroup; class QGLWidget; class QKeyEvent; class QMouseEvent; -class QNetworkAccessManager; class QSettings; class QWheelEvent; @@ -236,7 +235,6 @@ public: void lockOctreeSceneStats() { _octreeSceneStatsLock.lockForRead(); } void unlockOctreeSceneStats() { _octreeSceneStatsLock.unlock(); } - QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } AnimationCache* getAnimationCache() { return &_animationCache; } TextureCache* getTextureCache() { return &_textureCache; } @@ -423,7 +421,6 @@ private: QThread* _nodeThread; DatagramProcessor _datagramProcessor; - QNetworkAccessManager* _networkAccessManager; QMutex _settingsMutex; QSettings* _settings; int _numChangedSettings; From ab15a1487e58ba90723cc9b2b11d6dc8c289d0bc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:44:38 -0700 Subject: [PATCH 28/80] Switched BillboardOverlay to NetworkAccessManaqer --- interface/src/ui/overlays/BillboardOverlay.cpp | 16 +++++----------- interface/src/ui/overlays/BillboardOverlay.h | 3 +-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 40de565155..8742f19c3d 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -14,8 +14,7 @@ #include "BillboardOverlay.h" BillboardOverlay::BillboardOverlay() -: _manager(NULL), - _scale(1.0f), +: _scale(1.0f), _isFacingAvatar(true) { } @@ -119,18 +118,13 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) { } } -// TODO: handle setting image multiple times, how do we manage releasing the bound texture? void BillboardOverlay::setBillboardURL(const QUrl url) { - // TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made? - _manager->deleteLater(); - _manager = new QNetworkAccessManager(); - connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); - _manager->get(QNetworkRequest(url)); + QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(url)); + connect(reply, &QNetworkReply::finished, this, &BillboardOverlay::replyFinished); } -void BillboardOverlay::replyFinished(QNetworkReply* reply) { +void BillboardOverlay::replyFinished() { // replace our byte array with the downloaded data + QNetworkReply* reply = static_cast(sender()); _billboard = reply->readAll(); - _manager->deleteLater(); - _manager = NULL; } diff --git a/interface/src/ui/overlays/BillboardOverlay.h b/interface/src/ui/overlays/BillboardOverlay.h index 473e8a066f..0037d1a4f7 100644 --- a/interface/src/ui/overlays/BillboardOverlay.h +++ b/interface/src/ui/overlays/BillboardOverlay.h @@ -27,12 +27,11 @@ public: virtual void setProperties(const QScriptValue& properties); private slots: - void replyFinished(QNetworkReply* reply); + void replyFinished(); private: void setBillboardURL(const QUrl url); - QNetworkAccessManager* _manager; QUrl _url; QByteArray _billboard; QSize _size; From 30644c750d350e860f23292cc57a728064b47145 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:46:23 -0700 Subject: [PATCH 29/80] Switched AvatarData to NetworkAccessManager --- libraries/avatars/src/AvatarData.cpp | 30 ++++++++++++---------------- libraries/avatars/src/AvatarData.h | 5 ----- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 94066d9a1c..3f3e71c5e8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -16,10 +16,10 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -33,8 +33,6 @@ quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND; using namespace std; -QNetworkAccessManager* AvatarData::networkAccessManager = NULL; - AvatarData::AvatarData() : _sessionUUID(), _handPosition(0,0,0), @@ -751,18 +749,15 @@ void AvatarData::setBillboard(const QByteArray& billboard) { void AvatarData::setBillboardFromURL(const QString &billboardURL) { _billboardURL = billboardURL; - if (AvatarData::networkAccessManager) { - qDebug() << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL); - - QNetworkRequest billboardRequest; - billboardRequest.setUrl(QUrl(billboardURL)); - - QNetworkReply* networkReply = AvatarData::networkAccessManager->get(billboardRequest); - connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); - - } else { - qDebug() << "Billboard PNG download requested but no network access manager is available."; - } + + qDebug() << "Changing billboard for avatar to PNG at" << qPrintable(billboardURL); + + QNetworkRequest billboardRequest; + billboardRequest.setUrl(QUrl(billboardURL)); + + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* networkReply = networkAccessManager.get(billboardRequest); + connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); } void AvatarData::setBillboardFromNetworkReply() { @@ -839,8 +834,9 @@ void AvatarData::updateJointMappings() { _jointIndices.clear(); _jointNames.clear(); - if (networkAccessManager && _skeletonModelURL.fileName().toLower().endsWith(".fst")) { - QNetworkReply* networkReply = networkAccessManager->get(QNetworkRequest(_skeletonModelURL)); + if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL)); connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 4c7136fd0a..1b8f6e6007 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -102,7 +102,6 @@ enum KeyState { const glm::vec3 vec3Zero(0.0f); class QDataStream; -class QNetworkAccessManager; class AttachmentData; class JointData; @@ -269,8 +268,6 @@ public: QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; } virtual float getBoundingRadius() const { return 1.f; } - - static void setNetworkAccessManager(QNetworkAccessManager* sharedAccessManager) { networkAccessManager = sharedAccessManager; } public slots: void sendIdentityPacket(); @@ -323,8 +320,6 @@ protected: QHash _jointIndices; ///< 1-based, since zero is returned for missing keys QStringList _jointNames; ///< in order of depth-first traversal - - static QNetworkAccessManager* networkAccessManager; quint64 _errorLogExpiry; ///< time in future when to log an error From 7c3292a41b480fd7ded2cb4943bc8e897c1e6f86 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Jul 2014 17:47:31 -0700 Subject: [PATCH 30/80] Switched AccountManager to NetworkAccessManager --- libraries/networking/src/AccountManager.cpp | 27 ++++++++------------- libraries/networking/src/AccountManager.h | 6 ++--- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 918261a953..82487ae1c0 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -49,7 +49,6 @@ JSONCallbackParameters::JSONCallbackParameters() : AccountManager::AccountManager() : _authURL(), - _networkAccessManager(NULL), _pendingCallbackMap(), _accountInfo() { @@ -153,9 +152,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { - if (!_networkAccessManager) { - _networkAccessManager = new QNetworkAccessManager(this); - } + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); if (hasValidAccessToken()) { QNetworkRequest authenticatedRequest; @@ -184,23 +181,23 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: switch (operation) { case QNetworkAccessManager::GetOperation: - networkReply = _networkAccessManager->get(authenticatedRequest); + networkReply = networkAccessManager.get(authenticatedRequest); break; case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::PutOperation: if (dataMultiPart) { if (operation == QNetworkAccessManager::PostOperation) { - networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); + networkReply = networkAccessManager.post(authenticatedRequest, dataMultiPart); } else { - networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); + networkReply = networkAccessManager.put(authenticatedRequest, dataMultiPart); } dataMultiPart->setParent(networkReply); } else { authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); if (operation == QNetworkAccessManager::PostOperation) { - networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + networkReply = networkAccessManager.post(authenticatedRequest, dataByteArray); } else { - networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + networkReply = networkAccessManager.put(authenticatedRequest, dataByteArray); } } @@ -304,9 +301,7 @@ bool AccountManager::checkAndSignalForAccessToken() { void AccountManager::requestAccessToken(const QString& login, const QString& password) { - if (!_networkAccessManager) { - _networkAccessManager = new QNetworkAccessManager(this); - } + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request; @@ -324,7 +319,7 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas request.setUrl(grantURL); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - QNetworkReply* requestReply = _networkAccessManager->post(request, postData); + QNetworkReply* requestReply = networkAccessManager.post(request, postData); connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestAccessTokenFinished); connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestAccessTokenError(QNetworkReply::NetworkError))); } @@ -376,15 +371,13 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) } void AccountManager::requestProfile() { - if (!_networkAccessManager) { - _networkAccessManager = new QNetworkAccessManager(this); - } + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QUrl profileURL = _authURL; profileURL.setPath("/api/v1/users/profile"); profileURL.setQuery("access_token=" + _accountInfo.getAccessToken().token); - QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL)); + QNetworkReply* profileReply = networkAccessManager.get(QNetworkRequest(profileURL)); connect(profileReply, &QNetworkReply::finished, this, &AccountManager::requestProfileFinished); connect(profileReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestProfileError(QNetworkReply::NetworkError))); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index c18836ca54..9ac67ee664 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -15,9 +15,10 @@ #include #include #include -#include #include +#include "NetworkAccessManager.h" + #include "DataServerAccountInfo.h" class JSONCallbackParameters { @@ -58,8 +59,6 @@ public: const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; } - void destroy() { delete _networkAccessManager; } - public slots: void requestAccessTokenFinished(); void requestProfileFinished(); @@ -93,7 +92,6 @@ private: QHttpMultiPart* dataMultiPart); QUrl _authURL; - QNetworkAccessManager* _networkAccessManager; QMap _pendingCallbackMap; DataServerAccountInfo _accountInfo; From a9e352981a94de1a0949d1ecc1fa87bc1273b3f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 17:59:49 -0700 Subject: [PATCH 31/80] Fix cleanup of resources for UserLocations* --- interface/src/Menu.cpp | 2 +- interface/src/UserLocationsModel.cpp | 6 ++++++ interface/src/UserLocationsModel.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ae3cc1b77c..c3417144ee 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1187,7 +1187,7 @@ void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse res void Menu::toggleLocationList() { if (!_userLocationsWindow) { - _userLocationsWindow = new UserLocationsWindow(); + _userLocationsWindow = new UserLocationsWindow(Application::getInstance()->getWindow()); } if (_userLocationsWindow->isVisible()) { _userLocationsWindow->hide(); diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 824c1269bd..90d6927e1e 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -133,6 +133,11 @@ UserLocationsModel::UserLocationsModel(QObject* parent) : refresh(); } +UserLocationsModel::~UserLocationsModel() { + qDeleteAll(_locations); + _locations.clear(); +} + void UserLocationsModel::update() { beginResetModel(); endResetModel(); @@ -151,6 +156,7 @@ void UserLocationsModel::renameLocation(const QModelIndex& index, const QString& void UserLocationsModel::refresh() { if (!_updating) { beginResetModel(); + qDeleteAll(_locations); _locations.clear(); _updating = true; endResetModel(); diff --git a/interface/src/UserLocationsModel.h b/interface/src/UserLocationsModel.h index 7cf984a8ac..d3f86faa5a 100644 --- a/interface/src/UserLocationsModel.h +++ b/interface/src/UserLocationsModel.h @@ -52,6 +52,7 @@ class UserLocationsModel : public QAbstractListModel { Q_OBJECT public: UserLocationsModel(QObject* parent = NULL); + ~UserLocationsModel(); virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; From aa08577c73c9fc1097f723bd2947e1a0ae814e0a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 17:59:59 -0700 Subject: [PATCH 32/80] Fix long line --- interface/src/UserLocationsModel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 90d6927e1e..b69d8db748 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -181,7 +181,9 @@ void UserLocationsModel::handleLocationsResponse(const QJsonObject& responseData QJsonObject location = (*it).toObject(); QJsonObject address = location["address"].toObject(); UserLocation* userLocation = new UserLocation(location["id"].toString(), location["name"].toString(), - "hifi://" + address["domain"].toString() + "/" + address["position"].toString() + "/" + address["orientation"].toString()); + "hifi://" + address["domain"].toString() + + "/" + address["position"].toString() + + "/" + address["orientation"].toString()); _locations.append(userLocation); connect(userLocation, &UserLocation::deleted, this, &UserLocationsModel::removeLocation); connect(userLocation, &UserLocation::updated, this, &UserLocationsModel::update); From 83349e0e53e97f7e9e4eca43b23d4abcf2e043ee Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 20:03:05 -0700 Subject: [PATCH 33/80] Rename UserLocationsWindow to UserLocationsDialog --- interface/src/Menu.cpp | 12 +++++----- interface/src/Menu.h | 4 ++-- ...ionsWindow.cpp => UserLocationsDialog.cpp} | 24 +++++++++---------- ...ocationsWindow.h => UserLocationsDialog.h} | 16 ++++++------- ...ationsWindow.ui => userLocationsDialog.ui} | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) rename interface/src/ui/{UserLocationsWindow.cpp => UserLocationsDialog.cpp} (82%) rename interface/src/ui/{UserLocationsWindow.h => UserLocationsDialog.h} (65%) rename interface/ui/{userLocationsWindow.ui => userLocationsDialog.ui} (97%) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c3417144ee..a1c7ee3c08 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -91,7 +91,7 @@ Menu::Menu() : _jsConsole(NULL), _octreeStatsDialog(NULL), _lodToolsDialog(NULL), - _userLocationsWindow(NULL), + _userLocationsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), @@ -1186,13 +1186,13 @@ void Menu::namedLocationCreated(LocationManager::NamedLocationCreateResponse res } void Menu::toggleLocationList() { - if (!_userLocationsWindow) { - _userLocationsWindow = new UserLocationsWindow(Application::getInstance()->getWindow()); + if (!_userLocationsDialog) { + _userLocationsDialog = new UserLocationsDialog(Application::getInstance()->getWindow()); } - if (_userLocationsWindow->isVisible()) { - _userLocationsWindow->hide(); + if (_userLocationsDialog->isVisible()) { + _userLocationsDialog->hide(); } else { - _userLocationsWindow->show(); + _userLocationsDialog->show(); } } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9a5e2f9d43..3112607753 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -29,7 +29,7 @@ #include "ui/JSConsole.h" #include "ui/LoginDialog.h" #include "ui/ScriptEditorWindow.h" -#include "ui/UserLocationsWindow.h" +#include "ui/UserLocationsDialog.h" const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -261,7 +261,7 @@ private: QDialog* _jsConsole; OctreeStatsDialog* _octreeStatsDialog; LodToolsDialog* _lodToolsDialog; - UserLocationsWindow* _userLocationsWindow; + UserLocationsDialog* _userLocationsDialog; int _maxVoxels; float _voxelSizeScale; float _oculusUIAngularSize; diff --git a/interface/src/ui/UserLocationsWindow.cpp b/interface/src/ui/UserLocationsDialog.cpp similarity index 82% rename from interface/src/ui/UserLocationsWindow.cpp rename to interface/src/ui/UserLocationsDialog.cpp index f7e684fc64..f72e66ce77 100644 --- a/interface/src/ui/UserLocationsWindow.cpp +++ b/interface/src/ui/UserLocationsDialog.cpp @@ -1,5 +1,5 @@ // -// UserLocationsWindow.cpp +// UserLocationsDialog.cpp // interface/src/ui // // Created by Ryan Huffman on 06/24/14. @@ -14,9 +14,9 @@ #include #include "Menu.h" -#include "UserLocationsWindow.h" +#include "UserLocationsDialog.h" -UserLocationsWindow::UserLocationsWindow(QWidget* parent) : +UserLocationsDialog::UserLocationsDialog(QWidget* parent) : QDialog(parent), _ui(), _proxyModel(this), @@ -32,30 +32,30 @@ UserLocationsWindow::UserLocationsWindow(QWidget* parent) : _ui.locationsTreeView->sortByColumn(UserLocationsModel::NameColumn, Qt::AscendingOrder); connect(_ui.locationsTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, - this, &UserLocationsWindow::updateEnabled); - connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsWindow::updateEnabled); + this, &UserLocationsDialog::updateEnabled); + connect(&_userLocationsModel, &UserLocationsModel::modelReset, this, &UserLocationsDialog::updateEnabled); connect(&_userLocationsModel, &UserLocationsModel::modelReset, &_proxyModel, &QSortFilterProxyModel::invalidate); - connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsWindow::goToModelIndex); + connect(_ui.locationsTreeView, &QTreeView::doubleClicked, this, &UserLocationsDialog::goToModelIndex); - connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsWindow::deleteSelection); - connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsWindow::renameSelection); + connect(_ui.deleteButton, &QPushButton::clicked, this, &UserLocationsDialog::deleteSelection); + connect(_ui.renameButton, &QPushButton::clicked, this, &UserLocationsDialog::renameSelection); connect(_ui.refreshButton, &QPushButton::clicked, &_userLocationsModel, &UserLocationsModel::refresh); this->setWindowTitle("My Locations"); } -void UserLocationsWindow::updateEnabled() { +void UserLocationsDialog::updateEnabled() { bool enabled = _ui.locationsTreeView->selectionModel()->hasSelection(); _ui.renameButton->setEnabled(enabled); _ui.deleteButton->setEnabled(enabled); } -void UserLocationsWindow::goToModelIndex(const QModelIndex& index) { +void UserLocationsDialog::goToModelIndex(const QModelIndex& index) { QVariant location = _proxyModel.data(index.sibling(index.row(), UserLocationsModel::LocationColumn)); Menu::getInstance()->goToURL(location.toString()); } -void UserLocationsWindow::deleteSelection() { +void UserLocationsDialog::deleteSelection() { QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); selection = _proxyModel.mapToSource(selection); if (selection.isValid()) { @@ -63,7 +63,7 @@ void UserLocationsWindow::deleteSelection() { } } -void UserLocationsWindow::renameSelection() { +void UserLocationsDialog::renameSelection() { QModelIndex selection = _ui.locationsTreeView->selectionModel()->currentIndex(); selection = _proxyModel.mapToSource(selection); if (selection.isValid()) { diff --git a/interface/src/ui/UserLocationsWindow.h b/interface/src/ui/UserLocationsDialog.h similarity index 65% rename from interface/src/ui/UserLocationsWindow.h rename to interface/src/ui/UserLocationsDialog.h index 215c1957f3..0e596ece87 100644 --- a/interface/src/ui/UserLocationsWindow.h +++ b/interface/src/ui/UserLocationsDialog.h @@ -1,5 +1,5 @@ // -// UserLocationsWindow.h +// UserLocationsDialog.h // interface/src/ui // // Created by Ryan Huffman on 06/24/14. @@ -9,16 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_UserLocationsWindow_h -#define hifi_UserLocationsWindow_h +#ifndef hifi_UserLocationsDialog_h +#define hifi_UserLocationsDialog_h -#include "ui_userLocationsWindow.h" +#include "ui_userLocationsDialog.h" #include "UserLocationsModel.h" -class UserLocationsWindow : public QDialog { +class UserLocationsDialog : public QDialog { Q_OBJECT public: - UserLocationsWindow(QWidget* parent = NULL); + UserLocationsDialog(QWidget* parent = NULL); protected slots: void updateEnabled(); @@ -27,9 +27,9 @@ protected slots: void renameSelection(); private: - Ui::UserLocationsWindow _ui; + Ui::UserLocationsDialog _ui; QSortFilterProxyModel _proxyModel; UserLocationsModel _userLocationsModel; }; -#endif // hifi_UserLocationsWindow_h +#endif // hifi_UserLocationsDialog_h diff --git a/interface/ui/userLocationsWindow.ui b/interface/ui/userLocationsDialog.ui similarity index 97% rename from interface/ui/userLocationsWindow.ui rename to interface/ui/userLocationsDialog.ui index 61bb0149f8..609ce1c8ab 100644 --- a/interface/ui/userLocationsWindow.ui +++ b/interface/ui/userLocationsDialog.ui @@ -1,7 +1,7 @@ - UserLocationsWindow - + UserLocationsDialog + 0 From f0c013960df8fe1267be7bc7940239b4820f0d3e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Jul 2014 20:05:30 -0700 Subject: [PATCH 34/80] Remove unnecessary qDebug --- interface/src/UserLocationsModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index b69d8db748..87c81bbcd9 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -56,7 +56,6 @@ void UserLocation::requestRename(const QString& newName) { void UserLocation::handleRenameResponse(const QJsonObject& responseData) { _updating = false; - qDebug() << responseData; QJsonValue status = responseData["status"]; if (!status.isUndefined() && status.toString() == "success") { QString updatedName = responseData["data"].toObject()["name"].toString(); From 67ecde7d312b3652130ef536924bd1616e8df7b1 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Tue, 1 Jul 2014 21:39:19 -0700 Subject: [PATCH 35/80] Made tree editor voxel world stationary and not crash --- interface/src/Application.cpp | 7 +-- interface/src/devices/OculusManager.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 36 ++++++++++++ interface/src/ui/ApplicationOverlay.cpp | 75 ++++++++++++++++++++++++- interface/src/ui/ApplicationOverlay.h | 1 + 5 files changed, 113 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f21fedabea..b48d35c5e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -641,13 +641,8 @@ void Application::paintGL() { } } else if (TV3DManager::isConnected()) { - if (glowEnabled) { - _glowEffect.prepare(); - } + TV3DManager::display(whichCamera); - if (glowEnabled) { - _glowEffect.render(); - } } else { if (glowEnabled) { diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d9549438b5..e156e148ab 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -262,7 +262,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p 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 + // We only need to render the overlays to a texture once, then we just render the texture on the hemisphere // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::DisplayOculusOverlays); diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index b5cc28b07f..98fe3ac6d4 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -93,6 +93,18 @@ void TV3DManager::display(Camera& whichCamera) { int portalW = Application::getInstance()->getGLWidget()->width() / 2; int portalH = Application::getInstance()->getGLWidget()->height(); + const bool glowEnabled = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect); + + 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); + + if (glowEnabled) { + Application::getInstance()->getGlowEffect()->prepare(); + } + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_SCISSOR_TEST); @@ -102,13 +114,24 @@ void TV3DManager::display(Camera& whichCamera) { glPushMatrix(); { + glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_leftEye.left, _leftEye.right, _leftEye.bottom, _leftEye.top, nearZ, farZ); // set left view frustum + GLfloat p[4][4]; + glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); + GLfloat cotangent = p[1][1]; + GLfloat fov = atan(1.0f / cotangent); glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + + + printf("FOV %f\n", fov); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); + + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } glPopMatrix(); glDisable(GL_SCISSOR_TEST); @@ -124,14 +147,27 @@ void TV3DManager::display(Camera& whichCamera) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); // reset projection matrix glFrustum(_rightEye.left, _rightEye.right, _rightEye.bottom, _rightEye.top, nearZ, farZ); // set left view frustum + GLfloat p[4][4]; + glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0])); + GLfloat cotangent = p[1][1]; + GLfloat fov = atan(1.0f / cotangent); glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax + + printf("FOV %f\n", fov); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); + + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); } glPopMatrix(); glDisable(GL_SCISSOR_TEST); // reset the viewport to how we started glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); + + if (glowEnabled) { + Application::getInstance()->getGlowEffect()->render(); + } } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 77e8986297..07582e2781 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -206,7 +206,7 @@ void ApplicationOverlay::getClickLocation(int &x, int &y) const { } } -// Draws the FBO texture for Oculus rift. TODO: Draw a curved texture instead of plane. +// Draws the FBO texture for Oculus rift. void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_alpha == 0.0f) { @@ -293,6 +293,79 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { } +// Draws the FBO texture for 3DTV. +void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { + + if (_alpha == 0.0f) { + return; + } + + Application* application = Application::getInstance(); + + MyAvatar* myAvatar = application->getAvatar(); + const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); + + glActiveTexture(GL_TEXTURE0); + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glLoadIdentity(); + // Transform to world space + glm::quat rotation = whichCamera.getRotation(); + glm::vec3 axis2 = glm::axis(rotation); + glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); + glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); + + // Translate to the front of the camera + glm::vec3 pos = whichCamera.getPosition(); + glm::quat rot = myAvatar->getOrientation(); + glm::vec3 axis = glm::axis(rot); + + glTranslatef(pos.x, pos.y, pos.z); + glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); + + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + //Render + const GLfloat distance = 1.0f; + + const GLfloat halfQuadHeight = atan(fov) * distance; + const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; + const GLfloat quadWidth = halfQuadWidth * 2.0f; + const GLfloat quadHeight = halfQuadHeight * 2.0f; + + const GLfloat x = -halfQuadWidth; + const GLfloat y = -halfQuadHeight; + + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); + glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); + glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); + glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); + + glEnd(); + + glPopMatrix(); + + glDepthMask(GL_TRUE); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_LIGHTING); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +} + //Renders optional pointers void ApplicationOverlay::renderPointers() { Application* application = Application::getInstance(); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index b9f9596ccf..7c1f87d575 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -29,6 +29,7 @@ public: void renderOverlay(bool renderToTexture = false); void displayOverlayTexture(); void displayOverlayTextureOculus(Camera& whichCamera); + void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); void computeOculusPickRay(float x, float y, glm::vec3& direction) const; void getClickLocation(int &x, int &y) const; From 36fb530594e679593310c97ed20748d5336fd519 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 10:26:38 -0700 Subject: [PATCH 36/80] Switched DomainServer to NetworkAccessManager --- assignment-client/src/octree/OctreeServer.cpp | 1 - domain-server/src/DomainServer.cpp | 6 ++---- domain-server/src/DomainServer.h | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 23719b86cf..551bed795d 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -10,7 +10,6 @@ // #include -#include #include #include diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7a2d5f4f99..366a5016f9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -51,8 +51,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : _argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments()); - _networkAccessManager = new QNetworkAccessManager(this); - if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) { // we either read a certificate and private key or were not passed one // and completed login or did not need to @@ -1196,7 +1194,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u QNetworkRequest tokenRequest(tokenRequestUrl); tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - QNetworkReply* tokenReply = _networkAccessManager->post(tokenRequest, tokenPostBody.toLocal8Bit()); + QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit()); qDebug() << "Requesting a token for user with session UUID" << uuidStringWithoutCurlyBraces(stateUUID); @@ -1233,7 +1231,7 @@ void DomainServer::handleTokenRequestFinished() { profileURL.setPath("/api/v1/users/profile"); profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken)); - QNetworkReply* profileReply = _networkAccessManager->get(QNetworkRequest(profileURL)); + QNetworkReply* profileReply = NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL)); qDebug() << "Requesting access token for user with session UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 01f44b698e..cc44bd95a8 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -103,8 +103,6 @@ private: bool _isUsingDTLS; - QNetworkAccessManager* _networkAccessManager; - QUrl _oauthProviderURL; QString _oauthClientID; QString _oauthClientSecret; From 6489151578b34b8101e778cc5f533ee67a82b8ed Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 10:28:26 -0700 Subject: [PATCH 37/80] Switch ImageOverlay to NetworkAccessManager --- interface/src/ui/overlays/ImageOverlay.cpp | 16 ++++++---------- interface/src/ui/overlays/ImageOverlay.h | 5 ++--- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 79b1b23de5..aeea781eb6 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -19,7 +19,6 @@ #include "ImageOverlay.h" ImageOverlay::ImageOverlay() : - _manager(NULL), _textureID(0), _renderImage(false), _textureBound(false), @@ -36,21 +35,18 @@ ImageOverlay::~ImageOverlay() { // TODO: handle setting image multiple times, how do we manage releasing the bound texture? void ImageOverlay::setImageURL(const QUrl& url) { - // TODO: are we creating too many QNetworkAccessManager() when multiple calls to setImageURL are made? - _manager->deleteLater(); - _manager = new QNetworkAccessManager(); - connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); - _manager->get(QNetworkRequest(url)); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); + connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); } -void ImageOverlay::replyFinished(QNetworkReply* reply) { - +void ImageOverlay::replyFinished() { + QNetworkReply* reply = static_cast(sender()); + // replace our byte array with the downloaded data QByteArray rawData = reply->readAll(); _textureImage.loadFromData(rawData); _renderImage = true; - _manager->deleteLater(); - _manager = NULL; } void ImageOverlay::render() { diff --git a/interface/src/ui/overlays/ImageOverlay.h b/interface/src/ui/overlays/ImageOverlay.h index 613cd95989..633567287d 100644 --- a/interface/src/ui/overlays/ImageOverlay.h +++ b/interface/src/ui/overlays/ImageOverlay.h @@ -16,13 +16,13 @@ #include #include -#include #include #include #include #include #include +#include #include #include "Overlay.h" @@ -46,13 +46,12 @@ public: virtual void setProperties(const QScriptValue& properties); private slots: - void replyFinished(QNetworkReply* reply); // we actually want to hide this... + void replyFinished(); // we actually want to hide this... private: QUrl _imageURL; QImage _textureImage; - QNetworkAccessManager* _manager; GLuint _textureID; QRect _fromImage; // where from in the image to sample From f6221abb71711b7913022fcb09c54425fd2abacb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 10:52:08 -0700 Subject: [PATCH 38/80] Switch ModelUploader to NetworkAccessManager --- interface/src/ModelUploader.cpp | 2 +- interface/src/ModelUploader.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 81bca0fc5a..12a4b145cc 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -396,7 +396,7 @@ void ModelUploader::uploadFailed(QNetworkReply::NetworkError errorCode, const QS void ModelUploader::checkS3() { qDebug() << "Checking S3 for " << _url; QNetworkRequest request(_url); - QNetworkReply* reply = _networkAccessManager.head(request); + QNetworkReply* reply = NetworkAccessManager::getInstance().head(request); connect(reply, SIGNAL(finished()), SLOT(processCheck())); } diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h index 634de05640..2596120751 100644 --- a/interface/src/ModelUploader.h +++ b/interface/src/ModelUploader.h @@ -58,7 +58,6 @@ private: bool _readyToSend; QHttpMultiPart* _dataMultiPart; - QNetworkAccessManager _networkAccessManager; int _numberOfChecks; QTimer _timer; From da0021cc8e566a0fe71a567a845e1ed799694e7f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 10:53:30 -0700 Subject: [PATCH 39/80] Switch ModelsBrowser to NetworkAccessManager --- interface/src/ui/ModelsBrowser.cpp | 18 ++++++++++-------- interface/src/ui/ModelsBrowser.h | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 203c54d97a..ec583a14f7 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -14,10 +14,11 @@ #include #include #include -#include #include #include +#include + #include "Application.h" #include "ModelsBrowser.h" @@ -210,10 +211,10 @@ void ModelHandler::update() { } for (int i = 0; i < _model.rowCount(); ++i) { QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); - QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); - accessManager->head(request); - connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + QNetworkReply* reply = networkAccessManager.head(request); + connect(reply, SIGNAL(finished()), SLOT(processCheck())); } _lock.unlock(); } @@ -233,7 +234,8 @@ void ModelHandler::exit() { _lock.unlock(); } -void ModelHandler::downloadFinished(QNetworkReply* reply) { +void ModelHandler::downloadFinished() { + QNetworkReply* reply = static_cast(sender()); QByteArray data = reply->readAll(); if (!data.isEmpty()) { @@ -261,10 +263,10 @@ void ModelHandler::queryNewFiles(QString marker) { // Download url.setQuery(query); - QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); - accessManager->get(request); - connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + QNetworkReply* reply = networkAccessManager.get(request); + connect(reply, SIGNAL(finished()), SLOT(processCheck())); } diff --git a/interface/src/ui/ModelsBrowser.h b/interface/src/ui/ModelsBrowser.h index 3e832c9dbe..8063fd8eeb 100644 --- a/interface/src/ui/ModelsBrowser.h +++ b/interface/src/ui/ModelsBrowser.h @@ -43,7 +43,7 @@ public slots: void exit(); private slots: - void downloadFinished(QNetworkReply* reply); + void downloadFinished(); private: bool _initiateExit; From 70121357be57dc557eb7682cfd0e4f31479483a5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 2 Jul 2014 11:12:06 -0700 Subject: [PATCH 40/80] Update JSONCallbackParameters to take params in constructor --- interface/src/UserLocationsModel.cpp | 16 +++------------- libraries/networking/src/AccountManager.cpp | 16 +++++++++------- libraries/networking/src/AccountManager.h | 4 +++- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/interface/src/UserLocationsModel.cpp b/interface/src/UserLocationsModel.cpp index 87c81bbcd9..e84cae8f95 100644 --- a/interface/src/UserLocationsModel.cpp +++ b/interface/src/UserLocationsModel.cpp @@ -34,11 +34,7 @@ void UserLocation::requestRename(const QString& newName) { if (!_updating && newName.toLower() != _name) { _updating = true; - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "handleRenameResponse"; - callbackParams.errorCallbackReceiver = this; - callbackParams.errorCallbackMethod = "handleRenameError"; + JSONCallbackParameters callbackParams(this, "handleRenameResponse", this, "handleRenameError"); QJsonObject jsonNameObject; jsonNameObject.insert("name", QJsonValue(newName)); QJsonDocument jsonDocument(jsonNameObject); @@ -93,11 +89,7 @@ void UserLocation::requestDelete() { if (!_updating) { _updating = true; - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "handleDeleteResponse"; - callbackParams.errorCallbackReceiver = this; - callbackParams.errorCallbackMethod = "handleDeleteError"; + JSONCallbackParameters callbackParams(this, "handleDeleteResponse", this, "handleDeleteError"); AccountManager::getInstance().authenticatedRequest(PLACES_DELETE.arg(_id), QNetworkAccessManager::DeleteOperation, callbackParams); @@ -160,9 +152,7 @@ void UserLocationsModel::refresh() { _updating = true; endResetModel(); - JSONCallbackParameters callbackParams; - callbackParams.jsonCallbackReceiver = this; - callbackParams.jsonCallbackMethod = "handleLocationsResponse"; + JSONCallbackParameters callbackParams(this, "handleLocationsResponse"); AccountManager::getInstance().authenticatedRequest(PLACES_GET, QNetworkAccessManager::GetOperation, callbackParams); diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 8800686178..ce138e144e 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -37,13 +37,15 @@ Q_DECLARE_METATYPE(JSONCallbackParameters) const QString ACCOUNTS_GROUP = "accounts"; -JSONCallbackParameters::JSONCallbackParameters() : - jsonCallbackReceiver(NULL), - jsonCallbackMethod(), - errorCallbackReceiver(NULL), - errorCallbackMethod(), - updateReciever(NULL), - updateSlot() +JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, const QString& jsonCallbackMethod, + QObject* errorCallbackReceiver, const QString& errorCallbackMethod, + QObject* updateReceiver, const QString& updateSlot) : + jsonCallbackReceiver(jsonCallbackReceiver), + jsonCallbackMethod(jsonCallbackMethod), + errorCallbackReceiver(errorCallbackReceiver), + errorCallbackMethod(errorCallbackMethod), + updateReciever(updateReceiver), + updateSlot(updateSlot) { } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index c18836ca54..389f84e01f 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -22,7 +22,9 @@ class JSONCallbackParameters { public: - JSONCallbackParameters(); + JSONCallbackParameters(QObject* jsonCallbackReceiver = NULL, const QString& jsonCallbackMethod = QString(), + QObject* errorCallbackReceiver = NULL, const QString& errorCallbackMethod = QString(), + QObject* updateReceiver = NULL, const QString& updateSlot = QString()); bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; } From c3f7d9d15598e2988270f27fbacaf21143968bae Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Jul 2014 11:20:14 -0700 Subject: [PATCH 41/80] delete AngularConstraints at end of tests --- tests/shared/src/AngularConstraintTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 22762ea524..d6a9214acc 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -281,6 +281,7 @@ void AngularConstraintTests::testHingeConstraint() { << " ERROR: HingeConstraint rotation = " << newRotation << " but expected " << expectedRotation << std::endl; } } + delete c; } void AngularConstraintTests::testConeRollerConstraint() { @@ -466,6 +467,7 @@ void AngularConstraintTests::testConeRollerConstraint() { << " ERROR: rotation = " << newRotation << " but expected " << expectedRotation << std::endl; } } + delete c; } void AngularConstraintTests::runAllTests() { From 15b37ec3d1181542fb3c47e4a0efd146ab2cbf79 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:21:07 -0700 Subject: [PATCH 42/80] Switched ResourceCache to NetworkAccessManager --- libraries/{shared => networking}/src/ResourceCache.cpp | 8 ++++---- libraries/{shared => networking}/src/ResourceCache.h | 6 ------ 2 files changed, 4 insertions(+), 10 deletions(-) rename libraries/{shared => networking}/src/ResourceCache.cpp (97%) rename libraries/{shared => networking}/src/ResourceCache.h (94%) diff --git a/libraries/shared/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp similarity index 97% rename from libraries/shared/src/ResourceCache.cpp rename to libraries/networking/src/ResourceCache.cpp index 14998232d6..a183e2f9a1 100644 --- a/libraries/shared/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -16,6 +16,8 @@ #include #include +#include "NetworkAccessManager.h" + #include "ResourceCache.h" ResourceCache::ResourceCache(QObject* parent) : @@ -103,8 +105,6 @@ void ResourceCache::requestCompleted(Resource* resource) { } } -QNetworkAccessManager* ResourceCache::_networkAccessManager = NULL; - const int DEFAULT_REQUEST_LIMIT = 10; int ResourceCache::_requestLimit = DEFAULT_REQUEST_LIMIT; @@ -219,7 +219,7 @@ void Resource::init() { if (_url.isEmpty()) { _startedLoading = _loaded = true; - } else if (!(_url.isValid() && ResourceCache::getNetworkAccessManager())) { + } else if (!(_url.isValid())) { _startedLoading = _failedToLoad = true; } } @@ -272,7 +272,7 @@ void Resource::handleReplyTimeout() { } void Resource::makeRequest() { - _reply = ResourceCache::getNetworkAccessManager()->get(_request); + _reply = NetworkAccessManager::getInstance().get(_request); connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); diff --git a/libraries/shared/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h similarity index 94% rename from libraries/shared/src/ResourceCache.h rename to libraries/networking/src/ResourceCache.h index 2404485c46..1593ad45fc 100644 --- a/libraries/shared/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -22,7 +22,6 @@ #include #include -class QNetworkAccessManager; class QNetworkReply; class QTimer; @@ -33,10 +32,6 @@ class ResourceCache : public QObject { Q_OBJECT public: - - static void setNetworkAccessManager(QNetworkAccessManager* manager) { _networkAccessManager = manager; } - static QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } - static void setRequestLimit(int limit) { _requestLimit = limit; } static int getRequestLimit() { return _requestLimit; } @@ -76,7 +71,6 @@ private: QHash > _resources; int _lastLRUKey; - static QNetworkAccessManager* _networkAccessManager; static int _requestLimit; static QList > _pendingRequests; static QList _loadingRequests; From 602015be661bf21e950248a8338840cd91cfa493 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:21:26 -0700 Subject: [PATCH 43/80] Switched ScriptModel to NetworkAccessManager --- interface/src/ScriptsModel.cpp | 16 +++++++++------- interface/src/ScriptsModel.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index f9ed94f3fa..77a9619d43 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -11,14 +11,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include #include #include -#include "ScriptsModel.h" +#include + #include "Menu.h" +#include "ScriptsModel.h" static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; static const QString PUBLIC_URL = "http://public.highfidelity.io"; @@ -113,14 +114,15 @@ void ScriptsModel::requestRemoteFiles(QString marker) { } url.setQuery(query); - QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); - connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); - + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); - accessManager->get(request); + QNetworkReply* reply = networkAccessManager.get(request); + connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); + } -void ScriptsModel::downloadFinished(QNetworkReply* reply) { +void ScriptsModel::downloadFinished() { + QNetworkReply* reply = static_cast(sender()); bool finished = true; if (reply->error() == QNetworkReply::NoError) { diff --git a/interface/src/ScriptsModel.h b/interface/src/ScriptsModel.h index 250c7eb9a8..ca72a8d8f4 100644 --- a/interface/src/ScriptsModel.h +++ b/interface/src/ScriptsModel.h @@ -43,7 +43,7 @@ public: protected slots: void updateScriptsLocation(const QString& newPath); - void downloadFinished(QNetworkReply* reply); + void downloadFinished(); void reloadLocalFiles(); void reloadRemoteFiles(); From 9bcd4e7ac85d720a6eda839131e1c257675d5b17 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:21:54 -0700 Subject: [PATCH 44/80] Switched ScriptEditorWidget to NetworkAccessManager --- interface/src/ui/ScriptEditorWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index 513bbd899a..d25408e568 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -148,8 +148,8 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) { disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); } } else { - QNetworkAccessManager* networkManager = new QNetworkAccessManager(this); - QNetworkReply* reply = networkManager->get(QNetworkRequest(url)); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << scriptPath; QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); From b018c1c4a554d5cef2d2ca5698daae344e903b88 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Jul 2014 11:22:07 -0700 Subject: [PATCH 45/80] Add copy ctor for JointState create AngularConstraint for joints that need them (but not used yet) --- interface/src/renderer/JointState.cpp | 30 ++++++++++++++++++++++++--- interface/src/renderer/JointState.h | 4 +++- interface/src/renderer/Model.cpp | 3 +-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index 3b3c135eb5..f7b4dbc96f 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -23,6 +23,15 @@ JointState::JointState() : _constraint(NULL) { } +JointState::JointState(const JointState& other) : _constraint(NULL) { + _rotationInParentFrame = other._rotationInParentFrame; + _transform = other._transform; + _rotation = other._rotation; + _animationPriority = other._animationPriority; + _fbxJoint = other._fbxJoint; + // DO NOT copy _constraint +} + JointState::~JointState() { delete _constraint; _constraint = NULL; @@ -33,6 +42,22 @@ void JointState::setFBXJoint(const FBXJoint* joint) { _rotationInParentFrame = joint->rotation; // NOTE: JointState does not own the FBXJoint to which it points. _fbxJoint = joint; + if (_constraint) { + delete _constraint; + _constraint = NULL; + } +} + +void JointState::updateConstraint() { + if (_constraint) { + delete _constraint; + _constraint = NULL; + } + if (glm::distance2(glm::vec3(-PI), _fbxJoint->rotationMin) > EPSILON || + glm::distance2(glm::vec3(PI), _fbxJoint->rotationMax) > EPSILON ) { + // this joint has rotation constraints + _constraint = AngularConstraint::newAngularConstraint(_fbxJoint->rotationMin, _fbxJoint->rotationMax); + } } void JointState::copyState(const JointState& state) { @@ -40,7 +65,7 @@ void JointState::copyState(const JointState& state) { _transform = state._transform; _rotation = extractRotation(_transform); _animationPriority = state._animationPriority; - // DO NOT copy _fbxJoint + // DO NOT copy _fbxJoint or _constraint } void JointState::computeTransform(const glm::mat4& parentTransform) { @@ -88,8 +113,7 @@ void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, floa return; } _animationPriority = priority; - if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) && - _fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) { + if (!constrain || _constraint == NULL) { // no constraints _rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation; _rotation = delta * _rotation; diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index 4eadc51f7c..e5f02fdf16 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -23,11 +23,13 @@ class AngularConstraint; class JointState { public: JointState(); + JointState(const JointState& other); ~JointState(); void setFBXJoint(const FBXJoint* joint); const FBXJoint& getFBXJoint() const { return *_fbxJoint; } + void updateConstraint(); void copyState(const JointState& state); void computeTransform(const glm::mat4& parentTransform); @@ -64,7 +66,7 @@ private: glm::quat _rotation; // joint- to model-frame const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint - AngularConstraint* _constraint; + AngularConstraint* _constraint; // JointState owns its AngularConstraint }; #endif // hifi_JointState_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3b5cda4fd2..a86d392981 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -561,8 +561,6 @@ bool Model::updateGeometry() { void Model::setJointStates(QVector states) { _jointStates = states; - // compute an approximate bounding radius for broadphase collision queries - // against PhysicsSimulation boundaries int numJoints = _jointStates.size(); float radius = 0.0f; for (int i = 0; i < numJoints; ++i) { @@ -570,6 +568,7 @@ void Model::setJointStates(QVector states) { if (distance > radius) { radius = distance; } + _jointStates[i].updateConstraint(); } _boundingRadius = radius; } From 14a2bbb454aff65eb09cec82ff27bbc2f9470387 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:22:29 -0700 Subject: [PATCH 46/80] Switched SnapshotShareDialog to NetworkAccessManager --- interface/src/ui/SnapshotShareDialog.cpp | 18 +++--------------- interface/src/ui/SnapshotShareDialog.h | 2 -- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/interface/src/ui/SnapshotShareDialog.cpp b/interface/src/ui/SnapshotShareDialog.cpp index 617d5e7101..046aa4d12c 100644 --- a/interface/src/ui/SnapshotShareDialog.cpp +++ b/interface/src/ui/SnapshotShareDialog.cpp @@ -40,8 +40,7 @@ Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) SnapshotShareDialog::SnapshotShareDialog(QString fileName, QWidget* parent) : QDialog(parent), - _fileName(fileName), - _networkAccessManager(NULL) + _fileName(fileName) { setAttribute(Qt::WA_DeleteOnClose); @@ -92,10 +91,6 @@ void SnapshotShareDialog::uploadSnapshot() { return; } - if (!_networkAccessManager) { - _networkAccessManager = new QNetworkAccessManager(this); - } - QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart apiKeyPart; @@ -118,9 +113,7 @@ void SnapshotShareDialog::uploadSnapshot() { QUrl url(FORUM_UPLOADS_URL); QNetworkRequest request(url); - QNetworkReply* reply = _networkAccessManager->post(request, multiPart); - - + QNetworkReply* reply = NetworkAccessManager::getInstance().post(request, multiPart); connect(reply, &QNetworkReply::finished, this, &SnapshotShareDialog::uploadRequestFinished); QEventLoop loop; @@ -129,11 +122,6 @@ void SnapshotShareDialog::uploadSnapshot() { } void SnapshotShareDialog::sendForumPost(QString snapshotPath) { - - if (!_networkAccessManager) { - _networkAccessManager = new QNetworkAccessManager(this); - } - // post to Discourse forum QNetworkRequest request; QUrl forumUrl(FORUM_POST_URL); @@ -148,7 +136,7 @@ void SnapshotShareDialog::sendForumPost(QString snapshotPath) { request.setUrl(forumUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - QNetworkReply* requestReply = _networkAccessManager->post(request, postData); + QNetworkReply* requestReply = NetworkAccessManager::getInstance().post(request, postData); connect(requestReply, &QNetworkReply::finished, this, &SnapshotShareDialog::postRequestFinished); QEventLoop loop; diff --git a/interface/src/ui/SnapshotShareDialog.h b/interface/src/ui/SnapshotShareDialog.h index a8795d578a..ced9f2d951 100644 --- a/interface/src/ui/SnapshotShareDialog.h +++ b/interface/src/ui/SnapshotShareDialog.h @@ -14,7 +14,6 @@ #include "ui_shareSnapshot.h" -#include #include #include @@ -26,7 +25,6 @@ public: private: QString _fileName; - QNetworkAccessManager* _networkAccessManager; Ui_SnapshotShareDialog _ui; void uploadSnapshot(); From 2549b0d9465a63718cb26cc1d722c4ab28e2bb09 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:22:44 -0700 Subject: [PATCH 47/80] Switched ScriptEngine to NetworkAccessManager --- libraries/script-engine/src/ScriptEngine.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 55b99d6039..daf66dafbe 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -141,8 +141,8 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, emit errorMessage("ERROR Loading file:" + fileName); } } else { - QNetworkAccessManager* networkManager = new QNetworkAccessManager(this); - QNetworkReply* reply = networkManager->get(QNetworkRequest(url)); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << url; QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); @@ -646,8 +646,8 @@ void ScriptEngine::include(const QString& includeFile) { QString includeContents; if (url.scheme() == "http" || url.scheme() == "ftp") { - QNetworkAccessManager* networkManager = new QNetworkAccessManager(this); - QNetworkReply* reply = networkManager->get(QNetworkRequest(url)); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << includeFile; QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); From 74e7e0a7bf778b84f2c6be2ee776994e71a428fb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:27:32 -0700 Subject: [PATCH 48/80] Switched XMLHttpRequestClass to NetworkAccessManager --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 5 +++-- libraries/script-engine/src/XMLHttpRequestClass.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index a81f8950fa..d9b7312bf4 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -14,6 +14,8 @@ #include +#include + #include "XMLHttpRequestClass.h" XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : @@ -22,7 +24,6 @@ XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : _url(), _method(""), _responseType(""), - _manager(this), _request(), _reply(NULL), _sendData(NULL), @@ -161,7 +162,7 @@ void XMLHttpRequestClass::send(const QString& data) { } void XMLHttpRequestClass::doSend() { - _reply = _manager.sendCustomRequest(_request, _method.toLatin1(), _sendData); + _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); connectToReply(_reply); diff --git a/libraries/script-engine/src/XMLHttpRequestClass.h b/libraries/script-engine/src/XMLHttpRequestClass.h index 49a952e638..48f1a596e1 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.h +++ b/libraries/script-engine/src/XMLHttpRequestClass.h @@ -13,7 +13,6 @@ #define hifi_XMLHttpRequestClass_h #include -#include #include #include #include @@ -104,7 +103,6 @@ private: QUrl _url; QString _method; QString _responseType; - QNetworkAccessManager _manager; QNetworkRequest _request; QNetworkReply* _reply; QBuffer* _sendData; From 598c1cb516166cc3a2680d9cad87993804aae7bc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 11:27:55 -0700 Subject: [PATCH 49/80] Switched Sound to NetworkAccessManager --- interface/src/ui/overlays/TextOverlay.h | 1 - libraries/audio/src/Sound.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 78a037762e..c2aafb24e8 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 7ef3afdf29..03c9f6b8ee 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -15,12 +15,12 @@ #include #include -#include #include #include #include #include +#include #include #include "AudioRingBuffer.h" @@ -73,11 +73,11 @@ Sound::Sound(const QUrl& sampleURL, QObject* parent) : // assume we have a QApplication or QCoreApplication instance and use the // QNetworkAccess manager to grab the raw audio file at the given URL - QNetworkAccessManager *manager = new QNetworkAccessManager(this); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); qDebug() << "Requesting audio file" << sampleURL.toDisplayString(); - QNetworkReply* soundDownload = manager->get(QNetworkRequest(sampleURL)); + QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL)); connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished); connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError))); } From e903b1659a1f79ea2c8ab23644353d198134947d Mon Sep 17 00:00:00 2001 From: Chris Oates Date: Wed, 2 Jul 2014 13:09:16 -0700 Subject: [PATCH 50/80] Implemented Improved Perlin Noise in existing "textured voxels" option. TextureCache.cpp: modified so that permutation texture contains known permutation of 0..255 rather than random set of values. Does not noticeably affect visuals. perlin_modulate.frag: implementation of improved noise, per 2002 SIGGRAPH paper, including "turbulence" summation. --- .../resources/shaders/perlin_modulate.frag | 109 ++++++++++++++++-- interface/src/renderer/TextureCache.cpp | 37 +++++- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/interface/resources/shaders/perlin_modulate.frag b/interface/resources/shaders/perlin_modulate.frag index 8693b14e1b..23d31ff72e 100644 --- a/interface/resources/shaders/perlin_modulate.frag +++ b/interface/resources/shaders/perlin_modulate.frag @@ -11,18 +11,114 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// the texture containing our permutations and normals -uniform sampler2D permutationNormalTexture; +// implementation based on Ken Perlin's Improved Noise reference implementation (orig. in Java) at +// http://mrl.nyu.edu/~perlin/noise/ + +uniform sampler2D permutationTexture; // the noise frequency -const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128 +const float frequency = 256.0; +//const float frequency = 65536.0; // looks better with current TREE_SCALE, was 1024 when TREE_SCALE was either 512 or 128 // the noise amplitude -const float amplitude = 0.1; +const float amplitude = 0.5; // the position in model space varying vec3 position; +// gradient based on gradients from cube edge centers rather than random from texture lookup +float randomEdgeGrad(int hash, vec3 position){ + int h = int(mod(hash, 16)); + float u = h < 8 ? position.x : position.y; + float v = h < 4 ? position.y : h == 12 || h == 14 ? position.x : position.z; + bool even = mod(hash, 2) == 0; + bool four = mod(hash, 4) == 0; + return (even ? u : -u) + (four ? v : -v); +} + +// still have the option to lookup based on texture +float randomTextureGrad(int hash, vec3 position){ + float u = float(hash) / 256.0; + vec3 g = -1 + 2 * texture2D(permutationTexture, vec2(u, 0.75)).rgb; + return dot(position, g); +} + +float improvedGrad(int hash, vec3 position){ +// Untested whether texture lookup is faster than math, uncomment one line or the other to try out +// cube edge gradients versus random spherical gradients sent in texture. + +// return randomTextureGrad(hash, position); + return randomEdgeGrad(hash, position); +} + +// 5th order fade function to remove 2nd order discontinuties +vec3 fade3(vec3 t){ + return t * t * t * (t * (t * 6 - 15) + 10); +} + +int permutation(int index){ + float u = float(index) / 256.0; + float t = texture2D(permutationTexture, vec2(u, 0.25)).r; + return int(t * 256); +} + +float improvedNoise(vec3 position){ + int X = int(mod(floor(position.x), 256)); + int Y = int(mod(floor(position.y), 256)); + int Z = int(mod(floor(position.z), 256)); + + vec3 fracs = fract(position); + + vec3 fades = fade3(fracs); + + int A = permutation(X + 0) + Y; + int AA = permutation(A + 0) + Z; + int AB = permutation(A + 1) + Z; + int B = permutation(X + 1) + Y; + int BA = permutation(B + 0) + Z; + int BB = permutation(B + 1) + Z; + + float gradAA0 = improvedGrad(permutation(AA + 0), vec3(fracs.x , fracs.y , fracs.z )); + float gradBA0 = improvedGrad(permutation(BA + 0), vec3(fracs.x - 1, fracs.y , fracs.z )); + float gradAB0 = improvedGrad(permutation(AB + 0), vec3(fracs.x , fracs.y - 1, fracs.z )); + float gradBB0 = improvedGrad(permutation(BB + 0), vec3(fracs.x - 1, fracs.y - 1, fracs.z )); + float gradAA1 = improvedGrad(permutation(AA + 1), vec3(fracs.x , fracs.y , fracs.z - 1)); + float gradBA1 = improvedGrad(permutation(BA + 1), vec3(fracs.x - 1, fracs.y , fracs.z - 1)); + float gradAB1 = improvedGrad(permutation(AB + 1), vec3(fracs.x , fracs.y - 1, fracs.z - 1)); + float gradBB1 = improvedGrad(permutation(BB + 1), vec3(fracs.x - 1, fracs.y - 1, fracs.z - 1)); + + return mix(mix(mix(gradAA0, gradBA0, fades.x), mix(gradAB0, gradBB0, fades.x), fades.y), mix(mix(gradAA1, gradBA1, fades.x), mix(gradAB1, gradBB1, fades.x), fades.y), fades.z); +} + +float turbulence(vec3 position, float power){ + return (1.0f / power) * improvedNoise(power * position); +} + +float turb(vec3 position){ + return turbulence(position, 1) + + turbulence(position, 2), + + turbulence(position, 4) + + turbulence(position, 8) + + turbulence(position, 16) + + turbulence(position, 32) + + turbulence(position, 64) + + turbulence(position, 128) + ; +} + + +void main(void) { + + // get noise in range 0 .. 1 + float noise = clamp(0.5f + amplitude * turb(position * frequency), 0, 1); + + // apply vertex lighting + vec3 color = gl_Color.rgb * vec3(noise, noise, noise); + gl_FragColor = vec4(color, 1); +} + + +/* old implementation // returns the gradient at a single corner of our sampling cube vec3 grad(vec3 location) { float p1 = texture2D(permutationNormalTexture, vec2(location.x / 256.0, 0.25)).r; @@ -60,7 +156,4 @@ float perlin(vec3 location) { mix(mix(ffcv, cfcv, params.x), mix(fccv, cccv, params.x), params.y), params.z); } - -void main(void) { - gl_FragColor = vec4(gl_Color.rgb * (1.0 + amplitude*(perlin(position * frequency) - 1.0)), 1.0); -} +*/ \ No newline at end of file diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 0588ca70d2..c792cc59a9 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -51,6 +51,33 @@ TextureCache::~TextureCache() { delete _tertiaryFramebufferObject; } +// use fixed table of permutations. Could also make ordered list programmatically +// and then shuffle algorithm. For testing, this ensures consistent behavior in each run. +// this list taken from Ken Perlin's Improved Noise reference implementation (orig. in Java) at +// http://mrl.nyu.edu/~perlin/noise/ + +const int permutation[256] = +{ + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, + 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, + 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, + 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, + 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, + 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, + 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, + 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, + 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, + 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, + 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, + 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, + 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, + 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, + 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; + +#define USE_CHRIS_NOISE 0 + GLuint TextureCache::getPermutationNormalTextureID() { if (_permutationNormalTextureID == 0) { glGenTextures(1, &_permutationNormalTextureID); @@ -58,10 +85,17 @@ GLuint TextureCache::getPermutationNormalTextureID() { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; +#if defined(USE_CHRIS_NOISE) + for (int i = 0; i < 256; i++) { + data[3*i+0] = permutation[i]; + data[3*i+1] = permutation[i]; + data[3*i+2] = permutation[i]; +#else for (int i = 0; i < 256 * 3; i++) { data[i] = rand() % 256; +#endif } - // the next, random unit normals + for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { glm::vec3 randvec = glm::sphericalRand(1.0f); data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f; @@ -71,7 +105,6 @@ GLuint TextureCache::getPermutationNormalTextureID() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); } return _permutationNormalTextureID; From c79c5df295111060468b6fe991b0be18f0fc5889 Mon Sep 17 00:00:00 2001 From: Chris Oates Date: Wed, 2 Jul 2014 13:50:47 -0700 Subject: [PATCH 51/80] Fixing up #define / #if pair so that permutation table change can be turned of by setting #defined variable to 0 instead of having to comment it out. --- interface/src/renderer/TextureCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 1352b2c326..01c3dc1cc1 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -110,7 +110,7 @@ const int permutation[256] = 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; -#define USE_CHRIS_NOISE 0 +#define USE_CHRIS_NOISE 1 GLuint TextureCache::getPermutationNormalTextureID() { if (_permutationNormalTextureID == 0) { @@ -119,7 +119,7 @@ GLuint TextureCache::getPermutationNormalTextureID() { // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; -#if defined(USE_CHRIS_NOISE) +#if (USE_CHRIS_NOISE==1) for (int i = 0; i < 256; i++) { data[3*i+0] = permutation[i]; data[3*i+1] = permutation[i]; From bf520d0effdffcfb0456d033f66d666bba09b704 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 14:05:46 -0700 Subject: [PATCH 52/80] Added thread safe implementation of NetworkAccessManager main methods --- .../networking/src/NetworkAccessManager.cpp | 115 +++++++++++++++++- .../networking/src/NetworkAccessManager.h | 11 ++ 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index a33817b50d..7c45dc69d5 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include "NetworkAccessManager.h" NetworkAccessManager& NetworkAccessManager::getInstance() { @@ -17,4 +20,114 @@ NetworkAccessManager& NetworkAccessManager::getInstance() { } NetworkAccessManager::NetworkAccessManager() { -} \ No newline at end of file +} + +QNetworkReply* NetworkAccessManager::get(const QNetworkRequest& request) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "get", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request)); + return result; + } + return QNetworkAccessManager::get(request); +} + +QNetworkReply* NetworkAccessManager::head(const QNetworkRequest& request) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "head", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request)); + return result; + } + return QNetworkAccessManager::head(request); +} + +QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QIODevice* data) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "post", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(QIODevice*, data)); + return result; + } + return QNetworkAccessManager::post(request, data); +} + +QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, const QByteArray& data) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "post", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(const QByteArray, data)); + return result; + } + return QNetworkAccessManager::post(request, data); +} + +QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QHttpMultiPart* multiPart) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "post", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(QHttpMultiPart*, multiPart)); + return result; + } + return QNetworkAccessManager::post(request, multiPart); +} + +QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QIODevice* data) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "put", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(QIODevice*, data)); + return result; + } + return QNetworkAccessManager::put(request, data); +} + +QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QHttpMultiPart* multiPart) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "put", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(QHttpMultiPart*, multiPart)); + return result; + } + return QNetworkAccessManager::put(request, multiPart); +} + +QNetworkReply* NetworkAccessManager::put(const QNetworkRequest & request, const QByteArray & data) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "put", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(const QByteArray, data)); + return result; + } + return QNetworkAccessManager::put(request, data); +} diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index c7cc74340a..b1df269022 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -13,12 +13,23 @@ #define hifi_NetworkAccessManager_h #include +#include +#include +/// Wrapper around QNetworkAccessManager wo that we only use one instance class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: static NetworkAccessManager& getInstance(); + Q_INVOKABLE QNetworkReply* get(const QNetworkRequest& request); + Q_INVOKABLE QNetworkReply* head(const QNetworkRequest& request); + Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QIODevice* data); + Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, const QByteArray& data); + Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QHttpMultiPart* multiPart); + Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QIODevice* data); + Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QHttpMultiPart* multiPart); + Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, const QByteArray& data); private: NetworkAccessManager(); From 84ea9833bb899d2439ea26796b454ef22c53c217 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 14:30:40 -0700 Subject: [PATCH 53/80] Added forgotten sendCustomRequest Method + comments --- .../networking/src/NetworkAccessManager.cpp | 16 ++++++++++++++++ libraries/networking/src/NetworkAccessManager.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index 7c45dc69d5..b9eda27947 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -131,3 +131,19 @@ QNetworkReply* NetworkAccessManager::put(const QNetworkRequest & request, const } return QNetworkAccessManager::put(request, data); } + + +QNetworkReply* NetworkAccessManager::sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data) { + if (QThread::currentThread() != thread()) { + QNetworkReply* result; + QMetaObject::invokeMethod(this, + "sendCustomRequest", + Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QNetworkReply*, result), + Q_ARG(const QNetworkRequest, request), + Q_ARG(const QByteArray, verb), + Q_ARG(QIODevice*, data)); + return result; + } + return QNetworkAccessManager::sendCustomRequest(request, verb, data); +} \ No newline at end of file diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index b1df269022..ba97f12552 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -17,6 +17,8 @@ #include /// Wrapper around QNetworkAccessManager wo that we only use one instance +/// For any other method you should need, make sure to be on the right thread +/// or call the method using QMetaObject::invokeMethod() class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: @@ -30,6 +32,7 @@ public: Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QIODevice* data); Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QHttpMultiPart* multiPart); Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, const QByteArray& data); + Q_INVOKABLE QNetworkReply* sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data = 0); private: NetworkAccessManager(); From 1ac38c9884ee83fc3a05b272d70158c8e7e63f1d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 14:31:19 -0700 Subject: [PATCH 54/80] Switched call to setCache to invokeMethod --- assignment-client/src/Agent.cpp | 10 ++++++---- interface/src/Application.cpp | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1805a414b5..fcd983873d 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -208,12 +208,14 @@ void Agent::run() { scriptURL = QUrl(_payload); } - NetworkAccessManager& networkManager = NetworkAccessManager::getInstance(); - QNetworkReply *reply = networkManager.get(QNetworkRequest(scriptURL)); - QNetworkDiskCache* cache = new QNetworkDiskCache(&networkManager); + NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL)); + QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache"); - networkManager.setCache(cache); + QMetaObject::invokeMethod(&networkAccessManager, "setCache", + Qt::BlockingQueuedConnection, + Q_ARG(QAbstractNetworkCache*, cache)); qDebug() << "Downloading script at" << scriptURL.toString(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 10b6fc8165..7193a06125 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -317,7 +317,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkDiskCache* cache = new QNetworkDiskCache(&networkAccessManager); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); - networkAccessManager.setCache(cache); + QMetaObject::invokeMethod(&networkAccessManager, "setCache", + Qt::BlockingQueuedConnection, + Q_ARG(QAbstractNetworkCache*, cache)); ResourceCache::setRequestLimit(3); From 73312ecc5f8780ae73cc51a2319c829d89aedbb7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 2 Jul 2014 15:07:49 -0700 Subject: [PATCH 55/80] add the PitchWheel constant to the MIDIManager class --- interface/src/devices/MIDIManager.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h index a3633298a5..eddc473950 100644 --- a/interface/src/devices/MIDIManager.h +++ b/interface/src/devices/MIDIManager.h @@ -25,6 +25,8 @@ class MIDIManager : public QObject { Q_PROPERTY(unsigned int NoteOn READ NoteOn) Q_PROPERTY(unsigned int NoteOff READ NoteOff) Q_PROPERTY(unsigned int ModWheel READ ModWheel) + Q_PROPERTY(unsigned int PitchWheel READ PitchWheel) + public: static MIDIManager& getInstance(); static void midiCallback(double deltaTime, std::vector* message, void* userData); @@ -37,6 +39,7 @@ public slots: unsigned int NoteOn() const { return 144; } unsigned int NoteOff() const { return 128; } unsigned int ModWheel() const { return 176; } + unsigned int PitchWheel() const { return 224; } signals: void midiEvent(const MIDIEvent& event); From 90a27bb118dd82e31d2989089e93be9cd746b77d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 15:18:56 -0700 Subject: [PATCH 56/80] Removed json callback --- libraries/networking/src/UserActivityLogger.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index aa18cb43ee..5b20c82263 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -83,17 +83,10 @@ void UserActivityLogger::close(int delayTime) { // In order to get the end of the session, we need to give the account manager enough time to send the packet. QEventLoop loop; - // Here we connect the callbacks to stop the event loop - JSONCallbackParameters params; - params.jsonCallbackReceiver = &loop; - params.errorCallbackReceiver = &loop; - params.jsonCallbackMethod = "quit"; - params.errorCallbackMethod = "quit"; - // In case something goes wrong, we also setup a timer so that the delai is not greater than delayTime QTimer timer; connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); // Now we can log it - logAction(ACTION_NAME, QJsonObject(), params); + logAction(ACTION_NAME, QJsonObject()); timer.start(delayTime); loop.exec(); } From 45db5e2c40b610b86a100aa6c9ea82d8b539a5b0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 15:57:11 -0700 Subject: [PATCH 57/80] Removed Xcode warnings --- interface/src/ScriptsModel.cpp | 2 -- libraries/particles/src/ParticleCollisionSystem.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index f9ed94f3fa..7e57d2971e 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -30,8 +30,6 @@ static const QString IS_TRUNCATED_NAME = "IsTruncated"; static const QString CONTAINER_NAME = "Contents"; static const QString KEY_NAME = "Key"; -static const int SCRIPT_PATH = Qt::UserRole; - ScriptItem::ScriptItem(const QString& filename, const QString& fullPath) : _filename(filename), _fullPath(fullPath) { diff --git a/libraries/particles/src/ParticleCollisionSystem.cpp b/libraries/particles/src/ParticleCollisionSystem.cpp index d8d5887d97..0291690c3d 100644 --- a/libraries/particles/src/ParticleCollisionSystem.cpp +++ b/libraries/particles/src/ParticleCollisionSystem.cpp @@ -183,7 +183,6 @@ void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) // MIN_VALID_SPEED is obtained by computing speed gained at one gravity after the shortest expected frame const float MIN_EXPECTED_FRAME_PERIOD = 0.0167f; // 1/60th of a second -const float HALTING_SPEED = 9.8 * MIN_EXPECTED_FRAME_PERIOD / (float)(TREE_SCALE); void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) { // particles that are in hand, don't collide with avatars From 1815472c6b99698a5bda5a47916ec3f723d81224 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 16:12:39 -0700 Subject: [PATCH 58/80] Modified recently added case to AccountManager --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 7cae1991a9..563d735790 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -205,7 +205,7 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: break; case QNetworkAccessManager::DeleteOperation: - networkReply = _networkAccessManager->sendCustomRequest(authenticatedRequest, "DELETE"); + networkReply = networkAccessManager.sendCustomRequest(authenticatedRequest, "DELETE"); break; default: // other methods not yet handled From a859094d4a6e930aa718ababb89c556c6da80394 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 16:40:02 -0700 Subject: [PATCH 59/80] Clickable 3D UI in 3DTV --- interface/src/Application.cpp | 2 +- interface/src/devices/TV3DManager.cpp | 5 ---- interface/src/ui/ApplicationOverlay.cpp | 34 ++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b48d35c5e8..b24c3ac949 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1130,7 +1130,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { _lastMouseMove = usecTimestampNow(); - if (_mouseHidden && showMouse && !OculusManager::isConnected()) { + if (_mouseHidden && showMouse && !OculusManager::isConnected() && !TV3DManager::isConnected()) { getGLWidget()->setCursor(Qt::ArrowCursor); _mouseHidden = false; _seenMouseMove = true; diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index 98fe3ac6d4..25d3ff892a 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -124,9 +124,6 @@ void TV3DManager::display(Camera& whichCamera) { GLfloat fov = atan(1.0f / cotangent); glTranslatef(_leftEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax - - printf("FOV %f\n", fov); - glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); @@ -153,8 +150,6 @@ void TV3DManager::display(Camera& whichCamera) { GLfloat fov = atan(1.0f / cotangent); glTranslatef(_rightEye.modelTranslation, 0.0, 0.0); // translate to cancel parallax - printf("FOV %f\n", fov); - glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Application::getInstance()->displaySide(whichCamera); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 07582e2781..44a83e164a 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -335,15 +335,17 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glColor4f(1.0f, 1.0f, 1.0f, _alpha); //Render + // fov -= RADIANS_PER_DEGREE * 2.5f; //reduce by 5 degrees so it fits in the view const GLfloat distance = 1.0f; - const GLfloat halfQuadHeight = atan(fov) * distance; + const GLfloat halfQuadHeight = distance * tan(fov); const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; const GLfloat quadWidth = halfQuadWidth * 2.0f; const GLfloat quadHeight = halfQuadHeight * 2.0f; - const GLfloat x = -halfQuadWidth; - const GLfloat y = -halfQuadHeight; + GLfloat x = -halfQuadWidth; + GLfloat y = -halfQuadHeight; + glDisable(GL_DEPTH_TEST); glBegin(GL_QUADS); @@ -354,6 +356,32 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glEnd(); + if (_crosshairTexture == 0) { + _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); + } + + //draw the mouse pointer + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); + + const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; + x -= reticleSize / 2.0f; + y += reticleSize / 2.0f; + const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth; + const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight; + + glBegin(GL_QUADS); + + glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); + + glTexCoord2d(0.0f, 0.0f); glVertex3f(x + mouseX, y + mouseY, -distance); + glTexCoord2d(1.0f, 0.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY, -distance); + glTexCoord2d(1.0f, 1.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance); + glTexCoord2d(0.0f, 1.0f); glVertex3f(x + mouseX, y + mouseY - reticleSize, -distance); + + glEnd(); + + glEnable(GL_DEPTH_TEST); + glPopMatrix(); glDepthMask(GL_TRUE); From ee30a446e9f21a84cf27ab2008d09cb84f9c123c Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 16:45:05 -0700 Subject: [PATCH 60/80] Fixed 3rd person camera for non oculus --- interface/src/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b24c3ac949..ab6d1d1e20 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -586,7 +586,11 @@ void Application::paintGL() { //Note, the camera distance is set in Camera::setMode() so we dont have to do it here. _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); - _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation()); + if (OculusManager::isConnected()) { + _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation()); + } else { + _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation()); + } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness(0.0f); From edcf4d04f8f0396c119ca2668969f9c334f47ab7 Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 2 Jul 2014 17:05:06 -0700 Subject: [PATCH 61/80] Fixed bug when switching from normal view to oculus --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab6d1d1e20..7cfadc1ff2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -634,6 +634,10 @@ void Application::paintGL() { //If we aren't using the glow shader, we have to clear the color and depth buffer if (!glowEnabled) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } else if (OculusManager::isConnected()) { + //Clear the color buffer to ensure that there isnt any residual color + //Left over from when OR was not connected. + glClear(GL_COLOR_BUFFER_BIT); } if (OculusManager::isConnected()) { From 69533c25c2f3d10098566424cbac1e97ae58e88d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Jul 2014 17:54:21 -0700 Subject: [PATCH 62/80] Fix script not being loaded at startup --- interface/src/Application.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f8fbbae56..6c1982f328 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -398,18 +398,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : } Application::~Application() { + qInstallMessageHandler(NULL); + + saveSettings(); + storeSizeAndPosition(); + saveScripts(); + int DELAY_TIME = 1000; UserActivityLogger::getInstance().close(DELAY_TIME); - qInstallMessageHandler(NULL); - // make sure we don't call the idle timer any more delete idleTimer; - + _sharedVoxelSystem.changeTree(new VoxelTree); - - saveSettings(); - delete _voxelImporter; // let the avatar mixer know we're out @@ -432,8 +433,6 @@ Application::~Application() { _particleEditSender.terminate(); _modelEditSender.terminate(); - storeSizeAndPosition(); - saveScripts(); VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); From 356a29c2fbb82f2a3080e4b71f7e66f177ff9536 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 3 Jul 2014 08:40:34 -0700 Subject: [PATCH 63/80] add AngularConstraint::softClamp() for hands --- interface/src/renderer/JointState.cpp | 13 +++- interface/src/renderer/JointState.h | 2 +- interface/src/renderer/Model.cpp | 2 +- libraries/shared/src/AngularConstraint.cpp | 34 +++++++-- libraries/shared/src/AngularConstraint.h | 8 +- tests/shared/src/AngularConstraintTests.cpp | 84 ++++++++++----------- 6 files changed, 88 insertions(+), 55 deletions(-) diff --git a/interface/src/renderer/JointState.cpp b/interface/src/renderer/JointState.cpp index 6cb58f0664..429084480d 100644 --- a/interface/src/renderer/JointState.cpp +++ b/interface/src/renderer/JointState.cpp @@ -24,9 +24,9 @@ JointState::JointState() : } JointState::JointState(const JointState& other) : _constraint(NULL) { - _rotationInParentFrame = other._rotationInParentFrame; _transform = other._transform; _rotation = other._rotation; + _rotationInParentFrame = other._rotationInParentFrame; _animationPriority = other._animationPriority; _fbxJoint = other._fbxJoint; // DO NOT copy _constraint @@ -102,11 +102,15 @@ void JointState::restoreRotation(float fraction, float priority) { } } -void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) { +void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority, bool constrain) { // rotation is from bind- to model-frame assert(_fbxJoint != NULL); if (priority >= _animationPriority) { - setRotationInParentFrame(_rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation)); + glm::quat targetRotation = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation); + if (constrain && _constraint) { + _constraint->softClamp(targetRotation, _rotationInParentFrame, 0.5f); + } + setRotationInParentFrame(targetRotation); _animationPriority = priority; } } @@ -154,6 +158,9 @@ void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float if (mixFactor > 0.0f && mixFactor <= 1.0f) { targetRotation = safeMix(targetRotation, _fbxJoint->rotation, mixFactor); } + if (_constraint) { + _constraint->softClamp(targetRotation, _rotationInParentFrame, 0.5f); + } setRotationInParentFrame(targetRotation); } diff --git a/interface/src/renderer/JointState.h b/interface/src/renderer/JointState.h index 5e8c8704fc..3bd752cdff 100644 --- a/interface/src/renderer/JointState.h +++ b/interface/src/renderer/JointState.h @@ -68,7 +68,7 @@ public: /// \param rotation is from bind- to model-frame /// computes and sets new _rotationInParentFrame /// NOTE: the JointState's model-frame transform/rotation are NOT updated! - void setRotationFromBindFrame(const glm::quat& rotation, float priority); + void setRotationFromBindFrame(const glm::quat& rotation, float priority, bool constrain = false); void setRotationInParentFrame(const glm::quat& targetRotation); const glm::quat& getRotationInParentFrame() const { return _rotationInParentFrame; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index c47fd0893f..1d822c7ed1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1216,7 +1216,7 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } while (numIterations < MAX_ITERATION_COUNT && distanceToGo < ACCEPTABLE_IK_ERROR); // set final rotation of the end joint - endState.setRotationFromBindFrame(targetRotation, priority); + endState.setRotationFromBindFrame(targetRotation, priority, true); _shapesAreDirty = !_shapes.isEmpty(); } diff --git a/libraries/shared/src/AngularConstraint.cpp b/libraries/shared/src/AngularConstraint.cpp index 48649450e1..4689568ac8 100644 --- a/libraries/shared/src/AngularConstraint.cpp +++ b/libraries/shared/src/AngularConstraint.cpp @@ -74,6 +74,26 @@ AngularConstraint* AngularConstraint::newAngularConstraint(const glm::vec3& minA return NULL; } +bool AngularConstraint::softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction) { + glm::quat clampedTarget = targetRotation; + bool clamped = clamp(clampedTarget); + if (clamped) { + // check if oldRotation is also clamped + glm::quat clampedOld = oldRotation; + bool clamped2 = clamp(clampedOld); + if (clamped2) { + // oldRotation is already beyond the constraint + // we clamp again midway between targetRotation and clamped oldPosition + clampedTarget = glm::shortMix(clampedOld, targetRotation, mixFraction); + // and then clamp that + clamp(clampedTarget); + } + // finally we mix targetRotation with the clampedTarget + targetRotation = glm::shortMix(clampedTarget, targetRotation, mixFraction); + } + return clamped; +} + HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle) : _minAngle(minAngle), _maxAngle(maxAngle) { assert(_minAngle < _maxAngle); @@ -87,7 +107,7 @@ HingeConstraint::HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& } // virtual -bool HingeConstraint::applyTo(glm::quat& rotation) const { +bool HingeConstraint::clamp(glm::quat& rotation) const { glm::vec3 forward = rotation * _forwardAxis; forward -= glm::dot(forward, _rotationAxis) * _rotationAxis; float length = glm::length(forward); @@ -108,6 +128,11 @@ bool HingeConstraint::applyTo(glm::quat& rotation) const { return false; } +bool HingeConstraint::softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction) { + // the hinge works best without a soft clamp + return clamp(targetRotation); +} + ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll) : _coneAngle(coneAngle), _minRoll(minRoll), _maxRoll(maxRoll) { assert(_maxRoll >= _minRoll); @@ -117,7 +142,7 @@ ConeRollerConstraint::ConeRollerConstraint(float coneAngle, const glm::vec3& con } // virtual -bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { +bool ConeRollerConstraint::clamp(glm::quat& rotation) const { bool applied = false; glm::vec3 rotatedAxis = rotation * _coneAxis; glm::vec3 perpAxis = glm::cross(rotatedAxis, _coneAxis); @@ -131,8 +156,7 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { rotatedAxis = rotation * _coneAxis; applied = true; } - } - else { + } else { // the rotation is 100% roll // there is no obvious perp axis so we must pick one perpAxis = rotatedAxis; @@ -168,7 +192,7 @@ bool ConeRollerConstraint::applyTo(glm::quat& rotation) const { float roll = sign * angleBetween(rolledPerpAxis, perpAxis); if (roll < _minRoll || roll > _maxRoll) { float clampedRoll = clampAngle(roll, _minRoll, _maxRoll); - rotation = glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation; + rotation = glm::normalize(glm::angleAxis(clampedRoll - roll, rotatedAxis) * rotation); applied = true; } return applied; diff --git a/libraries/shared/src/AngularConstraint.h b/libraries/shared/src/AngularConstraint.h index 8003e4c9a3..929a58959b 100644 --- a/libraries/shared/src/AngularConstraint.h +++ b/libraries/shared/src/AngularConstraint.h @@ -24,14 +24,16 @@ public: AngularConstraint() {} virtual ~AngularConstraint() {} - virtual bool applyTo(glm::quat& rotation) const = 0; + virtual bool clamp(glm::quat& rotation) const = 0; + virtual bool softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction); protected: }; class HingeConstraint : public AngularConstraint { public: HingeConstraint(const glm::vec3& forwardAxis, const glm::vec3& rotationAxis, float minAngle, float maxAngle); - virtual bool applyTo(glm::quat& rotation) const; + virtual bool clamp(glm::quat& rotation) const; + virtual bool softClamp(glm::quat& targetRotation, const glm::quat& oldRotation, float mixFraction); protected: glm::vec3 _forwardAxis; glm::vec3 _rotationAxis; @@ -42,7 +44,7 @@ protected: class ConeRollerConstraint : public AngularConstraint { public: ConeRollerConstraint(float coneAngle, const glm::vec3& coneAxis, float minRoll, float maxRoll); - virtual bool applyTo(glm::quat& rotation) const; + virtual bool clamp(glm::quat& rotation) const; private: float _coneAngle; glm::vec3 _coneAxis; diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index d6a9214acc..00916a7267 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -36,10 +36,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -51,10 +51,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -66,10 +66,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should not applyTo()" << std::endl; + << " ERROR: HingeConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -81,10 +81,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -102,10 +102,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -123,10 +123,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -144,10 +144,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -169,10 +169,10 @@ void AngularConstraintTests::testHingeConstraint() { glm::quat rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -193,10 +193,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -217,10 +217,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -241,10 +241,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -265,10 +265,10 @@ void AngularConstraintTests::testHingeConstraint() { rotation = offRotation * glm::angleAxis(angle, yAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: HingeConstraint should applyTo()" << std::endl; + << " ERROR: HingeConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -315,10 +315,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation(angles); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -330,10 +330,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(expectedConeAngle - deltaAngle, perpAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -344,10 +344,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -358,10 +358,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -372,10 +372,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should not applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should not clamp()" << std::endl; } if (rotation != newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -386,10 +386,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -405,10 +405,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis); glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -427,10 +427,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = pitchYaw * roll; glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ @@ -450,10 +450,10 @@ void AngularConstraintTests::testConeRollerConstraint() { glm::quat rotation = pitchYaw * roll; glm::quat newRotation = rotation; - bool constrained = c->applyTo(newRotation); + bool constrained = c->clamp(newRotation); if (!constrained) { std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: ConeRollerConstraint should applyTo()" << std::endl; + << " ERROR: ConeRollerConstraint should clamp()" << std::endl; } if (rotation == newRotation) { std::cout << __FILE__ << ":" << __LINE__ From 55dd2a4835be6d86fa9a235eef920b246209baf5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 3 Jul 2014 09:10:23 -0700 Subject: [PATCH 64/80] re-enable gravity effect on arm IK --- interface/src/renderer/Model.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1d822c7ed1..86d742c949 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1158,14 +1158,9 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } glm::quat deltaRotation = rotationBetween(leverArm, targetPosition - pivot); - /* DON'T REMOVE! This code provides the gravitational effect on the IK solution. - * It is commented out for the moment because we're blending the IK solution with - * the default pose which provides similar stability, but we might want to use - * gravity again later. - - // We want to mix the shortest rotation with one that will pull the system down with gravity. - // So we compute a simplified center of mass, where each joint has a mass of 1.0 and we don't - // bother averaging it because we only need direction. + // We want to mix the shortest rotation with one that will pull the system down with gravity + // so that limbs don't float unrealistically. To do this we compute a simplified center of mass + // where each joint has unit mass and we don't bother averaging it because we only need direction. if (j > 1) { glm::vec3 centerOfMass(0.0f); @@ -1187,11 +1182,9 @@ void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm: } deltaRotation = safeMix(deltaRotation, gravityDelta, mixFactor); } - */ // Apply the rotation, but use mixRotationDelta() which blends a bit of the default pose - // at in the process. This provides stability to the IK solution and removes the necessity - // for the gravity effect. + // at in the process. This provides stability to the IK solution for most models. glm::quat oldNextRotation = nextState.getRotation(); float mixFactor = 0.03f; nextState.mixRotationDelta(deltaRotation, mixFactor, priority); From 20cdc0e3cabece8351810f4b48680736719be696 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Jul 2014 10:30:21 -0700 Subject: [PATCH 65/80] Fix wrong slot names in ModelBrowser --- interface/src/ui/ModelsBrowser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index ec583a14f7..a803625206 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -214,7 +214,7 @@ void ModelHandler::update() { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.head(request); - connect(reply, SIGNAL(finished()), SLOT(processCheck())); + connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); } _lock.unlock(); } @@ -266,7 +266,7 @@ void ModelHandler::queryNewFiles(QString marker) { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.get(request); - connect(reply, SIGNAL(finished()), SLOT(processCheck())); + connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); } From 059628c26a6a083f90c86bcb6402f63cd1656518 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 3 Jul 2014 10:37:09 -0700 Subject: [PATCH 66/80] fixed bug in SequenceNumberStats and its unit test; test passes now --- libraries/networking/src/SequenceNumberStats.cpp | 3 +-- tests/networking/src/SequenceNumberStatsTests.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 5bdeedf39d..5174d53ba2 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -94,6 +94,7 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU _numEarly++; _numLost += (incomingInt - expectedInt); + _lastReceived = incoming; // add all sequence numbers that were skipped to the missing sequence numbers list for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) { @@ -105,8 +106,6 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) { pruneMissingSet(wantExtraDebugging); } - - _lastReceived = incoming; } else { // late if (wantExtraDebugging) { qDebug() << "this packet is later than expected..."; diff --git a/tests/networking/src/SequenceNumberStatsTests.cpp b/tests/networking/src/SequenceNumberStatsTests.cpp index 89a14deb20..8d37a3e41f 100644 --- a/tests/networking/src/SequenceNumberStatsTests.cpp +++ b/tests/networking/src/SequenceNumberStatsTests.cpp @@ -115,6 +115,11 @@ void SequenceNumberStatsTests::earlyLateTest() { } } stats.reset(); + numSent = 0; + numEarly = 0; + numLate = 0; + numLost = 0; + numRecovered = 0; } } @@ -203,6 +208,11 @@ void SequenceNumberStatsTests::duplicateTest() { } } stats.reset(); + numSent = 0; + numDuplicate = 0; + numEarly = 0; + numLate = 0; + numLost = 0; } } @@ -263,5 +273,8 @@ void SequenceNumberStatsTests::pruneTest() { } } stats.reset(); + numSent = 0; + numEarly = 0; + numLost = 0; } } From a2451a96516ed1b4f365cdfd7ec158b145430cc2 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 3 Jul 2014 10:41:54 -0700 Subject: [PATCH 67/80] moved and updated a comment in SequenceNumberStats --- libraries/networking/src/SequenceNumberStats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 5174d53ba2..3f696a522b 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -112,6 +112,8 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU } _numLate++; + // do not update _lastReceived; it shouldn't become smaller + // remove this from missing sequence number if it's in there if (_missingSet.remove(incoming)) { if (wantExtraDebugging) { @@ -125,8 +127,6 @@ void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderU } _numDuplicate++; } - - // do not update _incomingLastSequence; it shouldn't become smaller } } } From 0af79c4d95f9fe246b2d87cc5d92590d39bf903e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 10:45:05 -0700 Subject: [PATCH 68/80] fix for script agent audio missing channel flag --- assignment-client/src/audio/AudioMixer.cpp | 1 + libraries/script-engine/src/ScriptEngine.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1c3046b9b1..a38f3b6e4b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -99,6 +99,7 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf bool shouldAttenuate = (bufferToAdd != listeningNodeBuffer); if (shouldAttenuate) { + // if the two buffer pointers do not match then these are different buffers glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index daf66dafbe..7a6a251297 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1,3 +1,4 @@ + // // ScriptEngine.cpp // libraries/script-engine/src @@ -469,7 +470,10 @@ void ScriptEngine::run() { // pack a placeholder value for sequence number for now, will be packed when destination node is known int numPreSequenceNumberBytes = audioPacket.size(); - packetStream << (quint16)0; + packetStream << (quint16) 0; + + // assume scripted avatar audio is mono and set channel flag to zero + packetStream << (quint8) 0; // use the orientation and position of this avatar for the source of this audio packetStream.writeRawData(reinterpret_cast(&_avatarData->getPosition()), sizeof(glm::vec3)); From 0a3a8b069358f981213ec8365c6786441a97a952 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 10:45:43 -0700 Subject: [PATCH 69/80] remove space at the top of the ScriptEngine file --- libraries/script-engine/src/ScriptEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 7a6a251297..4154c4d415 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1,4 +1,3 @@ - // // ScriptEngine.cpp // libraries/script-engine/src From fe52787572002ba9e4e178da994f36bcf695486c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 11:05:12 -0700 Subject: [PATCH 70/80] implement a new rolloff function --- assignment-client/src/audio/AudioMixer.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1c3046b9b1..59c5d15582 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -89,6 +89,9 @@ AudioMixer::~AudioMixer() { delete _listenerUnattenuatedZone; } +const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f; +const float ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE = 0.18f; + void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, AvatarAudioRingBuffer* listeningNodeBuffer) { float bearingRelativeAngleToSource = 0.0f; @@ -162,16 +165,9 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; - const float DISTANCE_SCALE = 2.5f; - const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; - const float DISTANCE_LOG_BASE = 2.5f; - const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); - // calculate the distance coefficient using the distance to this node - float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, - DISTANCE_SCALE_LOG + - (0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); - distanceCoefficient = std::min(1.0f, distanceCoefficient); + float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f) + * ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE); // multiply the current attenuation coefficient by the distance coefficient attenuationCoefficient *= distanceCoefficient; From 507518f16d90128413bf617d699af4220b062477 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 3 Jul 2014 11:11:56 -0700 Subject: [PATCH 71/80] removed numFramesCapacity from being exposed everywhere --- assignment-client/src/Agent.cpp | 4 +--- assignment-client/src/audio/AudioMixerClientData.cpp | 7 ++----- assignment-client/src/audio/AvatarAudioRingBuffer.cpp | 4 ++-- assignment-client/src/audio/AvatarAudioRingBuffer.h | 2 +- interface/src/Audio.cpp | 6 ++---- libraries/audio/src/AudioRingBuffer.cpp | 2 +- libraries/audio/src/AudioRingBuffer.h | 4 +++- libraries/audio/src/InjectedAudioRingBuffer.cpp | 4 ++-- libraries/audio/src/InjectedAudioRingBuffer.h | 2 +- libraries/audio/src/MixedAudioRingBuffer.cpp | 4 ++-- libraries/audio/src/MixedAudioRingBuffer.h | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 5 ++--- libraries/audio/src/PositionalAudioRingBuffer.h | 5 +++-- 13 files changed, 23 insertions(+), 28 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 25c775f14b..5720ecaaf5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -31,14 +31,12 @@ #include "Agent.h" -static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 10; - Agent::Agent(const QByteArray& packet) : ThreadedAssignment(packet), _voxelEditSender(), _particleEditSender(), _modelEditSender(), - _receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, AUDIO_RING_BUFFER_CAPACITY_FRAMES), + _receivedAudioBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), _avatarHashMap() { // be the parent of the script engine so it gets moved when we do diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b8f4d18b1d..f6437f9c97 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -19,8 +19,6 @@ #include "AudioMixer.h" #include "AudioMixerClientData.h" -static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 100; - AudioMixerClientData::AudioMixerClientData() : _ringBuffers(), _outgoingMixedAudioSequenceNumber(0), @@ -78,7 +76,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { if (!avatarRingBuffer) { // we don't have an AvatarAudioRingBuffer yet, so add it - avatarRingBuffer = new AvatarAudioRingBuffer(AUDIO_RING_BUFFER_CAPACITY_FRAMES, isStereo, AudioMixer::getUseDynamicJitterBuffers()); + avatarRingBuffer = new AvatarAudioRingBuffer(isStereo, AudioMixer::getUseDynamicJitterBuffers()); _ringBuffers.push_back(avatarRingBuffer); } @@ -103,8 +101,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { if (!matchingInjectedRingBuffer) { // we don't have a matching injected audio ring buffer, so add it - matchingInjectedRingBuffer = new InjectedAudioRingBuffer(AUDIO_RING_BUFFER_CAPACITY_FRAMES, streamIdentifier, - AudioMixer::getUseDynamicJitterBuffers()); + matchingInjectedRingBuffer = new InjectedAudioRingBuffer(streamIdentifier, AudioMixer::getUseDynamicJitterBuffers()); _ringBuffers.push_back(matchingInjectedRingBuffer); } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index a3e15c7f9e..9c6cc32f57 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -13,8 +13,8 @@ #include "AvatarAudioRingBuffer.h" -AvatarAudioRingBuffer::AvatarAudioRingBuffer(int numFramesCapacity, bool isStereo, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(numFramesCapacity, PositionalAudioRingBuffer::Microphone, isStereo, dynamicJitterBuffer) { +AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo, bool dynamicJitterBuffer) : + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone, isStereo, dynamicJitterBuffer) { } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index 816fd937a6..e227e70958 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -18,7 +18,7 @@ class AvatarAudioRingBuffer : public PositionalAudioRingBuffer { public: - AvatarAudioRingBuffer(int numFramesCapacity, bool isStereo = false, bool dynamicJitterBuffer = false); + AvatarAudioRingBuffer(bool isStereo = false, bool dynamicJitterBuffer = false); int parseData(const QByteArray& packet); private: diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1ae3b5b8e6..98987f2d0a 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -48,8 +48,6 @@ static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_ static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; -static const int AUDIO_RING_BUFFER_CAPACITY_FRAMES = 10; - // Mute icon configration static const int MUTE_ICON_SIZE = 24; @@ -68,8 +66,8 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _loopbackOutputDevice(NULL), _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), - _inputRingBuffer(0, AUDIO_RING_BUFFER_CAPACITY_FRAMES), - _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, AUDIO_RING_BUFFER_CAPACITY_FRAMES), + _inputRingBuffer(0), + _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 56b6725745..636ee76844 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -19,7 +19,7 @@ #include "AudioRingBuffer.h" -AudioRingBuffer::AudioRingBuffer(int numFrameSamples, int numFramesCapacity, bool randomAccessMode) : +AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : NodeData(), _overflowCount(0), _frameCapacity(numFramesCapacity), diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 0bf5e2d1d6..0a6a123b71 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -34,10 +34,12 @@ const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SA const int MAX_SAMPLE_VALUE = std::numeric_limits::max(); const int MIN_SAMPLE_VALUE = std::numeric_limits::min(); +const int DEFAULT_RING_BUFFER_FRAME_CAPACITY = 10; + class AudioRingBuffer : public NodeData { Q_OBJECT public: - AudioRingBuffer(int numFrameSamples, int numFramesCapacity, bool randomAccessMode = false); + AudioRingBuffer(int numFrameSamples, bool randomAccessMode = false, int numFramesCapacity = DEFAULT_RING_BUFFER_FRAME_CAPACITY); ~AudioRingBuffer(); void reset(); diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 77688506dd..c84fe173c9 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -19,8 +19,8 @@ #include "InjectedAudioRingBuffer.h" -InjectedAudioRingBuffer::InjectedAudioRingBuffer(int numFramesCapacity, const QUuid& streamIdentifier, bool dynamicJitterBuffer) : - PositionalAudioRingBuffer(numFramesCapacity, PositionalAudioRingBuffer::Injector, false, dynamicJitterBuffer), +InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier, bool dynamicJitterBuffer) : + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Injector, false, dynamicJitterBuffer), _streamIdentifier(streamIdentifier), _radius(0.0f), _attenuationRatio(0) diff --git a/libraries/audio/src/InjectedAudioRingBuffer.h b/libraries/audio/src/InjectedAudioRingBuffer.h index 64862b6963..4e3fea672b 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.h +++ b/libraries/audio/src/InjectedAudioRingBuffer.h @@ -18,7 +18,7 @@ class InjectedAudioRingBuffer : public PositionalAudioRingBuffer { public: - InjectedAudioRingBuffer(int numFramesCapacity, const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false); + InjectedAudioRingBuffer(const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false); int parseData(const QByteArray& packet); diff --git a/libraries/audio/src/MixedAudioRingBuffer.cpp b/libraries/audio/src/MixedAudioRingBuffer.cpp index fb414ee387..c975d7b68e 100644 --- a/libraries/audio/src/MixedAudioRingBuffer.cpp +++ b/libraries/audio/src/MixedAudioRingBuffer.cpp @@ -11,8 +11,8 @@ #include "MixedAudioRingBuffer.h" -MixedAudioRingBuffer::MixedAudioRingBuffer(int numFrameSamples, int numFramesCapacity) : - AudioRingBuffer(numFrameSamples, numFramesCapacity), +MixedAudioRingBuffer::MixedAudioRingBuffer(int numFrameSamples) : + AudioRingBuffer(numFrameSamples), _lastReadFrameAverageLoudness(0.0f) { diff --git a/libraries/audio/src/MixedAudioRingBuffer.h b/libraries/audio/src/MixedAudioRingBuffer.h index 4ebe4d577e..25574a3ea6 100644 --- a/libraries/audio/src/MixedAudioRingBuffer.h +++ b/libraries/audio/src/MixedAudioRingBuffer.h @@ -17,7 +17,7 @@ class MixedAudioRingBuffer : public AudioRingBuffer { Q_OBJECT public: - MixedAudioRingBuffer(int numFrameSamples, int numFramesCapacity); + MixedAudioRingBuffer(int numFrameSamples); float getLastReadFrameAverageLoudness() const { return _lastReadFrameAverageLoudness; } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index e1e85721f0..8f3030782f 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -85,11 +85,10 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() { } -PositionalAudioRingBuffer::PositionalAudioRingBuffer(int numFramesCapacity, PositionalAudioRingBuffer::Type type, - bool isStereo, bool dynamicJitterBuffers) : +PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo, bool dynamicJitterBuffers) : AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, - numFramesCapacity), + AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index ac56d8487c..6a7c4b492a 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -43,6 +43,8 @@ private: bool _newWindowMaxGapAvailable; }; +const int AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY = 100; + class PositionalAudioRingBuffer : public AudioRingBuffer { public: enum Type { @@ -50,8 +52,7 @@ public: Injector }; - PositionalAudioRingBuffer(int numFramesCapacity, PositionalAudioRingBuffer::Type type, - bool isStereo = false, bool dynamicJitterBuffers = false); + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false, bool dynamicJitterBuffers = false); int parseData(const QByteArray& packet); int parsePositionalData(const QByteArray& positionalByteArray); From ef9bb85f8aaf946f5cf2417b42f070cd2c53b793 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 11:16:01 -0700 Subject: [PATCH 72/80] fix so domain-server doesn't open missing config file --- domain-server/src/DomainServerSettingsManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index d7e2e05ca8..f9996aa0e7 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -36,9 +36,12 @@ DomainServerSettingsManager::DomainServerSettingsManager() : // load the existing config file to get the current values QFile configFile(QCoreApplication::applicationDirPath() + SETTINGS_CONFIG_FILE_RELATIVE_PATH); - configFile.open(QIODevice::ReadOnly); - _settingsMap = QJsonDocument::fromJson(configFile.readAll()).toVariant().toMap(); + if (configFile.exists()) { + configFile.open(QIODevice::ReadOnly); + + _settingsMap = QJsonDocument::fromJson(configFile.readAll()).toVariant().toMap(); + } } const QString DESCRIPTION_SETTINGS_KEY = "settings"; From 2c6b2000b2733250ad3cc7d228f090840314741c Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 3 Jul 2014 11:34:16 -0700 Subject: [PATCH 73/80] forgot arg in AudioRingBuffer constructor in PositionalAudioRingBUffer changed _currentJitterBufferFrames to be -1 to indicate starved. --- libraries/audio/src/PositionalAudioRingBuffer.cpp | 8 ++++---- libraries/audio/src/PositionalAudioRingBuffer.h | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 8f3030782f..def71b7d90 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -88,7 +88,7 @@ quint64 InterframeTimeGapStats::getWindowMaxGap() { PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo, bool dynamicJitterBuffers) : AudioRingBuffer(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, - AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY), + false, AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), @@ -98,7 +98,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _isStereo(isStereo), _listenerUnattenuatedZone(NULL), _desiredJitterBufferFrames(1), - _currentJitterBufferFrames(0), + _currentJitterBufferFrames(-1), _dynamicJitterBuffers(dynamicJitterBuffers) { } @@ -216,8 +216,8 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // if the buffer doesn't have a full frame of samples to take for mixing, it is starved _isStarved = true; - // set to 0 to indicate the jitter buffer is starved - _currentJitterBufferFrames = 0; + // set to -1 to indicate the jitter buffer is starved + _currentJitterBufferFrames = -1; // reset our _shouldOutputStarveDebug to true so the next is printed _shouldOutputStarveDebug = true; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 6a7c4b492a..0322afb47b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -105,6 +105,11 @@ protected: int _desiredJitterBufferFrames; int _currentJitterBufferFrames; bool _dynamicJitterBuffers; + + // extra stats + int _starveCount; + int _silentFramesDropped; + }; #endif // hifi_PositionalAudioRingBuffer_h From 411733feb72c9dd4c00fb20f3948784a9b1604eb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 11:34:39 -0700 Subject: [PATCH 74/80] make sure NetworkAccessManager singleton is on main AC thread --- assignment-client/src/AssignmentClient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index da1feda7a0..f7594e97f2 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -104,6 +104,8 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // connections to AccountManager for authentication connect(&AccountManager::getInstance(), &AccountManager::authRequired, this, &AssignmentClient::handleAuthenticationRequest); + + NetworkAccessManager::getInstance(); } void AssignmentClient::sendAssignmentRequest() { From a53d007c3383668e7582d7cd163d30358c00414c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 3 Jul 2014 11:59:18 -0700 Subject: [PATCH 75/80] add support for getting current animation details for running avatar animations --- interface/src/avatar/MyAvatar.cpp | 34 ++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 3 ++ interface/src/renderer/Model.h | 9 ++++++ libraries/animation/src/AnimationCache.cpp | 24 ++++++++++++++ libraries/animation/src/AnimationCache.h | 33 +++++++++++++++++++ libraries/script-engine/src/ScriptEngine.cpp | 2 ++ 6 files changed, 105 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7599baf7da..6cb6ba6840 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -551,6 +551,40 @@ void MyAvatar::stopAnimation(const QString& url) { } } +AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) { + AnimationDetails result; + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AnimationDetails, result), + Q_ARG(const QString&, role)); + return result; + } + foreach (const AnimationHandlePointer& handle, _skeletonModel.getRunningAnimations()) { + if (handle->getRole() == role) { + result = handle->getAnimationDetails(); + break; + } + } + return result; +} + +AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { + AnimationDetails result; + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AnimationDetails, result), + Q_ARG(const QString&, url)); + return result; + } + foreach (const AnimationHandlePointer& handle, _skeletonModel.getRunningAnimations()) { + if (handle->getURL() == url) { + result = handle->getAnimationDetails(); + break; + } + } + return result; +} + void MyAvatar::saveData(QSettings* settings) { settings->beginGroup("Avatar"); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0ee76c6b45..0b2254bafa 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -83,6 +83,9 @@ public: /// Stops an animation identified by its role. Q_INVOKABLE void stopAnimationByRole(const QString& role); + + Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role); + Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url); // get/set avatar data void saveData(QSettings* settings); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 835207b7eb..538babb541 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -354,6 +354,15 @@ public: void setRunning(bool running); bool isRunning() const { return _running; } + void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } + float getFrameIndex() const { return _frameIndex; } + + AnimationDetails getAnimationDetails() const { + AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, + _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); + return details; + } + signals: void runningChanged(bool running); diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index ce7e4cdf36..ddf27af352 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -102,3 +102,27 @@ void Animation::downloadFinished(QNetworkReply* reply) { QThreadPool::globalInstance()->start(new AnimationReader(_self, reply)); } + +QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) { + QScriptValue obj = engine->newObject(); + obj.setProperty("role", details.role); + obj.setProperty("url", details.url.toString()); + obj.setProperty("fps", details.fps); + obj.setProperty("priority", details.priority); + obj.setProperty("loop", details.loop); + obj.setProperty("hold", details.hold); + obj.setProperty("startAutomatically", details.startAutomatically); + obj.setProperty("firstFrame", details.firstFrame); + obj.setProperty("lastFrame", details.lastFrame); + obj.setProperty("running", details.running); + obj.setProperty("frameIndex", details.frameIndex); + + + + return obj; +} + +void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) { + // nothing for now... +} + diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index 392443e7b5..b4aee5f9e3 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -12,6 +12,9 @@ #ifndef hifi_AnimationCache_h #define hifi_AnimationCache_h +#include +#include + #include #include @@ -68,4 +71,34 @@ private: bool _isValid; }; + +class AnimationDetails { +public: + AnimationDetails() : + role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false), + startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f) { } + + AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop, + bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex) : + role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold), + startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame), + running(running), frameIndex(frameIndex) { } + + QString role; + QUrl url; + float fps; + float priority; + bool loop; + bool hold; + bool startAutomatically; + float firstFrame; + float lastFrame; + bool running; + float frameIndex; +}; +Q_DECLARE_METATYPE(AnimationDetails); +QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event); +void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event); + + #endif // hifi_AnimationCache_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index daf66dafbe..254eda1011 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -254,6 +254,8 @@ void ScriptEngine::init() { qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); + qScriptRegisterMetaType(&_engine, animationDetailsToScriptValue, animationDetailsFromScriptValue); + registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); registerGlobalObject("Controller", _controllerScriptingInterface); From 59e8a984127ca4a5b5440c4d4bae5dfff4ade0ca Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 3 Jul 2014 12:05:18 -0700 Subject: [PATCH 76/80] added example script --- examples/animationStateExample.js | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/animationStateExample.js diff --git a/examples/animationStateExample.js b/examples/animationStateExample.js new file mode 100644 index 0000000000..c6987c8626 --- /dev/null +++ b/examples/animationStateExample.js @@ -0,0 +1,32 @@ +// +// animationStateExample.js +// examples +// +// Created by Brad Hefta-Gaub on 7/3/14. +// Copyright 2014 High Fidelity, Inc. +// +// This is an example script that runs in a loop and displays a counter to the log +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// + +var count = 0; + +function displayAnimationDetails(deltaTime) { + print("count =" + count + " deltaTime=" + deltaTime); + count++; + var animationDetails = MyAvatar.getAnimationDetailsByRole("idle"); + print("animationDetails.frameIndex=" + animationDetails.frameIndex); +} + +function scriptEnding() { + print("SCRIPT ENDNG!!!\n"); +} + +// register the call back so it fires before each data send +Script.update.connect(displayAnimationDetails); + +// register our scriptEnding callback +Script.scriptEnding.connect(scriptEnding); From 94c0c15c769549ae1dbaaf025488efbd0bd0d9b2 Mon Sep 17 00:00:00 2001 From: wangyix Date: Thu, 3 Jul 2014 12:06:18 -0700 Subject: [PATCH 77/80] fixed more small bugs with AudioRingBuffer constructor --- interface/src/Audio.cpp | 2 +- tests/audio/src/AudioRingBufferTests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 98987f2d0a..2357be32d4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -93,7 +93,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), - _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true), // random access mode + _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, true), // random access mode _scopeEnabled(false), _scopeEnabledPause(false), _scopeInputOffset(0), diff --git a/tests/audio/src/AudioRingBufferTests.cpp b/tests/audio/src/AudioRingBufferTests.cpp index 1c312d8323..b9ed596e52 100644 --- a/tests/audio/src/AudioRingBufferTests.cpp +++ b/tests/audio/src/AudioRingBufferTests.cpp @@ -29,7 +29,7 @@ void AudioRingBufferTests::runAllTests() { int readIndexAt; - AudioRingBuffer ringBuffer(10, 10); // makes buffer of 100 int16_t samples + AudioRingBuffer ringBuffer(10, false, 10); // makes buffer of 100 int16_t samples for (int T = 0; T < 300; T++) { writeIndexAt = 0; From 15619b5a9860a9a776a22803372cb3c965f6c097 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 13:30:14 -0700 Subject: [PATCH 78/80] don't require RtMidi if it isn't present --- interface/src/Application.cpp | 5 +++++ interface/src/devices/MIDIManager.cpp | 6 +++++- interface/src/devices/MIDIManager.h | 7 ++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ecc9c6e481..b728bcadc2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -398,9 +398,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _trayIcon->show(); +#ifdef HAVE_RTMIDI // setup the MIDIManager MIDIManager& midiManagerInstance = MIDIManager::getInstance(); midiManagerInstance.openDefaultPort(); +#endif } Application::~Application() { @@ -3630,7 +3632,10 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); + +#ifdef HAVE_RTMIDI scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); +#endif QThread* workerThread = new QThread(this); diff --git a/interface/src/devices/MIDIManager.cpp b/interface/src/devices/MIDIManager.cpp index f88bcd1d3d..38dd6a9760 100644 --- a/interface/src/devices/MIDIManager.cpp +++ b/interface/src/devices/MIDIManager.cpp @@ -13,6 +13,8 @@ #include "MIDIManager.h" +#ifdef HAVE_RTMIDI + MIDIManager& MIDIManager::getInstance() { static MIDIManager sharedInstance; return sharedInstance; @@ -61,4 +63,6 @@ void MIDIManager::openDefaultPort() { _midiInput = NULL; } } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h index eddc473950..886b0adb00 100644 --- a/interface/src/devices/MIDIManager.h +++ b/interface/src/devices/MIDIManager.h @@ -12,6 +12,8 @@ #ifndef hifi_MIDIManager_h #define hifi_MIDIManager_h +#ifdef HAVE_RTMIDI + #include #include @@ -47,5 +49,8 @@ private: RtMidiIn* _midiInput; }; +#endif + + +#endif // hifi_MIDIManager_h -#endif // hifi_MIDIManager_h \ No newline at end of file From 8755e2d42e05468bd3c782fb13020179b9d2f373 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 3 Jul 2014 13:38:52 -0700 Subject: [PATCH 79/80] CR feedback --- interface/src/renderer/Model.cpp | 7 +++++++ interface/src/renderer/Model.h | 6 +----- libraries/animation/src/AnimationCache.cpp | 18 +++++++++++++++--- libraries/animation/src/AnimationCache.h | 10 ++-------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 86d742c949..723297f6b4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1701,6 +1701,13 @@ AnimationHandle::AnimationHandle(Model* model) : _running(false) { } +AnimationDetails AnimationHandle::getAnimationDetails() const { + AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, + _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); + return details; +} + + void AnimationHandle::simulate(float deltaTime) { _frameIndex += deltaTime * _fps; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 538babb541..5e29b869e0 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -357,11 +357,7 @@ public: void setFrameIndex(float frameIndex) { _frameIndex = glm::clamp(_frameIndex, _firstFrame, _lastFrame); } float getFrameIndex() const { return _frameIndex; } - AnimationDetails getAnimationDetails() const { - AnimationDetails details(_role, _url, _fps, _priority, _loop, _hold, - _startAutomatically, _firstFrame, _lastFrame, _running, _frameIndex); - return details; - } + AnimationDetails getAnimationDetails() const; signals: diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index ddf27af352..1a68aeb908 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -103,6 +103,21 @@ void Animation::downloadFinished(QNetworkReply* reply) { } +AnimationDetails::AnimationDetails() : + role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false), + startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f) +{ +} + +AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop, + bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex) : + role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold), + startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame), + running(running), frameIndex(frameIndex) +{ +} + + QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) { QScriptValue obj = engine->newObject(); obj.setProperty("role", details.role); @@ -116,9 +131,6 @@ QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const Animatio obj.setProperty("lastFrame", details.lastFrame); obj.setProperty("running", details.running); obj.setProperty("frameIndex", details.frameIndex); - - - return obj; } diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index b4aee5f9e3..4af9f0a83f 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -74,15 +74,9 @@ private: class AnimationDetails { public: - AnimationDetails() : - role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false), - startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), frameIndex(0.0f) { } - + AnimationDetails(); AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop, - bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex) : - role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold), - startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame), - running(running), frameIndex(frameIndex) { } + bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float frameIndex); QString role; QUrl url; From 04e7df1a3fa6c5705c9f2afae1b9dd58b111b1cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 3 Jul 2014 13:46:38 -0700 Subject: [PATCH 80/80] change the audio rolloff function --- assignment-client/src/audio/AudioMixer.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 64cba7dd21..cb790ca7ac 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -166,12 +166,18 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; - // calculate the distance coefficient using the distance to this node - float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f) - * ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE); - - // multiply the current attenuation coefficient by the distance coefficient - attenuationCoefficient *= distanceCoefficient; + if (distanceBetween >= ATTENUATION_BEGINS_AT_DISTANCE) { + // calculate the distance coefficient using the distance to this node + float distanceCoefficient = 1 - (logf(distanceBetween / ATTENUATION_BEGINS_AT_DISTANCE) / logf(2.0f) + * ATTENUATION_AMOUNT_PER_DOUBLING_IN_DISTANCE); + + if (distanceCoefficient < 0) { + distanceCoefficient = 0; + } + + // multiply the current attenuation coefficient by the distance coefficient + attenuationCoefficient *= distanceCoefficient; + } // project the rotated source position vector onto the XZ plane rotatedSourcePosition.y = 0.0f;