From 38a5b5b8d14b6c155d4583b77505786b3e54d02e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 00:28:11 -0700 Subject: [PATCH 01/88] Add ScriptsLocation settings value --- interface/resources/styles/preferences.qss | 3 +- interface/src/Menu.cpp | 10 +- interface/src/Menu.h | 7 + interface/src/ui/PreferencesDialog.cpp | 26 ++++ interface/src/ui/PreferencesDialog.h | 1 + interface/src/ui/RunningScriptsWidget.cpp | 33 ++++- interface/ui/preferencesDialog.ui | 143 ++++++++++++++++++++- 7 files changed, 217 insertions(+), 6 deletions(-) diff --git a/interface/resources/styles/preferences.qss b/interface/resources/styles/preferences.qss index e678acd0c9..40e35c8e52 100644 --- a/interface/resources/styles/preferences.qss +++ b/interface/resources/styles/preferences.qss @@ -12,7 +12,8 @@ QLabel#advancedTuningLabel { QPushButton#buttonBrowseHead, QPushButton#buttonBrowseBody, -QPushButton#buttonBrowseLocation { +QPushButton#buttonBrowseLocation, +QPushButton#buttonBrowseScriptsLocation { background-image: url(styles/search.svg); background-repeat: no-repeat; background-position: center center; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 13b72bcdb3..a3d2a0cb56 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -93,8 +93,8 @@ Menu::Menu() : _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), _preferencesDialog(NULL), - _snapshotsLocation() -{ + _snapshotsLocation(), + _scriptsLocation() { Application *appInstance = Application::getInstance(); QMenu* fileMenu = addMenu("File"); @@ -501,6 +501,7 @@ void Menu::loadSettings(QSettings* settings) { _boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0); _snapshotsLocation = settings->value("snapshotsLocation", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).toString(); + setScriptsLocation(settings->value("scriptsLocation", QString()).toString()); settings->beginGroup("View Frustum Offset Camera"); // in case settings is corrupt or missing loadSetting() will check for NaN @@ -545,6 +546,7 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("avatarLODDistanceMultiplier", _avatarLODDistanceMultiplier); settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust); settings->setValue("snapshotsLocation", _snapshotsLocation); + settings->setValue("scriptsLocation", _scriptsLocation); settings->beginGroup("View Frustum Offset Camera"); settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw); settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffset.pitch); @@ -1604,3 +1606,7 @@ QString Menu::getSnapshotsLocation() const { return _snapshotsLocation; } +void Menu::setScriptsLocation(const QString& scriptsLocation) { + _scriptsLocation = scriptsLocation; + emit scriptLocationChanged(scriptsLocation); +} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 723d320905..7d4b3f5f6a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -93,6 +93,9 @@ public: QString getSnapshotsLocation() const; void setSnapshotsLocation(QString snapshotsLocation) { _snapshotsLocation = snapshotsLocation; } + const QString& getScriptsLocation() const { return _scriptsLocation; } + void setScriptsLocation(const QString& scriptsLocation); + BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; } FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; } ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } @@ -145,6 +148,9 @@ public: void static goToDomain(const QString newDomain); void static goTo(QString destination); +signals: + void scriptLocationChanged(const QString& newPath); + public slots: void loginForCurrentDomain(); @@ -261,6 +267,7 @@ private: QPointer _attachmentsDialog; QAction* _chatAction; QString _snapshotsLocation; + QString _scriptsLocation; }; namespace MenuOption { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index eed33fda23..3eb6f94195 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -29,6 +29,7 @@ PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : F connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser); connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser); connect(ui.buttonBrowseLocation, &QPushButton::clicked, this, &PreferencesDialog::openSnapshotLocationBrowser); + connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser); } void PreferencesDialog::accept() { @@ -70,13 +71,32 @@ void PreferencesDialog::openBodyModelBrowser() { void PreferencesDialog::openSnapshotLocationBrowser() { setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + show(); + QString dir = QFileDialog::getExistingDirectory(this, tr("Snapshots Location"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!dir.isNull() && !dir.isEmpty()) { ui.snapshotLocationEdit->setText(dir); } + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + show(); +} + +void PreferencesDialog::openScriptsLocationBrowser() { + setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + show(); + + QString dir = QFileDialog::getExistingDirectory(this, tr("Scripts Location"), + ui.scriptsLocationEdit->text(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + if (!dir.isNull() && !dir.isEmpty()) { + ui.scriptsLocationEdit->setText(dir); + } + + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + show(); } void PreferencesDialog::resizeEvent(QResizeEvent *resizeEvent) { @@ -116,6 +136,8 @@ void PreferencesDialog::loadPreferences() { ui.snapshotLocationEdit->setText(menuInstance->getSnapshotsLocation()); + ui.scriptsLocationEdit->setText(menuInstance->getScriptsLocation()); + ui.pupilDilationSlider->setValue(myAvatar->getHead()->getPupilDilation() * ui.pupilDilationSlider->maximum()); @@ -169,6 +191,10 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setSnapshotsLocation(ui.snapshotLocationEdit->text()); } + if (!ui.scriptsLocationEdit->text().isEmpty() && QDir(ui.scriptsLocationEdit->text()).exists()) { + Menu::getInstance()->setScriptsLocation(ui.scriptsLocationEdit->text()); + } + myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); myAvatar->setLeanScale(ui.leanScaleSpin->value()); myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index c52986cc5c..0573304eda 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -42,6 +42,7 @@ private slots: void setHeadUrl(QString modelUrl); void setSkeletonUrl(QString modelUrl); void openSnapshotLocationBrowser(); + void openScriptsLocationBrowser(); }; diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 61241f71fb..86db1c71fe 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -12,18 +12,27 @@ #include "ui_runningScriptsWidget.h" #include "RunningScriptsWidget.h" +#include +#include #include #include #include #include +#include +#include "ScriptListModel.h" #include "Application.h" + RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : FramelessDialog(parent, 0, POSITION_LEFT), - ui(new Ui::RunningScriptsWidget) { + ui(new Ui::RunningScriptsWidget), + _fsm(this), + _spm(this) { ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, false); + setAllowResize(false); ui->hideWidgetButton->setIcon(QIcon(Application::resourcesPath() + "images/close.svg")); @@ -31,6 +40,28 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : ui->stopAllButton->setIcon(QIcon(Application::resourcesPath() + "images/stop.svg")); ui->loadScriptButton->setIcon(QIcon(Application::resourcesPath() + "images/plus-white.svg")); + ui->recentlyLoadedScriptsArea->hide(); + + _fsm.setReadOnly(true); + _fsm.setRootPath(QDir("/Users/huffman/dev/hifi-19644/examples").absolutePath()); + _fsm.setFilter(QDir::NoDotAndDotDot | QDir::Files); + _fsm.setNameFilterDisables(false); + _fsm.setNameFilters(QStringList("*.js")); + _spm.setSourceModel(&_fsm); + _spm.sort(0, Qt::AscendingOrder); + _spm.setDynamicSortFilter(true); + ui->scriptListView->setModel(&_spm); + ui->scriptListView->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->scriptListView->setRootIndex(_spm.mapFromSource(_fsm.index("/Users/huffman/dev/hifi-19644/examples"))); + connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); + connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::scriptFileSelected); + + // QCompleter *completer = new QCompleter(this); + // completer->setModel(&_spm); + // completer->setCompletionMode(QCompleter::InlineCompletion); + // completer->setCaseSensitivity(Qt::CaseInsensitive); + // ui->filterLineEdit->setCompleter(completer); + _runningScriptsTable = new ScriptsTableWidget(ui->runningScriptsTableWidget); _runningScriptsTable->setColumnCount(2); _runningScriptsTable->setColumnWidth(0, 245); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 8a84956269..119b083d37 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -155,8 +155,8 @@ color: #0e7077 0 0 - 615 - 936 + 600 + 1039 @@ -612,6 +612,145 @@ color: #0e7077 + + + + + 0 + 0 + + + + + 0 + 40 + + + + + Arial + 20 + 50 + false + + + + color: #0e7077 + + + Scripts + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + Arial + 16 + + + + color: #0e7077 + + + Load scripts from this directory: + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + 0 + + + snapshotLocationEdit + + + + + + + + + + 0 + 0 + + + + + Arial + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 30 + 30 + + + + + + + + + + + 30 + 30 + + + + + + From 35151b5dada5dace965f4163a6b6b1f5a23a26ed Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 01:18:08 -0700 Subject: [PATCH 02/88] Add ScripsModel --- interface/src/ScriptsModel.cpp | 209 +++++++++++++++++++++++++++++++++ interface/src/ScriptsModel.h | 62 ++++++++++ 2 files changed, 271 insertions(+) create mode 100644 interface/src/ScriptsModel.cpp create mode 100644 interface/src/ScriptsModel.h diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp new file mode 100644 index 0000000000..2b819c04b1 --- /dev/null +++ b/interface/src/ScriptsModel.cpp @@ -0,0 +1,209 @@ +// +// ScriptsModel.cpp +// interface/src +// +// Created by Ryan Huffman on 05/12/14. +// Copyright 2014 High Fidelity, Inc. +// +// S3 request code written with ModelBrowser as a reference. +// +// 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 "ScriptsModel.h" +#include "Menu.h" + + +static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; +static const QString PUBLIC_URL = "http://public.highfidelity.io"; +static const QString MODELS_LOCATION = "scripts/"; + +static const QString PREFIX_PARAMETER_NAME = "prefix"; +static const QString MARKER_PARAMETER_NAME = "marker"; +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) { +}; + +ScriptsModel::ScriptsModel(QObject* parent) : + QAbstractListModel(parent), + _loadingScripts(false), + _localDirectory(), + _fsWatcher(), + _localFiles(), + _remoteFiles() { + + QString scriptPath = Menu::getInstance()->getScriptsLocation(); + + _localDirectory.setPath(scriptPath); + _localDirectory.setFilter(QDir::Files | QDir::Readable); + _localDirectory.setNameFilters(QStringList("*.js")); + + _fsWatcher.addPath(_localDirectory.absolutePath()); + connect(&_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &ScriptsModel::reloadLocalFiles); + + connect(Menu::getInstance(), &Menu::scriptLocationChanged, this, &ScriptsModel::updateScriptsLocation); + + reloadLocalFiles(); + reloadRemoteFiles(); +} + +QVariant ScriptsModel::data(const QModelIndex& index, int role) const { + const QList* files = NULL; + int row = 0; + bool isLocal = index.row() < _localFiles.size(); + if (isLocal) { + files = &_localFiles; + row = index.row(); + } else { + files = &_remoteFiles; + row = index.row() - _localFiles.size(); + } + + if (role == Qt::DisplayRole) { + return QVariant((*files)[row]->getFilename() + (isLocal ? "" : " (remote)")); + } else if (role == ScriptPath) { + return QVariant((*files)[row]->getFullPath()); + } + return QVariant(); +} + +int ScriptsModel::rowCount(const QModelIndex& parent) const { + if (parent.isValid()) { + return 0; + } + return _localFiles.length() + _remoteFiles.length(); +} + +void ScriptsModel::updateScriptsLocation(const QString& newPath) { + _fsWatcher.removePath(_localDirectory.absolutePath()); + _localDirectory.setPath(newPath); + _fsWatcher.addPath(_localDirectory.absolutePath()); + reloadLocalFiles(); +} + +void ScriptsModel::reloadRemoteFiles() { + if (!_loadingScripts) { + _loadingScripts = true; + while (!_remoteFiles.isEmpty()) { + delete _remoteFiles.takeFirst(); + } + requestRemoteFiles(); + } +} + +void ScriptsModel::requestRemoteFiles(QString marker) { + QUrl url(S3_URL); + QUrlQuery query; + query.addQueryItem(PREFIX_PARAMETER_NAME, MODELS_LOCATION); + if (!marker.isEmpty()) { + query.addQueryItem(MARKER_PARAMETER_NAME, marker); + } + url.setQuery(query); + + QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + + QNetworkRequest request(url); + accessManager->get(request); +} + +void ScriptsModel::downloadFinished(QNetworkReply* reply) { + bool finished = true; + + if (reply->error() == QNetworkReply::NoError) { + QByteArray data = reply->readAll(); + + if (!data.isEmpty()) { + finished = parseXML(data); + } else { + qDebug() << "Error: Received no data when loading remote scripts"; + } + } + + reply->deleteLater(); + sender()->deleteLater(); + + if (finished) { + _loadingScripts = false; + } +} + +bool ScriptsModel::parseXML(QByteArray xmlFile) { + beginResetModel(); + + QXmlStreamReader xml(xmlFile); + QRegExp jsRegex(".*\\.js"); + bool truncated = false; + QString lastKey; + + while (!xml.atEnd() && !xml.hasError()) { + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == IS_TRUNCATED_NAME) { + while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == IS_TRUNCATED_NAME)) { + xml.readNext(); + if (xml.text().toString() == "true") { + truncated = true; + } + } + } + + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == CONTAINER_NAME) { + while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == CONTAINER_NAME)) { + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == KEY_NAME) { + xml.readNext(); + lastKey = xml.text().toString(); + if (jsRegex.exactMatch(xml.text().toString())) { + _remoteFiles.append(new ScriptItem(lastKey.mid(MODELS_LOCATION.length()), S3_URL + "/" + lastKey)); + } + } + xml.readNext(); + } + } + xml.readNext(); + } + + endResetModel(); + + // Error handling + if (xml.hasError()) { + qDebug() << "Error loading remote scripts: " << xml.errorString(); + return true; + } + + if (truncated) { + requestRemoteFiles(lastKey); + } + + // If this request was not truncated, we are done. + return !truncated; +} + +void ScriptsModel::reloadLocalFiles() { + beginResetModel(); + + while (!_localFiles.isEmpty()) { + delete _localFiles.takeFirst(); + } + + _localDirectory.refresh(); + + const QFileInfoList localFiles = _localDirectory.entryInfoList(); + for (int i = 0; i < localFiles.size(); i++) { + QFileInfo file = localFiles[i]; + _localFiles.append(new ScriptItem(file.fileName(), file.absoluteFilePath())); + } + + endResetModel(); +} diff --git a/interface/src/ScriptsModel.h b/interface/src/ScriptsModel.h new file mode 100644 index 0000000000..250c7eb9a8 --- /dev/null +++ b/interface/src/ScriptsModel.h @@ -0,0 +1,62 @@ +// +// ScriptsModel.h +// interface/src +// +// Created by Ryan Huffman on 05/12/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ScriptsModel_h +#define hifi_ScriptsModel_h + +#include +#include +#include +#include + +class ScriptItem { +public: + ScriptItem(const QString& filename, const QString& fullPath); + + const QString& getFilename() { return _filename; }; + const QString& getFullPath() { return _fullPath; }; + +private: + QString _filename; + QString _fullPath; +}; + +class ScriptsModel : public QAbstractListModel { + Q_OBJECT +public: + ScriptsModel(QObject* parent = NULL); + + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + + enum Role { + ScriptPath = Qt::UserRole, + }; + +protected slots: + void updateScriptsLocation(const QString& newPath); + void downloadFinished(QNetworkReply* reply); + void reloadLocalFiles(); + void reloadRemoteFiles(); + +protected: + void requestRemoteFiles(QString marker = QString()); + bool parseXML(QByteArray xmlFile); + +private: + bool _loadingScripts; + QDir _localDirectory; + QFileSystemWatcher _fsWatcher; + QList _localFiles; + QList _remoteFiles; +}; + +#endif // hifi_ScriptsModel_h From 03f9c0c7e23a4b0232fcd490576d3f1d6d1265c7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 01:42:24 -0700 Subject: [PATCH 03/88] Update Running Scripts Widget to use ScriptModel --- interface/src/ui/RunningScriptsWidget.cpp | 44 +- interface/src/ui/RunningScriptsWidget.h | 9 + interface/ui/runningScriptsWidget.ui | 792 +++++++++++++++------- 3 files changed, 598 insertions(+), 247 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 86db1c71fe..5eac34731f 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -3,6 +3,7 @@ // interface/src/ui // // Created by Mohammed Nafees on 03/28/2014. +// Updated by Ryan Huffman on 05/13/2014. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -18,17 +19,17 @@ #include #include #include -#include -#include "ScriptListModel.h" #include "Application.h" +#include "Menu.h" +#include "ScriptsModel.h" RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : FramelessDialog(parent, 0, POSITION_LEFT), ui(new Ui::RunningScriptsWidget), - _fsm(this), - _spm(this) { + _scriptsModel(this), + _proxyModel(this) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, false); @@ -42,17 +43,13 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : ui->recentlyLoadedScriptsArea->hide(); - _fsm.setReadOnly(true); - _fsm.setRootPath(QDir("/Users/huffman/dev/hifi-19644/examples").absolutePath()); - _fsm.setFilter(QDir::NoDotAndDotDot | QDir::Files); - _fsm.setNameFilterDisables(false); - _fsm.setNameFilters(QStringList("*.js")); - _spm.setSourceModel(&_fsm); - _spm.sort(0, Qt::AscendingOrder); - _spm.setDynamicSortFilter(true); - ui->scriptListView->setModel(&_spm); + QString scriptPath = "/Users/huffman/dev/hifi-19644/examples";//Application::getInstance()->getPreviousScriptLocation(); + + _proxyModel.setSourceModel(&_scriptsModel); + _proxyModel.sort(0, Qt::AscendingOrder); + _proxyModel.setDynamicSortFilter(true); + ui->scriptListView->setModel(&_proxyModel); ui->scriptListView->setAttribute(Qt::WA_MacShowFocusRect, false); - ui->scriptListView->setRootIndex(_spm.mapFromSource(_fsm.index("/Users/huffman/dev/hifi-19644/examples"))); connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::scriptFileSelected); @@ -88,6 +85,17 @@ RunningScriptsWidget::~RunningScriptsWidget() { delete ui; } +void RunningScriptsWidget::updateFileFilter(const QString& filter) { + QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive); + _proxyModel.setFilterRegExp(regex); +} + +void RunningScriptsWidget::scriptFileSelected(const QModelIndex& index) { + QVariant scriptFile = _proxyModel.data(index, ScriptsModel::ScriptPath); + qDebug() << "Loading: " << scriptFile.toString(); + Application::getInstance()->loadScript(scriptFile.toString()); +} + void RunningScriptsWidget::setBoundary(const QRect& rect) { _boundary = rect; } @@ -126,8 +134,6 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) { ui->runningScriptsTableWidget->resize(ui->runningScriptsTableWidget->width(), y - RUNNING_SCRIPTS_TABLE_LEFT_MARGIN); _runningScriptsTable->resize(_runningScriptsTable->width(), y - RUNNING_SCRIPTS_TABLE_LEFT_MARGIN); - ui->reloadAllButton->move(ui->reloadAllButton->x(), y); - ui->stopAllButton->move(ui->stopAllButton->x(), y); ui->recentlyLoadedLabel->move(ui->recentlyLoadedLabel->x(), ui->stopAllButton->y() + ui->stopAllButton->height() + RECENTLY_LOADED_TOP_MARGIN); ui->recentlyLoadedScriptsTableWidget->move(ui->recentlyLoadedScriptsTableWidget->x(), @@ -173,10 +179,12 @@ void RunningScriptsWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.setPen(QColor::fromRgb(225, 225, 225)); // #e1e1e1 + const QPoint& labelPos = ui->runningScriptsArea->mapToParent(ui->currentlyRunningLabel->pos()); + if (ui->currentlyRunningLabel->isVisible()) { // line below the 'Currently Running' label - painter.drawLine(36, ui->currentlyRunningLabel->y() + ui->currentlyRunningLabel->height(), - 300, ui->currentlyRunningLabel->y() + ui->currentlyRunningLabel->height()); + painter.drawLine(36, labelPos.y() + ui->currentlyRunningLabel->height(), + 300, labelPos.y() + ui->currentlyRunningLabel->height()); } if (ui->recentlyLoadedLabel->isVisible()) { diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h index ad310c4ed4..6b45ac2202 100644 --- a/interface/src/ui/RunningScriptsWidget.h +++ b/interface/src/ui/RunningScriptsWidget.h @@ -3,6 +3,7 @@ // interface/src/ui // // Created by Mohammed Nafees on 03/28/2014. +// Updated by Ryan Huffman on 05/13/2014. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -12,6 +13,10 @@ #ifndef hifi_RunningScriptsWidget_h #define hifi_RunningScriptsWidget_h +#include +#include + +#include "ScriptsModel.h" #include "FramelessDialog.h" #include "ScriptsTableWidget.h" @@ -42,9 +47,13 @@ private slots: void stopScript(int row, int column); void loadScript(int row, int column); void allScriptsStopped(); + void updateFileFilter(const QString& filter); + void scriptFileSelected(const QModelIndex& index); private: Ui::RunningScriptsWidget* ui; + QSortFilterProxyModel _proxyModel; + ScriptsModel _scriptsModel; ScriptsTableWidget* _runningScriptsTable; ScriptsTableWidget* _recentlyLoadedScriptsTable; QStringList _recentlyLoadedScripts; diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 6abd0f2d5a..324a460d1b 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 323 - 894 + 324 + 971 @@ -21,252 +21,586 @@ QWidget { background: #f7f7f7; } - - - - 37 - 29 - 251 - 20 - + + + 20 - - color: #0e7077; + + 20 + + + 20 + + + 20 + + + + + + 0 + + + 0 + + + 0 + + + + + color: #0e7077; font-size: 20pt; background: transparent; - - - <html><head/><body><p><span style=" font-size:18pt;">Running Scripts</span></p></body></html> - - - 0 - - - -1 - - - - - - 36 - 110 - 270 - 20 - - - - color: #0e7077; -font: bold 14pt; + + + <html><head/><body><p><span style=" font-size:18pt;">Running Scripts</span></p></body></html> + + + 0 + + + -1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PointingHandCursor + + + border: 0 + + + + + + + 16 + 16 + + + + true + + + + + + + + + + + 0 + 1 + + + + + 0 + 141 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Helvetica,Arial,sans-serif + 16 + 75 + false + true + + + + color: #0e7077; +font: bold 16pt; background: transparent; - - - <html><head/><body><p><span style=" font-weight:600;">Currently running</span></p></body></html> - - - - - - 36 - 270 - 111 - 35 - - - - PointingHandCursor - - - false - - - background: #0e7077; + + + <html><head/><body><p><span style=" font-weight:600;">Currently running</span></p></body></html> + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 0 + 8 + + + + + + + + + 0 + 0 + + + + + 24 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 111 + 35 + + + + PointingHandCursor + + + false + + + background: #0e7077; color: #fff; border-radius: 4px; font: bold 14pt; padding-top: 3px; - - - Reload all - - - - ../resources/images/reload.svg../resources/images/reload.svg - - - - - - 160 - 270 - 93 - 35 - - - - PointingHandCursor - - - background: #0e7077; + + + Reload all + + + + ../../../../../../../../.designer/resources/images/reload.svg../../../../../../../../.designer/resources/images/reload.svg + + + + + + + + 0 + 0 + + + + + 111 + 35 + + + + PointingHandCursor + + + background: #0e7077; color: #fff; border-radius: 4px; font: bold 14pt; padding-top: 3px; - - - Stop all - - - - ../resources/images/stop.svg../resources/images/stop.svg - - - - - - 36 - 320 - 265 - 20 - - - - color: #0e7077; -font: bold 14pt; - - - <html><head/><body><p><span style=" font-weight:600;">Recently loaded</span></p></body></html> - - - - - - 36 - 630 - 211 - 41 - - - - color: #95a5a6; + + + Stop all + + + + ../../../../../../../../.designer/resources/images/stop.svg../../../../../../../../.designer/resources/images/stop.svg + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 8 + + + + + + + + font: 14pt; + + + There are no scripts currently running. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + + 0 + 1 + + + + + 284 + 0 + + + + 0 + + + background: transparent; font-size: 14pt; - - - (click a script or use the 1-9 keys to load and run it) - - - true - - - - - - 285 - 29 - 16 - 16 - - - - PointingHandCursor - - - - - - - 16 - 16 - - - - true - - - - - - 36 - 110 - 271 - 51 - - - - font: 14pt; - - - There are no scripts currently running. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - 30 - 340 - 272 - 280 - - - - background: transparent; + + + + + + + + + + true + + + + 0 + 100 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + color: #0e7077; +font: bold 16pt; + + + <html><head/><body><p><span style=" font-weight:600;">Recently loaded</span></p></body></html> + + + + + + + font: 14pt; + + + There are no recently loaded scripts. + + + + + + + + 0 + 1 + + + + + 284 + 0 + + + + background: transparent; font-size: 14pt; - - - - - - 30 - 128 - 272 - 161 - - - - background: transparent; + + + + + + + color: #95a5a6; font-size: 14pt; - - - - - - 36 - 70 - 111 - 35 - - - - PointingHandCursor - - - background: #0e7077; + + + (click a script or use the 1-9 keys to load and run it) + + + true + + + + + + + + + + + 0 + 1 + + + + + 0 + 300 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 15 + + + + + color: #0e7077; +font: bold 16pt; + + + Scripts + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 111 + 35 + + + + PointingHandCursor + + + background: #0e7077; color: #fff; border-radius: 4px; font: bold 14pt; padding-top: 3px; - - - Load script - - - - ../resources/images/plus.svg../resources/images/plus.svg - - - widgetTitle - currentlyRunningLabel - recentlyLoadedLabel - recentlyLoadedInstruction - hideWidgetButton - recentlyLoadedScriptsTableWidget - runningScriptsTableWidget - noRunningScriptsLabel - reloadAllButton - stopAllButton - loadScriptButton + + + Load script + + + + ../../../../../../../../.designer/resources/images/plus.svg../../../../../../../../.designer/resources/images/plus.svg + + + + + + + + + + border: 1px solid rgb(128, 128, 128); +border-radius: 2px; +padding: 4px; +background-color: white; + + + filter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 6 + + + + + + + + border: 1px solid rgb(128, 128, 128); +border-radius: 2px; + + + QFrame::Box + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAsNeeded + + + + + + + From 90d3dd3ceb980c0ef582c1adac87f1e58bc596f0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 01:43:37 -0700 Subject: [PATCH 04/88] Remove unused lines --- interface/src/ui/RunningScriptsWidget.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 5eac34731f..5a7c2e7925 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -43,8 +43,6 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : ui->recentlyLoadedScriptsArea->hide(); - QString scriptPath = "/Users/huffman/dev/hifi-19644/examples";//Application::getInstance()->getPreviousScriptLocation(); - _proxyModel.setSourceModel(&_scriptsModel); _proxyModel.sort(0, Qt::AscendingOrder); _proxyModel.setDynamicSortFilter(true); @@ -53,12 +51,6 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::scriptFileSelected); - // QCompleter *completer = new QCompleter(this); - // completer->setModel(&_spm); - // completer->setCompletionMode(QCompleter::InlineCompletion); - // completer->setCaseSensitivity(Qt::CaseInsensitive); - // ui->filterLineEdit->setCompleter(completer); - _runningScriptsTable = new ScriptsTableWidget(ui->runningScriptsTableWidget); _runningScriptsTable->setColumnCount(2); _runningScriptsTable->setColumnWidth(0, 245); From 6e80b97efe3774c3690d1ce4711db1be1537d17d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 01:44:35 -0700 Subject: [PATCH 05/88] Disable hiding of running script area when none are running --- interface/src/ui/RunningScriptsWidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 5a7c2e7925..866297f92d 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -96,7 +96,6 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) { _runningScriptsTable->setRowCount(list.size()); ui->noRunningScriptsLabel->setVisible(list.isEmpty()); - ui->currentlyRunningLabel->setVisible(!list.isEmpty()); ui->runningScriptsTableWidget->setVisible(!list.isEmpty()); ui->reloadAllButton->setVisible(!list.isEmpty()); ui->stopAllButton->setVisible(!list.isEmpty()); @@ -220,7 +219,7 @@ void RunningScriptsWidget::createRecentlyLoadedScriptsTable() { } } - ui->recentlyLoadedLabel->setVisible(!_recentlyLoadedScripts.isEmpty()); + ui->noRecentlyLoadedLabel->setVisible(_recentlyLoadedScripts.isEmpty()); ui->recentlyLoadedScriptsTableWidget->setVisible(!_recentlyLoadedScripts.isEmpty()); ui->recentlyLoadedInstruction->setVisible(!_recentlyLoadedScripts.isEmpty()); From a1d5d44bc12630e80e6314788a21a5b7efd85b8f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 14 May 2014 01:45:07 -0700 Subject: [PATCH 06/88] Update RunningScripts to be created after Menu has been created --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b50e9ef1dc..ec6f0d9eff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -168,7 +168,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _bytesPerSecond(0), _previousScriptLocation(), _logger(new FileLogger(this)), - _runningScriptsWidget(new RunningScriptsWidget(_window)), + _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false) { // init GnuTLS for DTLS with domain-servers @@ -201,6 +201,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // call Menu getInstance static method to set up the menu _window->setMenuBar(Menu::getInstance()); + _runningScriptsWidget = new RunningScriptsWidget(_window); + unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); From 2eeb3f5f2f078e90fae0d808258011d3c0cd8125 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 May 2014 16:56:51 -0700 Subject: [PATCH 07/88] Update loadScript to optionally activate main window --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8509bd96d1..e89c3d9853 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3412,7 +3412,7 @@ void Application::saveScripts() { _settings->endArray(); } -ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) { +ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor, bool activateMainWindow) { if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){ return _scriptEnginesHash[scriptName]; } @@ -3486,7 +3486,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript workerThread->start(); // restore the main window's active state - if (!loadScriptFromEditor) { + if (activateMainWindow && !loadScriptFromEditor) { _window->activateWindow(); } bumpSettings(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 1968ef4fee..17200a9419 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -303,7 +303,7 @@ public slots: void loadScriptURLDialog(); void toggleLogDialog(); void initAvatarAndViewFrustum(); - ScriptEngine* loadScript(const QString& fileNameString, bool loadScriptFromEditor = false); + ScriptEngine* loadScript(const QString& fileNameString, bool loadScriptFromEditor = false, bool activateMainWindow = false); void scriptFinished(const QString& scriptName); void stopAllScripts(bool restart = false); void stopScript(const QString& scriptName); From b108ea31403cfdd032da606f611e725a76d7aeb1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 May 2014 16:57:13 -0700 Subject: [PATCH 08/88] Update script list to only label local files --- interface/src/ScriptsModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index 2b819c04b1..f9ed94f3fa 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -73,7 +73,7 @@ QVariant ScriptsModel::data(const QModelIndex& index, int role) const { } if (role == Qt::DisplayRole) { - return QVariant((*files)[row]->getFilename() + (isLocal ? "" : " (remote)")); + return QVariant((*files)[row]->getFilename() + (isLocal ? " (local)" : "")); } else if (role == ScriptPath) { return QVariant((*files)[row]->getFullPath()); } From c428e6896241752a423c06b9740b394fe573883a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 May 2014 17:03:07 -0700 Subject: [PATCH 09/88] Update script window to load script when pressing enter --- interface/src/ui/RunningScriptsWidget.cpp | 68 ++++++++++++++++++----- interface/src/ui/RunningScriptsWidget.h | 7 ++- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index b897c96c36..46989200cc 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -13,7 +13,6 @@ #include "ui_runningScriptsWidget.h" #include "RunningScriptsWidget.h" -#include #include #include #include @@ -43,13 +42,18 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : ui->recentlyLoadedScriptsArea->hide(); + ui->filterLineEdit->installEventFilter(this); + + connect(&_proxyModel, &QSortFilterProxyModel::modelReset, + this, &RunningScriptsWidget::selectFirstInList); + _proxyModel.setSourceModel(&_scriptsModel); _proxyModel.sort(0, Qt::AscendingOrder); _proxyModel.setDynamicSortFilter(true); ui->scriptListView->setModel(&_proxyModel); - ui->scriptListView->setAttribute(Qt::WA_MacShowFocusRect, false); + connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); - connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::scriptFileSelected); + connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); _runningScriptsTable = new ScriptsTableWidget(ui->runningScriptsTableWidget); _runningScriptsTable->setColumnCount(2); @@ -80,12 +84,19 @@ RunningScriptsWidget::~RunningScriptsWidget() { void RunningScriptsWidget::updateFileFilter(const QString& filter) { QRegExp regex("^.*" + QRegExp::escape(filter) + ".*$", Qt::CaseInsensitive); _proxyModel.setFilterRegExp(regex); + selectFirstInList(); } -void RunningScriptsWidget::scriptFileSelected(const QModelIndex& index) { +void RunningScriptsWidget::loadScriptFromList(const QModelIndex& index) { QVariant scriptFile = _proxyModel.data(index, ScriptsModel::ScriptPath); - qDebug() << "Loading: " << scriptFile.toString(); - Application::getInstance()->loadScript(scriptFile.toString()); + Application::getInstance()->loadScript(scriptFile.toString(), false, false); +} + +void RunningScriptsWidget::loadSelectedScript() { + QModelIndex selectedIndex = ui->scriptListView->currentIndex(); + if (selectedIndex.isValid()) { + loadScriptFromList(selectedIndex); + } } void RunningScriptsWidget::setBoundary(const QRect& rect) { @@ -134,14 +145,43 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) { createRecentlyLoadedScriptsTable(); } -void RunningScriptsWidget::keyPressEvent(QKeyEvent* event) -{ +void RunningScriptsWidget::showEvent(QShowEvent* event) { + if (!event->spontaneous()) { + ui->filterLineEdit->setFocus(); + } + + FramelessDialog::showEvent(event); +} + +void RunningScriptsWidget::selectFirstInList() { + if (_proxyModel.rowCount() > 0) { + ui->scriptListView->setCurrentIndex(_proxyModel.index(0, 0)); + } +} + +bool RunningScriptsWidget::eventFilter(QObject* sender, QEvent* event) { + if (sender == ui->filterLineEdit) { + if (event->type() != QEvent::KeyPress) { + return false; + } + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + QModelIndex selectedIndex = ui->scriptListView->currentIndex(); + if (selectedIndex.isValid()) { + loadScriptFromList(selectedIndex); + } + event->accept(); + return true; + } + return false; + } + + return FramelessDialog::eventFilter(sender, event); +} + +void RunningScriptsWidget::keyPressEvent(QKeyEvent* event) { int loadScriptNumber = -1; switch(event->key()) { - case Qt::Key_Escape: - Application::getInstance()->toggleRunningScriptsWidget(); - break; - case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: @@ -159,7 +199,7 @@ void RunningScriptsWidget::keyPressEvent(QKeyEvent* event) } if (loadScriptNumber >= 0) { if (_recentlyLoadedScripts.size() > loadScriptNumber) { - Application::getInstance()->loadScript(_recentlyLoadedScripts.at(loadScriptNumber)); + Application::getInstance()->loadScript(_recentlyLoadedScripts.at(loadScriptNumber), false, false); } } @@ -199,7 +239,7 @@ void RunningScriptsWidget::stopScript(int row, int column) { } void RunningScriptsWidget::loadScript(int row, int column) { - Application::getInstance()->loadScript(_recentlyLoadedScriptsTable->item(row, column)->toolTip()); + Application::getInstance()->loadScript(_recentlyLoadedScriptsTable->item(row, column)->toolTip(), false, false); } void RunningScriptsWidget::allScriptsStopped() { diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h index 8170cb65b8..7b03898ece 100644 --- a/interface/src/ui/RunningScriptsWidget.h +++ b/interface/src/ui/RunningScriptsWidget.h @@ -37,8 +37,11 @@ signals: void stopScriptName(const QString& name); protected: + virtual bool eventFilter(QObject* sender, QEvent* event); + virtual void keyPressEvent(QKeyEvent* event); virtual void paintEvent(QPaintEvent* event); + virtual void showEvent(QShowEvent* event); public slots: void scriptStopped(const QString& scriptName); @@ -49,7 +52,9 @@ private slots: void loadScript(int row, int column); void allScriptsStopped(); void updateFileFilter(const QString& filter); - void scriptFileSelected(const QModelIndex& index); + void loadScriptFromList(const QModelIndex& index); + void loadSelectedScript(); + void selectFirstInList(); private: Ui::RunningScriptsWidget* ui; From e21a7524c6b1a206910b74ce0cfc453added7ae9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 May 2014 17:03:19 -0700 Subject: [PATCH 10/88] Update runningscripts style --- interface/ui/runningScriptsWidget.ui | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 747b29abf2..063b2cd3b5 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -434,7 +434,7 @@ font-size: 14pt; 0 - 1 + 2 @@ -544,9 +544,15 @@ border-radius: 2px; padding: 4px; background-color: white; + + + filter + + true + @@ -568,8 +574,14 @@ background-color: white; - border: 1px solid rgb(128, 128, 128); -border-radius: 2px; + QListView { + border: 1px solid rgb(128, 128, 128); + border-radius: 2px; +} +QListView::item { + padding-top: 2px; + padding-bottom: 2px; +} QFrame::Box From 0877f9f15930e6fcd531b69e61fb85f40e93ee4a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 17 Jun 2014 20:19:49 -0700 Subject: [PATCH 11/88] Fix issues with running scripts window on Windows Replace running scripts table with a new widget that uses a proper layout that doesn't rely on hard-coded sizing. Custom painted lines were replaced with a horizontal QFrame line. --- interface/src/ui/RunningScriptsWidget.cpp | 161 +++++++--------------- interface/src/ui/RunningScriptsWidget.h | 8 +- interface/ui/runningScriptsWidget.ui | 97 +++++++++---- 3 files changed, 116 insertions(+), 150 deletions(-) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 449b11c89c..b2ee36d1fe 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -27,6 +27,7 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : FramelessDialog(parent, 0, POSITION_LEFT), ui(new Ui::RunningScriptsWidget), + _signalMapper(this), _scriptsModel(this), _proxyModel(this) { ui->setupUi(this); @@ -55,17 +56,9 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->scriptListView, &QListView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); - _runningScriptsTable = new ScriptsTableWidget(ui->runningScriptsTableWidget); - _runningScriptsTable->setColumnCount(2); - _runningScriptsTable->setColumnWidth(0, 245); - _runningScriptsTable->setColumnWidth(1, 22); - connect(_runningScriptsTable, &QTableWidget::cellClicked, this, &RunningScriptsWidget::stopScript); - _recentlyLoadedScriptsTable = new ScriptsTableWidget(ui->recentlyLoadedScriptsTableWidget); _recentlyLoadedScriptsTable->setColumnCount(1); _recentlyLoadedScriptsTable->setColumnWidth(0, 265); - connect(_recentlyLoadedScriptsTable, &QTableWidget::cellClicked, - this, &RunningScriptsWidget::loadScript); connect(ui->hideWidgetButton, &QPushButton::clicked, Application::getInstance(), &Application::toggleRunningScriptsWidget); @@ -75,6 +68,7 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : this, &RunningScriptsWidget::allScriptsStopped); connect(ui->loadScriptButton, &QPushButton::clicked, Application::getInstance(), &Application::loadDialog); + connect(&_signalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&))); } RunningScriptsWidget::~RunningScriptsWidget() { @@ -104,45 +98,55 @@ void RunningScriptsWidget::setBoundary(const QRect& rect) { } void RunningScriptsWidget::setRunningScripts(const QStringList& list) { - _runningScriptsTable->setRowCount(list.size()); + setUpdatesEnabled(false); + QLayoutItem* widget; + while ((widget = ui->scrollAreaWidgetContents->layout()->takeAt(0)) != NULL) { + delete widget->widget(); + delete widget; + } + const int CLOSE_ICON_HEIGHT = 12; + for (int i = 0; i < list.size(); i++) { + QWidget* row = new QWidget(ui->scrollAreaWidgetContents); + row->setLayout(new QHBoxLayout(row)); + + QUrl url = QUrl(list.at(i)); + QLabel* name = new QLabel(url.fileName(), row); + QPushButton* closeButton = new QPushButton(row); + closeButton->setFlat(true); + closeButton->setIcon( + QIcon(QPixmap(Application::resourcesPath() + "images/kill-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT))); + closeButton->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred)); + closeButton->setStyleSheet("border: 0;"); + closeButton->setCursor(Qt::PointingHandCursor); + + connect(closeButton, SIGNAL(clicked()), &_signalMapper, SLOT(map())); + _signalMapper.setMapping(closeButton, url.toString()); + + row->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + + row->layout()->setContentsMargins(4, 4, 4, 4); + row->layout()->setSpacing(0); + + row->layout()->addWidget(name); + row->layout()->addWidget(closeButton); + + QFrame* line = new QFrame(row); + line->setFrameShape(QFrame::HLine); + line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;"); + + ui->scrollAreaWidgetContents->layout()->addWidget(row); + ui->scrollAreaWidgetContents->layout()->addWidget(line); + } + ui->noRunningScriptsLabel->setVisible(list.isEmpty()); - ui->runningScriptsTableWidget->setVisible(!list.isEmpty()); ui->reloadAllButton->setVisible(!list.isEmpty()); ui->stopAllButton->setVisible(!list.isEmpty()); - const int CLOSE_ICON_HEIGHT = 12; - - for (int i = 0; i < list.size(); ++i) { - QTableWidgetItem *scriptName = new QTableWidgetItem; - scriptName->setText(QFileInfo(list.at(i)).fileName()); - scriptName->setToolTip(list.at(i)); - scriptName->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); - QTableWidgetItem *closeIcon = new QTableWidgetItem; - closeIcon->setIcon(QIcon(QPixmap(Application::resourcesPath() + "images/kill-script.svg").scaledToHeight(CLOSE_ICON_HEIGHT))); - - _runningScriptsTable->setItem(i, 0, scriptName); - _runningScriptsTable->setItem(i, 1, closeIcon); - } - - const int RUNNING_SCRIPTS_TABLE_LEFT_MARGIN = 12; - const int RECENTLY_LOADED_TOP_MARGIN = 61; - const int RECENTLY_LOADED_LABEL_TOP_MARGIN = 19; - - int y = ui->runningScriptsTableWidget->y() + RUNNING_SCRIPTS_TABLE_LEFT_MARGIN; - for (int i = 0; i < _runningScriptsTable->rowCount(); ++i) { - y += _runningScriptsTable->rowHeight(i); - } - - ui->runningScriptsTableWidget->resize(ui->runningScriptsTableWidget->width(), y - RUNNING_SCRIPTS_TABLE_LEFT_MARGIN); - _runningScriptsTable->resize(_runningScriptsTable->width(), y - RUNNING_SCRIPTS_TABLE_LEFT_MARGIN); - ui->recentlyLoadedLabel->move(ui->recentlyLoadedLabel->x(), - ui->stopAllButton->y() + ui->stopAllButton->height() + RECENTLY_LOADED_TOP_MARGIN); - ui->recentlyLoadedScriptsTableWidget->move(ui->recentlyLoadedScriptsTableWidget->x(), - ui->recentlyLoadedLabel->y() + RECENTLY_LOADED_LABEL_TOP_MARGIN); - - - createRecentlyLoadedScriptsTable(); + ui->scrollAreaWidgetContents->updateGeometry(); + setUpdatesEnabled(true); + Application::processEvents(); + repaint(); } void RunningScriptsWidget::showEvent(QShowEvent* event) { @@ -187,81 +191,10 @@ void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) { } } -void RunningScriptsWidget::paintEvent(QPaintEvent* event) { - QPainter painter(this); - painter.setPen(QColor::fromRgb(225, 225, 225)); // #e1e1e1 - - const QPoint& labelPos = ui->runningScriptsArea->mapToParent(ui->currentlyRunningLabel->pos()); - - if (ui->currentlyRunningLabel->isVisible()) { - // line below the 'Currently Running' label - painter.drawLine(36, labelPos.y() + ui->currentlyRunningLabel->height(), - 300, labelPos.y() + ui->currentlyRunningLabel->height()); - } - - if (ui->recentlyLoadedLabel->isVisible()) { - // line below the 'Recently loaded' label - painter.drawLine(36, ui->recentlyLoadedLabel->y() + ui->recentlyLoadedLabel->height(), - 300, ui->recentlyLoadedLabel->y() + ui->recentlyLoadedLabel->height()); - } - - painter.end(); -} - void RunningScriptsWidget::scriptStopped(const QString& scriptName) { - _recentlyLoadedScripts.prepend(scriptName); -} - -void RunningScriptsWidget::stopScript(int row, int column) { - if (column == 1) { // make sure the user has clicked on the close icon - _lastStoppedScript = _runningScriptsTable->item(row, 0)->toolTip(); - emit stopScriptName(_runningScriptsTable->item(row, 0)->toolTip()); - } -} - -void RunningScriptsWidget::loadScript(int row, int column) { - Application::getInstance()->loadScript(_recentlyLoadedScriptsTable->item(row, column)->toolTip(), false, false); + // _recentlyLoadedScripts.prepend(scriptName); } void RunningScriptsWidget::allScriptsStopped() { Application::getInstance()->stopAllScripts(); } - -void RunningScriptsWidget::createRecentlyLoadedScriptsTable() { - if (!_recentlyLoadedScripts.contains(_lastStoppedScript) && !_lastStoppedScript.isEmpty()) { - _recentlyLoadedScripts.prepend(_lastStoppedScript); - _lastStoppedScript = ""; - } - - for (int i = 0; i < _recentlyLoadedScripts.size(); ++i) { - if (Application::getInstance()->getRunningScripts().contains(_recentlyLoadedScripts.at(i))) { - _recentlyLoadedScripts.removeOne(_recentlyLoadedScripts.at(i)); - } - } - - ui->noRecentlyLoadedLabel->setVisible(_recentlyLoadedScripts.isEmpty()); - ui->recentlyLoadedScriptsTableWidget->setVisible(!_recentlyLoadedScripts.isEmpty()); - ui->recentlyLoadedInstruction->setVisible(!_recentlyLoadedScripts.isEmpty()); - - int limit = _recentlyLoadedScripts.size() > 9 ? 9 : _recentlyLoadedScripts.size(); - _recentlyLoadedScriptsTable->setRowCount(limit); - for (int i = 0; i < limit; i++) { - QTableWidgetItem *scriptName = new QTableWidgetItem; - scriptName->setText(QString::number(i + 1) + ". " + QFileInfo(_recentlyLoadedScripts.at(i)).fileName()); - scriptName->setToolTip(_recentlyLoadedScripts.at(i)); - scriptName->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); - - _recentlyLoadedScriptsTable->setItem(i, 0, scriptName); - } - - int y = ui->recentlyLoadedScriptsTableWidget->y() + 15; - for (int i = 0; i < _recentlyLoadedScriptsTable->rowCount(); ++i) { - y += _recentlyLoadedScriptsTable->rowHeight(i); - } - - ui->recentlyLoadedInstruction->setGeometry(36, y, - ui->recentlyLoadedInstruction->width(), - ui->recentlyLoadedInstruction->height()); - - repaint(); -} diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h index 7b03898ece..6810aca487 100644 --- a/interface/src/ui/RunningScriptsWidget.h +++ b/interface/src/ui/RunningScriptsWidget.h @@ -14,6 +14,7 @@ #define hifi_RunningScriptsWidget_h #include +#include #include #include "ScriptsModel.h" @@ -40,7 +41,6 @@ protected: virtual bool eventFilter(QObject* sender, QEvent* event); virtual void keyPressEvent(QKeyEvent* event); - virtual void paintEvent(QPaintEvent* event); virtual void showEvent(QShowEvent* event); public slots: @@ -48,8 +48,6 @@ public slots: void setBoundary(const QRect& rect); private slots: - void stopScript(int row, int column); - void loadScript(int row, int column); void allScriptsStopped(); void updateFileFilter(const QString& filter); void loadScriptFromList(const QModelIndex& index); @@ -58,15 +56,13 @@ private slots: private: Ui::RunningScriptsWidget* ui; + QSignalMapper _signalMapper; QSortFilterProxyModel _proxyModel; ScriptsModel _scriptsModel; - ScriptsTableWidget* _runningScriptsTable; ScriptsTableWidget* _recentlyLoadedScriptsTable; QStringList _recentlyLoadedScripts; QString _lastStoppedScript; QRect _boundary; - - void createRecentlyLoadedScriptsTable(); }; #endif // hifi_RunningScriptsWidget_h diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 063b2cd3b5..2f51ab7a94 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -304,6 +304,9 @@ padding-top: 3px; Qt::Vertical + + QSizePolicy::Fixed + 20 @@ -313,26 +316,73 @@ padding-top: 3px; - - - - 0 - 1 - + + + + Helvetica,Arial,sans-serif + 14 + - - - 284 - 0 - - - - 0 + + Qt::LeftToRight - background: transparent; -font-size: 14pt; + margin: 0; + + QFrame::NoFrame + + + 0 + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 269 + 16 + + + + + 0 + 0 + + + + font-size: 14pt; + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + @@ -410,20 +460,7 @@ font: bold 16pt; background: transparent; font-size: 14pt; - - - - - - color: #95a5a6; -font-size: 14pt; - - - (click a script or use the 1-9 keys to load and run it) - - - true - + runningScriptsList From a69c6f8e29347cad604ddf1ffa279410765f9d4d Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Thu, 19 Jun 2014 23:58:31 +0530 Subject: [PATCH 12/88] Change pt to px to solve the Windows font size issue --- interface/src/ui/ScriptsTableWidget.cpp | 2 +- interface/ui/runningScriptsWidget.ui | 26 ++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/ScriptsTableWidget.cpp b/interface/src/ui/ScriptsTableWidget.cpp index 95acca052c..7b4f9e6b1f 100644 --- a/interface/src/ui/ScriptsTableWidget.cpp +++ b/interface/src/ui/ScriptsTableWidget.cpp @@ -23,7 +23,7 @@ ScriptsTableWidget::ScriptsTableWidget(QWidget* parent) : setShowGrid(false); setSelectionMode(QAbstractItemView::NoSelection); setEditTriggers(QAbstractItemView::NoEditTriggers); - setStyleSheet("QTableWidget { background: transparent; color: #333333; } QToolTip { color: #000000; background: #f9f6e4; padding: 2px; }"); + setStyleSheet("QTableWidget { border: none; background: transparent; color: #333333; } QToolTip { color: #000000; background: #f9f6e4; padding: 2px; }"); setToolTipDuration(200); setWordWrap(true); setGeometry(0, 0, parent->width(), parent->height()); diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 6cb23f4c89..d8d95cabc6 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -25,18 +25,18 @@ QWidget { 37 - 29 + 20 251 - 20 + 31 color: #0e7077; -font-size: 20pt; +font-size: 20px; background: transparent; - <html><head/><body><p><span style=" font-size:18pt;">Running Scripts</span></p></body></html> + <html><head/><body><p><span style=" font-size:18px;">Running Scripts</span></p></body></html> 0 @@ -56,7 +56,7 @@ background: transparent; color: #0e7077; -font: bold 14pt; +font: bold 14px; background: transparent; @@ -82,7 +82,7 @@ background: transparent; background: #0e7077; color: #fff; border-radius: 4px; -font: bold 14pt; +font: bold 14px; padding-top: 3px; @@ -105,7 +105,7 @@ padding-top: 3px; background: #0e7077; color: #fff; border-radius: 4px; -font: bold 14pt; +font: bold 14px; padding-top: 3px; @@ -123,7 +123,7 @@ padding-top: 3px; color: #0e7077; -font: bold 14pt; +font: bold 14px; <html><head/><body><p><span style=" font-weight:600;">Recently loaded</span></p></body></html> @@ -140,7 +140,7 @@ font: bold 14pt; color: #95a5a6; -font-size: 14pt; +font-size: 14px; (click a script to load and run it) @@ -184,7 +184,7 @@ font-size: 14pt; - font: 14pt; + font: 14px; There are no scripts currently running. @@ -204,7 +204,7 @@ font-size: 14pt; background: transparent; -font-size: 14pt; +font-size: 14px; @@ -218,7 +218,7 @@ font-size: 14pt; background: transparent; -font-size: 14pt; +font-size: 14px; @@ -237,7 +237,7 @@ font-size: 14pt; background: #0e7077; color: #fff; border-radius: 4px; -font: bold 14pt; +font: bold 14px; padding-top: 3px; From 108fa36d2461777eacfc1c284173424ae8543f7b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 20 Jun 2014 16:32:42 -0700 Subject: [PATCH 13/88] Disable the ability to load a script multiple times It won't show up correctly in running scripts, and can cause it to end up running in the background unnoticed. Also added an error message for when a script doesn't load. --- interface/src/Application.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 869fdc2770..72b0c79724 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3523,8 +3523,13 @@ void Application::saveScripts() { ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor, bool activateMainWindow) { QUrl scriptUrl(scriptName); const QString& scriptURLString = scriptUrl.toString(); - if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptURLString) && !_scriptEnginesHash[scriptURLString]->isFinished()){ - return _scriptEnginesHash[scriptURLString]; + if (_scriptEnginesHash.contains(scriptURLString)) { + if(loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { + return _scriptEnginesHash[scriptURLString]; + } else { + QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " is already running."); + return NULL; + } } ScriptEngine* scriptEngine; @@ -3536,6 +3541,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript if (!scriptEngine->hasScript()) { qDebug() << "Application::loadScript(), script failed to load..."; + QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " failed to load."); return NULL; } From ad41f2da9a631e4e2f362dfba4dc74916b86a89e Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sat, 21 Jun 2014 16:27:13 +0530 Subject: [PATCH 14/88] Make changes to other UI forms as well --- interface/ui/preferencesDialog.ui | 2 +- interface/ui/shareSnapshot.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index f00d7c4788..df33d09939 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -660,7 +660,7 @@ color: #0e7077 background: #0e7077; color: #fff; border-radius: 4px; -font: bold 14pt; +font: bold 14px; padding: 10px;margin-top:10px diff --git a/interface/ui/shareSnapshot.ui b/interface/ui/shareSnapshot.ui index df7fc4939f..19e0772f13 100644 --- a/interface/ui/shareSnapshot.ui +++ b/interface/ui/shareSnapshot.ui @@ -277,7 +277,7 @@ padding-left:20px; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Helvetica'; font-size:14pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Helvetica'; font-size:14px; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> From 1368c72725280654f82671b5d8d00af720965323 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sat, 21 Jun 2014 17:55:19 +0530 Subject: [PATCH 15/88] Keep the filter line edit of the Models Browser disabled until the models list has been populated. This fixes interface from crashing in case the user types in the line edit and the list is not populated. --- interface/src/ui/ModelsBrowser.cpp | 16 +++++++++++++--- interface/src/ui/ModelsBrowser.h | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 4296a096a0..8774fa5966 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -89,6 +89,10 @@ ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : _view.setEditTriggers(QAbstractItemView::NoEditTriggers); _view.setRootIsDecorated(false); _view.setModel(_handler->getModel()); + + _searchBar = new QLineEdit; + _searchBar->setDisabled(true); + connect(_handler, SIGNAL(doneDownloading()), SLOT(enableSearchBar())); } void ModelsBrowser::applyFilter(const QString &filter) { @@ -130,6 +134,10 @@ void ModelsBrowser::resizeView() { } } +void ModelsBrowser::enableSearchBar() { + _searchBar->setEnabled(true); +} + void ModelsBrowser::browse() { QDialog dialog; dialog.setWindowTitle("Browse models"); @@ -138,12 +146,14 @@ void ModelsBrowser::browse() { QGridLayout* layout = new QGridLayout(&dialog); dialog.setLayout(layout); - QLineEdit* searchBar = new QLineEdit(&dialog); - layout->addWidget(searchBar, 0, 0); + /*if (!_searchBar) { + _searchBar = new QLineEdit(&dialog); + }*/ + layout->addWidget(_searchBar, 0, 0); layout->addWidget(&_view, 1, 0); dialog.connect(&_view, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(accept())); - connect(searchBar, SIGNAL(textChanged(const QString&)), SLOT(applyFilter(const QString&))); + connect(_searchBar, SIGNAL(textChanged(const QString&)), SLOT(applyFilter(const QString&))); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttons, 2, 0); diff --git a/interface/src/ui/ModelsBrowser.h b/interface/src/ui/ModelsBrowser.h index ff273a45bc..3e832c9dbe 100644 --- a/interface/src/ui/ModelsBrowser.h +++ b/interface/src/ui/ModelsBrowser.h @@ -74,9 +74,11 @@ public slots: private slots: void applyFilter(const QString& filter); void resizeView(); + void enableSearchBar(); private: ModelHandler* _handler; + QLineEdit* _searchBar; QTreeView _view; }; From 1b186c3b92eab7f4f486d2950e5a706f287f0e41 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sat, 21 Jun 2014 17:57:11 +0530 Subject: [PATCH 16/88] Remove unnecessary lines of code. --- interface/src/ui/ModelsBrowser.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 8774fa5966..2a7fc13074 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -146,11 +146,7 @@ void ModelsBrowser::browse() { QGridLayout* layout = new QGridLayout(&dialog); dialog.setLayout(layout); - /*if (!_searchBar) { - _searchBar = new QLineEdit(&dialog); - }*/ layout->addWidget(_searchBar, 0, 0); - layout->addWidget(&_view, 1, 0); dialog.connect(&_view, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(accept())); connect(_searchBar, SIGNAL(textChanged(const QString&)), SLOT(applyFilter(const QString&))); From 803ea28f99c9dc0852a3e98aca8de1a702ec9b58 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sat, 21 Jun 2014 23:01:22 +0530 Subject: [PATCH 17/88] Do not close the Models Browser if double clicked on the loading message --- interface/src/ui/ModelsBrowser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 2a7fc13074..203c54d97a 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -89,7 +89,9 @@ ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : _view.setEditTriggers(QAbstractItemView::NoEditTriggers); _view.setRootIsDecorated(false); _view.setModel(_handler->getModel()); + _view.blockSignals(true); + // Initialize the search bar _searchBar = new QLineEdit; _searchBar->setDisabled(true); connect(_handler, SIGNAL(doneDownloading()), SLOT(enableSearchBar())); @@ -135,6 +137,7 @@ void ModelsBrowser::resizeView() { } void ModelsBrowser::enableSearchBar() { + _view.blockSignals(false); _searchBar->setEnabled(true); } From e72429171ff86589fc0384bc23420562ff1b7cb8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 23 Jun 2014 12:01:49 -0700 Subject: [PATCH 18/88] Working on congestion tests. --- tests/metavoxels/src/MetavoxelTests.cpp | 77 +++++++++++++++++++++---- tests/metavoxels/src/MetavoxelTests.h | 2 +- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 287d3a648c..609d36c085 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -335,7 +335,7 @@ bool MetavoxelTests::run() { QByteArray datagramHeader("testheader"); const int SIMULATION_ITERATIONS = 10000; if (test == 0 || test == 1) { - qDebug() << "Running transmission tests..."; + qDebug() << "Running transmission test..."; qDebug(); // create two endpoints with the same header @@ -365,7 +365,37 @@ bool MetavoxelTests::run() { } if (test == 0 || test == 2) { - qDebug() << "Running serialization tests..."; + qDebug() << "Running congestion control test..."; + qDebug(); + + // clear the stats + streamedBytesSent = streamedBytesReceived = datagramsSent = bytesSent = 0; + datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0; + + // create two endpoints with the same header + Endpoint alice(datagramHeader, Endpoint::CONGESTION_MODE), bob(datagramHeader, Endpoint::CONGESTION_MODE); + + alice.setOther(&bob); + bob.setOther(&alice); + + // perform a large number of simulation iterations + for (int i = 0; i < SIMULATION_ITERATIONS; i++) { + if (alice.simulate(i) || bob.simulate(i)) { + return true; + } + } + + qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; + qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << + datagramsReceived << "with" << bytesReceived << "bytes"; + qDebug() << "Max" << maxDatagramsPerPacket << "datagrams," << maxBytesPerPacket << "bytes per packet"; + qDebug() << "Average" << (bytesReceived / datagramsReceived) << "bytes per datagram"; + qDebug() << "Speed:" << (bytesReceived / SIMULATION_ITERATIONS) << "bytes per iteration"; + qDebug() << "Efficiency:" << ((float)streamedBytesReceived / bytesReceived); + } + + if (test == 0 || test == 3) { + qDebug() << "Running serialization test..."; qDebug(); if (testSerialization(Bitstream::HASH_METADATA) || testSerialization(Bitstream::FULL_METADATA)) { @@ -373,8 +403,8 @@ bool MetavoxelTests::run() { } } - if (test == 0 || test == 3) { - qDebug() << "Running metavoxel data tests..."; + if (test == 0 || test == 4) { + qDebug() << "Running metavoxel data test..."; qDebug(); // clear the stats @@ -498,9 +528,15 @@ Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) : ReliableChannel* output = _sequencer->getReliableOutputChannel(1); output->setPriority(0.25f); output->setMessagesEnabled(false); - const int MIN_STREAM_BYTES = 100000; - const int MAX_STREAM_BYTES = 200000; - QByteArray bytes = createRandomBytes(MIN_STREAM_BYTES, MAX_STREAM_BYTES); + QByteArray bytes; + if (mode == CONGESTION_MODE) { + const int HUGE_STREAM_BYTES = 50 * 1024 * 1024; + bytes = createRandomBytes(HUGE_STREAM_BYTES, HUGE_STREAM_BYTES); + } else { + const int MIN_STREAM_BYTES = 100000; + const int MAX_STREAM_BYTES = 200000; + bytes = createRandomBytes(MIN_STREAM_BYTES, MAX_STREAM_BYTES); + } _dataStreamed.append(bytes); output->getBuffer().write(bytes); streamedBytesSent += bytes.size(); @@ -646,7 +682,16 @@ bool Endpoint::simulate(int iterationNumber) { int oldDatagramsSent = datagramsSent; int oldBytesSent = bytesSent; - if (_mode == METAVOXEL_CLIENT_MODE) { + if (_mode == CONGESTION_MODE) { + Bitstream& out = _sequencer->startPacket(); + out << QVariant(); + _sequencer->endPacket(); + + // record the send + SendRecord record = { _sequencer->getOutgoingPacketNumber() }; + _sendRecords.append(record); + + } else if (_mode == METAVOXEL_CLIENT_MODE) { Bitstream& out = _sequencer->startPacket(); ClientStateMessage state = { _lod }; @@ -748,13 +793,14 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { // some datagrams are dropped const float DROP_PROBABILITY = 0.1f; - if (randFloat() < DROP_PROBABILITY) { + float probabilityMultiplier = (_mode == CONGESTION_MODE) ? 0.01f : 1.0f; + if (randFloat() < DROP_PROBABILITY * probabilityMultiplier) { return; } // some are received out of order const float REORDER_PROBABILITY = 0.1f; - if (randFloat() < REORDER_PROBABILITY) { + if (randFloat() < REORDER_PROBABILITY * probabilityMultiplier) { const int MIN_DELAY = 1; const int MAX_DELAY = 5; // have to copy the datagram; the one we're passed is a reference to a shared buffer @@ -763,7 +809,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { // and some are duplicated const float DUPLICATE_PROBABILITY = 0.01f; - if (randFloat() > DUPLICATE_PROBABILITY) { + if (randFloat() > DUPLICATE_PROBABILITY * probabilityMultiplier) { return; } } @@ -788,6 +834,15 @@ void Endpoint::handleHighPriorityMessage(const QVariant& message) { } void Endpoint::readMessage(Bitstream& in) { + if (_mode == CONGESTION_MODE) { + QVariant message; + in >> message; + + // record the receipt + ReceiveRecord record = { _sequencer->getIncomingPacketNumber() }; + _receiveRecords.append(record); + return; + } if (_mode == METAVOXEL_CLIENT_MODE) { QVariant message; in >> message; diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index c340d78963..46bac319fa 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -40,7 +40,7 @@ class Endpoint : public QObject { public: - enum Mode { BASIC_PEER_MODE, METAVOXEL_SERVER_MODE, METAVOXEL_CLIENT_MODE }; + enum Mode { BASIC_PEER_MODE, CONGESTION_MODE, METAVOXEL_SERVER_MODE, METAVOXEL_CLIENT_MODE }; Endpoint(const QByteArray& datagramHeader, Mode mode = BASIC_PEER_MODE); From 556578b8dc83ef130935630410f3994b2fe361a0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Jun 2014 09:30:11 -0700 Subject: [PATCH 19/88] first pass - hair as vertlet strands --- examples/sit.js | 8 +- examples/squeezeHands.js | 4 +- interface/src/Application.cpp | 4 +- interface/src/Util.cpp | 1 + interface/src/avatar/Avatar.cpp | 192 ++++++++++++++++++++++++++++++ interface/src/avatar/Avatar.h | 24 ++++ interface/src/avatar/MyAvatar.cpp | 4 + 7 files changed, 229 insertions(+), 8 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index d10c08c95a..87b4f232ca 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -49,12 +49,12 @@ var pose = [ {joint:"RightFoot", rotation: {x:30, y:15.0, z:0.0}}, {joint:"LeftUpLeg", rotation: {x:100.0, y:-15.0, z:0.0}}, {joint:"LeftLeg", rotation: {x:-130.0, y:-15.0, z:0.0}}, - {joint:"LeftFoot", rotation: {x:30, y:15.0, z:0.0}}, + {joint:"LeftFoot", rotation: {x:30, y:15.0, z:0.0}} - {joint:"Spine2", rotation: {x:20, y:0.0, z:0.0}}, + //{joint:"Spine2", rotation: {x:20, y:0.0, z:0.0}}, - {joint:"RightShoulder", rotation: {x:0.0, y:40.0, z:0.0}}, - {joint:"LeftShoulder", rotation: {x:0.0, y:-40.0, z:0.0}} + //{joint:"RightShoulder", rotation: {x:0.0, y:40.0, z:0.0}}, + //{joint:"LeftShoulder", rotation: {x:0.0, y:-40.0, z:0.0}} ]; diff --git a/examples/squeezeHands.js b/examples/squeezeHands.js index e53dd9569c..da720734e1 100644 --- a/examples/squeezeHands.js +++ b/examples/squeezeHands.js @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/RightHandAnim.fbx"; -var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/LeftHandAnim.fbx"; +var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/RightHandAnimPhilip.fbx"; +var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/LeftHandAnimPhilip.fbx"; var LEFT = 0; var RIGHT = 1; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6b44503af4..9c257a7658 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -133,7 +133,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _nodeThread(new QThread(this)), _datagramProcessor(), _frameCount(0), - _fps(120.0f), + _fps(60.0f), _justStarted(true), _voxelImporter(NULL), _importSucceded(false), @@ -550,7 +550,7 @@ void Application::initializeGL() { } // update before the first render - update(0.0f); + update(1.f / _fps); InfoView::showFirstTime(); } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 07ca65b286..30fda645ca 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -66,6 +66,7 @@ void printVector(glm::vec3 vec) { qDebug("%4.2f, %4.2f, %4.2f", vec.x, vec.y, vec.z); } + // Return the azimuth angle (in radians) between two points. float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos) { return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index baf46605fd..95399062ae 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -48,6 +48,10 @@ Avatar::Avatar() : _skeletonModel(this), _bodyYawDelta(0.0f), _velocity(0.0f, 0.0f, 0.0f), + _lastVelocity(0.0f, 0.0f, 0.0f), + _acceleration(0.0f, 0.0f, 0.0f), + _angularVelocity(0.0f, 0.0f, 0.0f), + _lastOrientation(), _leanScale(0.5f), _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), @@ -76,6 +80,7 @@ void Avatar::init() { _skeletonModel.init(); _initialized = true; _shouldRenderBillboard = (getLODDistance() >= BILLBOARD_LOD_DISTANCE); + initializeHair(); } glm::vec3 Avatar::getChestPosition() const { @@ -134,10 +139,13 @@ void Avatar::simulate(float deltaTime) { head->setPosition(headPosition); head->setScale(_scale); head->simulate(deltaTime, false, _shouldRenderBillboard); + + simulateHair(deltaTime); } // update position by velocity, and subtract the change added earlier for gravity _position += _velocity * deltaTime; + updateAcceleration(deltaTime); // update animation for display name fade in/out if ( _displayNameTargetAlpha != _displayNameAlpha) { @@ -157,6 +165,17 @@ void Avatar::simulate(float deltaTime) { } } +void Avatar::updateAcceleration(float deltaTime) { + // Linear Component of Acceleration + _acceleration = (_velocity - _lastVelocity) * (1.f / deltaTime); + _lastVelocity = _velocity; + // Angular Component of Acceleration + glm::quat orientation = getOrientation(); + glm::quat delta = glm::inverse(_lastOrientation) * orientation; + _angularVelocity = safeEulerAngles(delta) * (1.f / deltaTime); + _lastOrientation = getOrientation(); +} + void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { _mouseRayOrigin = origin; _mouseRayDirection = direction; @@ -361,6 +380,179 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { getHand()->render(false, modelRenderMode); } getHead()->render(1.0f, modelRenderMode); + renderHair(); +} + +const float HAIR_LENGTH = 0.5f; +const float HAIR_LINK_LENGTH = HAIR_LENGTH / HAIR_LINKS; +const float HAIR_DAMPING = 0.99f; +const float HEAD_RADIUS = 0.20f; +const float COLLISION_RELAXATION = 10.f; +const float CONSTRAINT_RELAXATION = 10.0f; +const float NOISE = 0.0f; // 0.1f; +const float NOISE_MAGNITUDE = 0.02f; +const glm::vec3 HAIR_GRAVITY(0.f, -0.05f, 0.f); +const float HAIR_ACCELERATION_COUPLING = 0.025f; +const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.15f; +const float HAIR_MAX_LINEAR_ACCELERATION = 5.f; +const float HAIR_THICKNESS = 0.015f; +const glm::vec3 HAIR_COLOR1(0.98f, 0.92f, 0.843f); +const glm::vec3 HAIR_COLOR2(0.545f, 0.533f, 0.47f); + +void Avatar::renderHair() { + // + // Render the avatar's moveable hair + // + glm::vec3 headPosition = getHead()->getPosition(); + + glPushMatrix(); + glTranslatef(headPosition.x, headPosition.y, headPosition.z); + const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame(); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + glBegin(GL_QUADS); + for (int strand = 0; strand < HAIR_STRANDS; strand++) { + for (int link = 0; link < HAIR_LINKS - 1; link++) { + int vertexIndex = strand * HAIR_LINKS + link; + glColor3fv(&_hairColors[vertexIndex].x); + glNormal3fv(&_hairNormals[vertexIndex].x); + glVertex3f(_hairPosition[vertexIndex].x - _hairQuadDelta[vertexIndex].x, + _hairPosition[vertexIndex].y - _hairQuadDelta[vertexIndex].y, + _hairPosition[vertexIndex].z - _hairQuadDelta[vertexIndex].z); + glVertex3f(_hairPosition[vertexIndex].x + _hairQuadDelta[vertexIndex].x, + _hairPosition[vertexIndex].y + _hairQuadDelta[vertexIndex].y, + _hairPosition[vertexIndex].z + _hairQuadDelta[vertexIndex].z); + + glVertex3f(_hairPosition[vertexIndex + 1].x + _hairQuadDelta[vertexIndex].x, + _hairPosition[vertexIndex + 1].y + _hairQuadDelta[vertexIndex].y, + _hairPosition[vertexIndex + 1].z + _hairQuadDelta[vertexIndex].z); + glVertex3f(_hairPosition[vertexIndex + 1].x - _hairQuadDelta[vertexIndex].x, + _hairPosition[vertexIndex + 1].y - _hairQuadDelta[vertexIndex].y, + _hairPosition[vertexIndex + 1].z - _hairQuadDelta[vertexIndex].z); + } + } + glEnd(); + + //glColor4f(1.0f, 0.0f, 0.0f, 0.5f); + //glutSolidSphere(HEAD_RADIUS, 20, 20); + glPopMatrix(); + +} + +void Avatar::simulateHair(float deltaTime) { + deltaTime = glm::clamp(deltaTime, 0.f, 1.f / 30.f); + glm::vec3 acceleration = getAcceleration(); + if (glm::length(acceleration) > HAIR_MAX_LINEAR_ACCELERATION) { + acceleration = glm::normalize(acceleration) * HAIR_MAX_LINEAR_ACCELERATION; + } + const glm::quat& rotation = getHead()->getFinalOrientationInWorldFrame(); + acceleration = acceleration * rotation; + glm::vec3 angularVelocity = getAngularVelocity() + getHead()->getAngularVelocity(); + + for (int strand = 0; strand < HAIR_STRANDS; strand++) { + for (int link = 0; link < HAIR_LINKS; link++) { + int vertexIndex = strand * HAIR_LINKS + link; + if (vertexIndex % HAIR_LINKS == 0) { + // Base Joint - no integration + if (randFloat() < NOISE) { + // Move base of hair + _hairPosition[vertexIndex] += randVector() * NOISE_MAGNITUDE; + } + } else { + // + // Vertlet Integration + // + // Add velocity from last position, with damping + glm::vec3 thisPosition = _hairPosition[vertexIndex]; + glm::vec3 diff = thisPosition - _hairLastPosition[vertexIndex]; + _hairPosition[vertexIndex] += diff * HAIR_DAMPING; + // Attempt to resolve collision with head sphere + if (glm::length(_hairPosition[vertexIndex]) < HEAD_RADIUS) { + _hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex]) * + (HEAD_RADIUS - glm::length(_hairPosition[vertexIndex])) * COLLISION_RELAXATION * deltaTime; + } + // Add a little gravity + _hairPosition[vertexIndex] += HAIR_GRAVITY * rotation * deltaTime; + + // Add linear acceleration of the avatar body + _hairPosition[vertexIndex] -= acceleration * HAIR_ACCELERATION_COUPLING * deltaTime; + + const float ANGULAR_VELOCITY_MIN = 0.001f; + // Add angular acceleration of the avatar body + if (glm::length(angularVelocity) > ANGULAR_VELOCITY_MIN) { + glm::vec3 yawVector = _hairPosition[vertexIndex]; + yawVector.y = 0.f; + if (glm::length(yawVector) > EPSILON) { + float radius = glm::length(yawVector); + yawVector = glm::normalize(yawVector); + float angle = atan2f(yawVector.x, -yawVector.z) + PI; + glm::vec3 delta = glm::vec3(-1.f, 0.f, 0.f) * glm::angleAxis(angle, glm::vec3(0, 1, 0)); + _hairPosition[vertexIndex] -= delta * radius * angularVelocity.y * HAIR_ANGULAR_VELOCITY_COUPLING * deltaTime; + } + } + + // Iterate length constraints to other links + for (int link = 0; link < HAIR_MAX_CONSTRAINTS; link++) { + if (_hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + link] > -1) { + // If there is a constraint, try to enforce it + glm::vec3 vectorBetween = _hairPosition[_hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + link]] - _hairPosition[vertexIndex]; + _hairPosition[vertexIndex] += glm::normalize(vectorBetween) * (glm::length(vectorBetween) - HAIR_LINK_LENGTH) * CONSTRAINT_RELAXATION * deltaTime; + } + } + // Store start position for next vertlet pass + _hairLastPosition[vertexIndex] = thisPosition; + } + } + } +} + +void Avatar::initializeHair() { + const float FACE_WIDTH = 0.25f * PI; + glm::vec3 thisVertex; + for (int strand = 0; strand < HAIR_STRANDS; strand++) { + float strandAngle = randFloat() * PI; + float azimuth = randFloat() * 2.f * PI; + float elevation; + if ((azimuth > FACE_WIDTH) || (azimuth < -FACE_WIDTH)) { + elevation = randFloat() * PI_OVER_TWO; + } else { + elevation = (PI_OVER_TWO / 2.f) + randFloat() * (PI_OVER_TWO / 2.f); + } + glm::vec3 thisStrand(sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation)); + thisStrand *= HEAD_RADIUS + 0.01f; + + for (int link = 0; link < HAIR_LINKS; link++) { + int vertexIndex = strand * HAIR_LINKS + link; + // Clear constraints + for (int link = 0; link < HAIR_MAX_CONSTRAINTS; link++) { + _hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + link] = -1; + } + if (vertexIndex % HAIR_LINKS == 0) { + // start of strand + thisVertex = thisStrand; + } else { + thisVertex+= glm::normalize(thisStrand) * HAIR_LINK_LENGTH; + // Set constraints to vertex before and maybe vertex after in strand + _hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS] = vertexIndex - 1; + if (link < (HAIR_LINKS - 1)) { + _hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + 1] = vertexIndex + 1; + } + } + _hairPosition[vertexIndex] = thisVertex; + _hairLastPosition[vertexIndex] = _hairPosition[vertexIndex]; + + _hairQuadDelta[vertexIndex] = glm::vec3(cos(strandAngle) * HAIR_THICKNESS, 0.f, sin(strandAngle) * HAIR_THICKNESS); + _hairNormals[vertexIndex] = glm::normalize(randVector()); + if (randFloat() < elevation / PI_OVER_TWO) { + _hairColors[vertexIndex] = HAIR_COLOR1 * ((float)(link + 1) / (float)HAIR_LINKS); + } else { + _hairColors[vertexIndex] = HAIR_COLOR2 * ((float)(link + 1) / (float)HAIR_LINKS); + } + + } + } + qDebug() << "Initialize Hair"; } bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f928881068..cf45cdf07f 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -32,6 +32,10 @@ static const float RESCALING_TOLERANCE = .02f; extern const float CHAT_MESSAGE_SCALE; extern const float CHAT_MESSAGE_HEIGHT; +const int HAIR_STRANDS = 100; // Number of strands of hair +const int HAIR_LINKS = 10; // Number of links in a hair strand +const int HAIR_MAX_CONSTRAINTS = 2; + enum DriveKeys { FWD = 0, BACK, @@ -158,6 +162,9 @@ public: Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const; Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const; + glm::vec3 getAcceleration() const { return _acceleration; } + glm::vec3 getAngularVelocity() const { return _angularVelocity; } + public slots: void updateCollisionGroups(); @@ -169,6 +176,10 @@ protected: QVector _attachmentModels; float _bodyYawDelta; glm::vec3 _velocity; + glm::vec3 _lastVelocity; + glm::vec3 _acceleration; + glm::vec3 _angularVelocity; + glm::quat _lastOrientation; float _leanScale; float _scale; glm::vec3 _worldUpDirection; @@ -185,6 +196,7 @@ protected: glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; void setScale(float scale); + void updateAcceleration(float deltaTime); float getSkeletonHeight() const; float getHeadHeight() const; @@ -200,6 +212,17 @@ protected: virtual void renderAttachments(RenderMode renderMode); virtual void updateJointMappings(); + + glm::vec3 _hairPosition[HAIR_STRANDS * HAIR_LINKS]; + glm::vec3 _hairLastPosition[HAIR_STRANDS * HAIR_LINKS]; + glm::vec3 _hairQuadDelta[HAIR_STRANDS * HAIR_LINKS]; + glm::vec3 _hairNormals[HAIR_STRANDS * HAIR_LINKS]; + glm::vec3 _hairColors[HAIR_STRANDS * HAIR_LINKS]; + int _hairIsMoveable[HAIR_STRANDS * HAIR_LINKS]; + int _hairConstraints[HAIR_STRANDS * HAIR_LINKS * 2]; // Hair can link to two others + void renderHair(); + void simulateHair(float deltaTime); + void initializeHair(); private: @@ -211,6 +234,7 @@ private: void renderBillboard(); float getBillboardSize() const; + }; #endif // hifi_Avatar_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 54ed641d72..66f10e68c6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -188,6 +188,8 @@ void MyAvatar::simulate(float deltaTime) { head->setScale(_scale); head->simulate(deltaTime, true); } + + simulateHair(deltaTime); // now that we're done stepping the avatar forward in time, compute new collisions if (_collisionGroups != 0) { @@ -814,6 +816,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { getHead()->render(1.0f, modelRenderMode); } getHand()->render(true, modelRenderMode); + renderHair(); } const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; @@ -955,6 +958,7 @@ void MyAvatar::updatePosition(float deltaTime) { } else { _position += _velocity * deltaTime; } + updateAcceleration(deltaTime); } // update moving flag based on speed From 652543cdca28a00de94dff8a848e54e62091311d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jun 2014 11:46:35 -0700 Subject: [PATCH 20/88] Update _scriptEngineHash to work with duplicate running scripts --- interface/src/Application.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 72b0c79724..c3e8876a82 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3524,11 +3524,8 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript QUrl scriptUrl(scriptName); const QString& scriptURLString = scriptUrl.toString(); if (_scriptEnginesHash.contains(scriptURLString)) { - if(loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { + if (loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { return _scriptEnginesHash[scriptURLString]; - } else { - QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " is already running."); - return NULL; } } @@ -3545,7 +3542,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript return NULL; } - _scriptEnginesHash.insert(scriptURLString, scriptEngine); + _scriptEnginesHash.insertMulti(scriptURLString, scriptEngine); _runningScriptsWidget->setRunningScripts(getRunningScripts()); } @@ -3617,7 +3614,9 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript } void Application::scriptFinished(const QString& scriptName) { - if (_scriptEnginesHash.remove(scriptName)) { + QHash::iterator it = _scriptEnginesHash.find(scriptName); + if (it != _scriptEnginesHash.end()) { + _scriptEnginesHash.erase(it); _runningScriptsWidget->scriptStopped(scriptName); _runningScriptsWidget->setRunningScripts(getRunningScripts()); bumpSettings(); From 89f43acb7faf16f12f166f3cc548eac3ccaac061 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jun 2014 11:47:14 -0700 Subject: [PATCH 21/88] Add a tooltip with the full path to running scripts --- interface/src/ui/RunningScriptsWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index b2ee36d1fe..136d0a2d38 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -130,6 +130,8 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) { row->layout()->addWidget(name); row->layout()->addWidget(closeButton); + row->setToolTip(url.toString()); + QFrame* line = new QFrame(row); line->setFrameShape(QFrame::HLine); line->setStyleSheet("color: #E1E1E1; margin-left: 6px; margin-right: 6px;"); From f249020d6d028f35bc004e1d6a890be19fcb6491 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jun 2014 11:50:54 -0700 Subject: [PATCH 22/88] Clean up redundant if statement --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c3e8876a82..e74b5fd58a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3523,10 +3523,10 @@ void Application::saveScripts() { ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor, bool activateMainWindow) { QUrl scriptUrl(scriptName); const QString& scriptURLString = scriptUrl.toString(); - if (_scriptEnginesHash.contains(scriptURLString)) { - if (loadScriptFromEditor && !_scriptEnginesHash[scriptURLString]->isFinished()) { - return _scriptEnginesHash[scriptURLString]; - } + if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor + && !_scriptEnginesHash[scriptURLString]->isFinished()) { + + return _scriptEnginesHash[scriptURLString]; } ScriptEngine* scriptEngine; From afe2e577015d09c218897f2f9d3790c1dfe3b52d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 24 Jun 2014 12:33:40 -0700 Subject: [PATCH 23/88] add a settings page to DS that uses handlebars template library --- domain-server/CMakeLists.txt | 6 ++-- .../resources/web/js/handlebars-v1.3.0.min.js | 28 +++++++++++++++++++ domain-server/resources/web/js/settings.js | 8 ++++++ .../resources/web/settings/describe.json | 10 +++++++ .../resources/web/settings/index.shtml | 13 +++++++++ domain-server/src/DomainServer.cpp | 2 +- .../src/DomainServerSettingsManager.cpp | 12 ++++++++ .../src/DomainServerSettingsManager.h | 21 ++++++++++++++ 8 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 domain-server/resources/web/js/handlebars-v1.3.0.min.js create mode 100644 domain-server/resources/web/js/settings.js create mode 100644 domain-server/resources/web/settings/describe.json create mode 100644 domain-server/resources/web/settings/index.shtml create mode 100644 domain-server/src/DomainServerSettingsManager.cpp create mode 100644 domain-server/src/DomainServerSettingsManager.h diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index f9bbeb31fc..5650737965 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -25,11 +25,11 @@ setup_hifi_project(${TARGET_NAME} TRUE) # remove and then copy the files for the webserver add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E remove_directory - $/resources/web) + $/resources) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${PROJECT_SOURCE_DIR}/resources/web" - $/resources/web) + "${PROJECT_SOURCE_DIR}/resources" + $/resources) # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/domain-server/resources/web/js/handlebars-v1.3.0.min.js b/domain-server/resources/web/js/handlebars-v1.3.0.min.js new file mode 100644 index 0000000000..06e9c01623 --- /dev/null +++ b/domain-server/resources/web/js/handlebars-v1.3.0.min.js @@ -0,0 +1,28 @@ +/*! + + handlebars v1.3.0 + +Copyright (C) 2011 by Yehuda Katz + +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. + +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. + +@license +*/ +var Handlebars=function(){var a=function(){"use strict";function a(a){this.string=a}var b;return a.prototype.toString=function(){return""+this.string},b=a}(),b=function(a){"use strict";function b(a){return h[a]||"&"}function c(a,b){for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&(a[c]=b[c])}function d(a){return a instanceof g?a.toString():a||0===a?(a=""+a,j.test(a)?a.replace(i,b):a):""}function e(a){return a||0===a?m(a)&&0===a.length?!0:!1:!0}var f={},g=a,h={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},i=/[&<>"'`]/g,j=/[&<>"'`]/;f.extend=c;var k=Object.prototype.toString;f.toString=k;var l=function(a){return"function"==typeof a};l(/x/)&&(l=function(a){return"function"==typeof a&&"[object Function]"===k.call(a)});var l;f.isFunction=l;var m=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===k.call(a):!1};return f.isArray=m,f.escapeExpression=d,f.isEmpty=e,f}(a),c=function(){"use strict";function a(a,b){var d;b&&b.firstLine&&(d=b.firstLine,a+=" - "+d+":"+b.firstColumn);for(var e=Error.prototype.constructor.call(this,a),f=0;f0?a.helpers.each(b,c):d(this):e(b)}),a.registerHelper("each",function(a,b){var c,d=b.fn,e=b.inverse,f=0,g="";if(m(a)&&(a=a.call(this)),b.data&&(c=q(b.data)),a&&"object"==typeof a)if(l(a))for(var h=a.length;h>f;f++)c&&(c.index=f,c.first=0===f,c.last=f===a.length-1),g+=d(a[f],{data:c});else for(var i in a)a.hasOwnProperty(i)&&(c&&(c.key=i,c.index=f,c.first=0===f),g+=d(a[i],{data:c}),f++);return 0===f&&(g=e(this)),g}),a.registerHelper("if",function(a,b){return m(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||g.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})}),a.registerHelper("with",function(a,b){return m(a)&&(a=a.call(this)),g.isEmpty(a)?void 0:b.fn(a)}),a.registerHelper("log",function(b,c){var d=c.data&&null!=c.data.level?parseInt(c.data.level,10):1;a.log(d,b)})}function e(a,b){p.log(a,b)}var f={},g=a,h=b,i="1.3.0";f.VERSION=i;var j=4;f.COMPILER_REVISION=j;var k={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:">= 1.0.0"};f.REVISION_CHANGES=k;var l=g.isArray,m=g.isFunction,n=g.toString,o="[object Object]";f.HandlebarsEnvironment=c,c.prototype={constructor:c,logger:p,log:e,registerHelper:function(a,b,c){if(n.call(a)===o){if(c||b)throw new h("Arg not supported with multiple helpers");g.extend(this.helpers,a)}else c&&(b.not=c),this.helpers[a]=b},registerPartial:function(a,b){n.call(a)===o?g.extend(this.partials,a):this.partials[a]=b}};var p={methodMap:{0:"debug",1:"info",2:"warn",3:"error"},DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,log:function(a,b){if(p.level<=a){var c=p.methodMap[a];"undefined"!=typeof console&&console[c]&&console[c].call(console,b)}}};f.logger=p,f.log=e;var q=function(a){var b={};return g.extend(b,a),b};return f.createFrame=q,f}(b,c),e=function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=m;if(b!==c){if(c>b){var d=n[c],e=n[b];throw new l("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new l("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){if(!b)throw new l("No environment passed to template");var c=function(a,c,d,e,f,g){var h=b.VM.invokePartial.apply(this,arguments);if(null!=h)return h;if(b.compile){var i={helpers:e,partials:f,data:g};return f[c]=b.compile(a,{data:void 0!==g},b),f[c](d,i)}throw new l("The partial "+c+" could not be compiled when running in runtime-only mode")},d={escapeExpression:k.escapeExpression,invokePartial:c,programs:[],program:function(a,b,c){var d=this.programs[a];return c?d=g(a,b,c):d||(d=this.programs[a]=g(a,b)),d},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c={},k.extend(c,b),k.extend(c,a)),c},programWithDepth:b.VM.programWithDepth,noop:b.VM.noop,compilerInfo:null};return function(c,e){e=e||{};var f,g,h=e.partial?e:b;e.partial||(f=e.helpers,g=e.partials);var i=a.call(d,h,c,f,g,e.data);return e.partial||b.VM.checkRevision(d.compilerInfo),i}}function f(a,b,c){var d=Array.prototype.slice.call(arguments,3),e=function(a,e){return e=e||{},b.apply(this,[a,e.data||c].concat(d))};return e.program=a,e.depth=d.length,e}function g(a,b,c){var d=function(a,d){return d=d||{},b(a,d.data||c)};return d.program=a,d.depth=0,d}function h(a,b,c,d,e,f){var g={partial:!0,helpers:d,partials:e,data:f};if(void 0===a)throw new l("The partial "+b+" could not be found");return a instanceof Function?a(c,g):void 0}function i(){return""}var j={},k=a,l=b,m=c.COMPILER_REVISION,n=c.REVISION_CHANGES;return j.checkRevision=d,j.template=e,j.programWithDepth=f,j.program=g,j.invokePartial=h,j.noop=i,j}(b,c,d),f=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c,j=d,k=e,l=function(){var a=new g.HandlebarsEnvironment;return j.extend(a,g),a.SafeString=h,a.Exception=i,a.Utils=j,a.VM=k,a.template=function(b){return k.template(b,a)},a},m=l();return m.create=l,f=m}(d,a,c,b,e),g=function(a){"use strict";function b(a){a=a||{},this.firstLine=a.first_line,this.firstColumn=a.first_column,this.lastColumn=a.last_column,this.lastLine=a.last_line}var c,d=a,e={ProgramNode:function(a,c,d,f){var g,h;3===arguments.length?(f=d,d=null):2===arguments.length&&(f=c,c=null),b.call(this,f),this.type="program",this.statements=a,this.strip={},d?(h=d[0],h?(g={first_line:h.firstLine,last_line:h.lastLine,last_column:h.lastColumn,first_column:h.firstColumn},this.inverse=new e.ProgramNode(d,c,g)):this.inverse=new e.ProgramNode(d,c),this.strip.right=c.left):c&&(this.strip.left=c.right)},MustacheNode:function(a,c,d,f,g){if(b.call(this,g),this.type="mustache",this.strip=f,null!=d&&d.charAt){var h=d.charAt(3)||d.charAt(2);this.escaped="{"!==h&&"&"!==h}else this.escaped=!!d;this.sexpr=a instanceof e.SexprNode?a:new e.SexprNode(a,c),this.sexpr.isRoot=!0,this.id=this.sexpr.id,this.params=this.sexpr.params,this.hash=this.sexpr.hash,this.eligibleHelper=this.sexpr.eligibleHelper,this.isHelper=this.sexpr.isHelper},SexprNode:function(a,c,d){b.call(this,d),this.type="sexpr",this.hash=c;var e=this.id=a[0],f=this.params=a.slice(1),g=this.eligibleHelper=e.isSimple;this.isHelper=g&&(f.length||c)},PartialNode:function(a,c,d,e){b.call(this,e),this.type="partial",this.partialName=a,this.context=c,this.strip=d},BlockNode:function(a,c,e,f,g){if(b.call(this,g),a.sexpr.id.original!==f.path.original)throw new d(a.sexpr.id.original+" doesn't match "+f.path.original,this);this.type="block",this.mustache=a,this.program=c,this.inverse=e,this.strip={left:a.strip.left,right:f.strip.right},(c||e).strip.left=a.strip.right,(e||c).strip.right=f.strip.left,e&&!c&&(this.isInverse=!0)},ContentNode:function(a,c){b.call(this,c),this.type="content",this.string=a},HashNode:function(a,c){b.call(this,c),this.type="hash",this.pairs=a},IdNode:function(a,c){b.call(this,c),this.type="ID";for(var e="",f=[],g=0,h=0,i=a.length;i>h;h++){var j=a[h].part;if(e+=(a[h].separator||"")+j,".."===j||"."===j||"this"===j){if(f.length>0)throw new d("Invalid path: "+e,this);".."===j?g++:this.isScoped=!0}else f.push(j)}this.original=e,this.parts=f,this.string=f.join("."),this.depth=g,this.isSimple=1===a.length&&!this.isScoped&&0===g,this.stringModeValue=this.string},PartialNameNode:function(a,c){b.call(this,c),this.type="PARTIAL_NAME",this.name=a.original},DataNode:function(a,c){b.call(this,c),this.type="DATA",this.id=a},StringNode:function(a,c){b.call(this,c),this.type="STRING",this.original=this.string=this.stringModeValue=a},IntegerNode:function(a,c){b.call(this,c),this.type="INTEGER",this.original=this.integer=a,this.stringModeValue=Number(a)},BooleanNode:function(a,c){b.call(this,c),this.type="BOOLEAN",this.bool=a,this.stringModeValue="true"===a},CommentNode:function(a,c){b.call(this,c),this.type="comment",this.comment=a}};return c=e}(c),h=function(){"use strict";var a,b=function(){function a(a,b){return{left:"~"===a.charAt(2),right:"~"===b.charAt(0)||"~"===b.charAt(1)}}function b(){this.yy={}}var c={trace:function(){},yy:{},symbols_:{error:2,root:3,statements:4,EOF:5,program:6,simpleInverse:7,statement:8,openInverse:9,closeBlock:10,openBlock:11,mustache:12,partial:13,CONTENT:14,COMMENT:15,OPEN_BLOCK:16,sexpr:17,CLOSE:18,OPEN_INVERSE:19,OPEN_ENDBLOCK:20,path:21,OPEN:22,OPEN_UNESCAPED:23,CLOSE_UNESCAPED:24,OPEN_PARTIAL:25,partialName:26,partial_option0:27,sexpr_repetition0:28,sexpr_option0:29,dataName:30,param:31,STRING:32,INTEGER:33,BOOLEAN:34,OPEN_SEXPR:35,CLOSE_SEXPR:36,hash:37,hash_repetition_plus0:38,hashSegment:39,ID:40,EQUALS:41,DATA:42,pathSegments:43,SEP:44,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",32:"STRING",33:"INTEGER",34:"BOOLEAN",35:"OPEN_SEXPR",36:"CLOSE_SEXPR",40:"ID",41:"EQUALS",42:"DATA",44:"SEP"},productions_:[0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,4],[7,2],[17,3],[17,1],[31,1],[31,1],[31,1],[31,1],[31,1],[31,3],[37,1],[39,3],[26,1],[26,1],[26,1],[30,2],[21,1],[43,3],[43,1],[27,0],[27,1],[28,0],[28,2],[29,0],[29,1],[38,1],[38,2]],performAction:function(b,c,d,e,f,g){var h=g.length-1;switch(f){case 1:return new e.ProgramNode(g[h-1],this._$);case 2:return new e.ProgramNode([],this._$);case 3:this.$=new e.ProgramNode([],g[h-1],g[h],this._$);break;case 4:this.$=new e.ProgramNode(g[h-2],g[h-1],g[h],this._$);break;case 5:this.$=new e.ProgramNode(g[h-1],g[h],[],this._$);break;case 6:this.$=new e.ProgramNode(g[h],this._$);break;case 7:this.$=new e.ProgramNode([],this._$);break;case 8:this.$=new e.ProgramNode([],this._$);break;case 9:this.$=[g[h]];break;case 10:g[h-1].push(g[h]),this.$=g[h-1];break;case 11:this.$=new e.BlockNode(g[h-2],g[h-1].inverse,g[h-1],g[h],this._$);break;case 12:this.$=new e.BlockNode(g[h-2],g[h-1],g[h-1].inverse,g[h],this._$);break;case 13:this.$=g[h];break;case 14:this.$=g[h];break;case 15:this.$=new e.ContentNode(g[h],this._$);break;case 16:this.$=new e.CommentNode(g[h],this._$);break;case 17:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 18:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 19:this.$={path:g[h-1],strip:a(g[h-2],g[h])};break;case 20:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 21:this.$=new e.MustacheNode(g[h-1],null,g[h-2],a(g[h-2],g[h]),this._$);break;case 22:this.$=new e.PartialNode(g[h-2],g[h-1],a(g[h-3],g[h]),this._$);break;case 23:this.$=a(g[h-1],g[h]);break;case 24:this.$=new e.SexprNode([g[h-2]].concat(g[h-1]),g[h],this._$);break;case 25:this.$=new e.SexprNode([g[h]],null,this._$);break;case 26:this.$=g[h];break;case 27:this.$=new e.StringNode(g[h],this._$);break;case 28:this.$=new e.IntegerNode(g[h],this._$);break;case 29:this.$=new e.BooleanNode(g[h],this._$);break;case 30:this.$=g[h];break;case 31:g[h-1].isHelper=!0,this.$=g[h-1];break;case 32:this.$=new e.HashNode(g[h],this._$);break;case 33:this.$=[g[h-2],g[h]];break;case 34:this.$=new e.PartialNameNode(g[h],this._$);break;case 35:this.$=new e.PartialNameNode(new e.StringNode(g[h],this._$),this._$);break;case 36:this.$=new e.PartialNameNode(new e.IntegerNode(g[h],this._$));break;case 37:this.$=new e.DataNode(g[h],this._$);break;case 38:this.$=new e.IdNode(g[h],this._$);break;case 39:g[h-2].push({part:g[h],separator:g[h-1]}),this.$=g[h-2];break;case 40:this.$=[{part:g[h]}];break;case 43:this.$=[];break;case 44:g[h-1].push(g[h]);break;case 47:this.$=[g[h]];break;case 48:g[h-1].push(g[h])}},table:[{3:1,4:2,5:[1,3],8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[3]},{5:[1,16],8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[2,2]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{4:20,6:18,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{4:20,6:22,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{17:23,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:29,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:30,21:24,30:25,40:[1,28],42:[1,27],43:26},{17:31,21:24,30:25,40:[1,28],42:[1,27],43:26},{21:33,26:32,32:[1,34],33:[1,35],40:[1,28],43:26},{1:[2,1]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{10:36,20:[1,37]},{4:38,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,7],22:[1,13],23:[1,14],25:[1,15]},{7:39,8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,6],22:[1,13],23:[1,14],25:[1,15]},{17:23,18:[1,40],21:24,30:25,40:[1,28],42:[1,27],43:26},{10:41,20:[1,37]},{18:[1,42]},{18:[2,43],24:[2,43],28:43,32:[2,43],33:[2,43],34:[2,43],35:[2,43],36:[2,43],40:[2,43],42:[2,43]},{18:[2,25],24:[2,25],36:[2,25]},{18:[2,38],24:[2,38],32:[2,38],33:[2,38],34:[2,38],35:[2,38],36:[2,38],40:[2,38],42:[2,38],44:[1,44]},{21:45,40:[1,28],43:26},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],42:[2,40],44:[2,40]},{18:[1,46]},{18:[1,47]},{24:[1,48]},{18:[2,41],21:50,27:49,40:[1,28],43:26},{18:[2,34],40:[2,34]},{18:[2,35],40:[2,35]},{18:[2,36],40:[2,36]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{21:51,40:[1,28],43:26},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,3],22:[1,13],23:[1,14],25:[1,15]},{4:52,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,5],22:[1,13],23:[1,14],25:[1,15]},{14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]},{18:[2,45],21:56,24:[2,45],29:53,30:60,31:54,32:[1,57],33:[1,58],34:[1,59],35:[1,61],36:[2,45],37:55,38:62,39:63,40:[1,64],42:[1,27],43:26},{40:[1,65]},{18:[2,37],24:[2,37],32:[2,37],33:[2,37],34:[2,37],35:[2,37],36:[2,37],40:[2,37],42:[2,37]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,66]},{18:[2,42]},{18:[1,67]},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],25:[1,15]},{18:[2,24],24:[2,24],36:[2,24]},{18:[2,44],24:[2,44],32:[2,44],33:[2,44],34:[2,44],35:[2,44],36:[2,44],40:[2,44],42:[2,44]},{18:[2,46],24:[2,46],36:[2,46]},{18:[2,26],24:[2,26],32:[2,26],33:[2,26],34:[2,26],35:[2,26],36:[2,26],40:[2,26],42:[2,26]},{18:[2,27],24:[2,27],32:[2,27],33:[2,27],34:[2,27],35:[2,27],36:[2,27],40:[2,27],42:[2,27]},{18:[2,28],24:[2,28],32:[2,28],33:[2,28],34:[2,28],35:[2,28],36:[2,28],40:[2,28],42:[2,28]},{18:[2,29],24:[2,29],32:[2,29],33:[2,29],34:[2,29],35:[2,29],36:[2,29],40:[2,29],42:[2,29]},{18:[2,30],24:[2,30],32:[2,30],33:[2,30],34:[2,30],35:[2,30],36:[2,30],40:[2,30],42:[2,30]},{17:68,21:24,30:25,40:[1,28],42:[1,27],43:26},{18:[2,32],24:[2,32],36:[2,32],39:69,40:[1,70]},{18:[2,47],24:[2,47],36:[2,47],40:[2,47]},{18:[2,40],24:[2,40],32:[2,40],33:[2,40],34:[2,40],35:[2,40],36:[2,40],40:[2,40],41:[1,71],42:[2,40],44:[2,40]},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],35:[2,39],36:[2,39],40:[2,39],42:[2,39],44:[2,39]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{36:[1,72]},{18:[2,48],24:[2,48],36:[2,48],40:[2,48]},{41:[1,71]},{21:56,30:60,31:73,32:[1,57],33:[1,58],34:[1,59],35:[1,61],40:[1,28],42:[1,27],43:26},{18:[2,31],24:[2,31],32:[2,31],33:[2,31],34:[2,31],35:[2,31],36:[2,31],40:[2,31],42:[2,31]},{18:[2,33],24:[2,33],36:[2,33],40:[2,33]}],defaultActions:{3:[2,2],16:[2,1],50:[2,42]},parseError:function(a){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},d=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;gb[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 14;break;case 1:return 14;case 2:return this.popState(),14;case 3:return e(0,4),this.popState(),15;case 4:return 35;case 5:return 36;case 6:return 25;case 7:return 16;case 8:return 20;case 9:return 19;case 10:return 19;case 11:return 23;case 12:return 22;case 13:this.popState(),this.begin("com");break;case 14:return e(3,5),this.popState(),15;case 15:return 22;case 16:return 41;case 17:return 40;case 18:return 40;case 19:return 44;case 20:break;case 21:return this.popState(),24;case 22:return this.popState(),18;case 23:return b.yytext=e(1,2).replace(/\\"/g,'"'),32;case 24:return b.yytext=e(1,2).replace(/\\'/g,"'"),32;case 25:return 42;case 26:return 34;case 27:return 34;case 28:return 33;case 29:return 40;case 30:return b.yytext=e(1,2),40;case 31:return"INVALID";case 32:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[3],inclusive:!1},INITIAL:{rules:[0,1,32],inclusive:!0}},a}();return c.lexer=d,b.prototype=c,c.Parser=b,new b}();return a=b}(),i=function(a,b){"use strict";function c(a){return a.constructor===f.ProgramNode?a:(e.yy=f,e.parse(a))}var d={},e=a,f=b;return d.parser=e,d.parse=c,d}(h,g),j=function(a){"use strict";function b(){}function c(a,b,c){if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new f("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0);var d=c.parse(a),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function d(a,b,c){function d(){var d=c.parse(a),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}if(null==a||"string"!=typeof a&&a.constructor!==c.AST.ProgramNode)throw new f("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);b=b||{},"data"in b||(b.data=!0);var e;return function(a,b){return e||(e=d()),e.call(this,a,b)}}var e={},f=a;return e.Compiler=b,b.prototype={compiler:b,disassemble:function(){for(var a,b,c,d=this.opcodes,e=[],f=0,g=d.length;g>f;f++)if(a=d[f],"DECLARE"===a.opcode)e.push("DECLARE "+a.name+"="+a.value);else{b=[];for(var h=0;hc;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||d.args.length!==e.args.length)return!1;for(var f=0;fc;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.opcodes=[],this.children=[],this.depths={list:[]},this.options=b;var c=this.options.knownHelpers;if(this.options.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0},c)for(var d in c)this.options.knownHelpers[d]=c[d];return this.accept(a)},accept:function(a){var b,c=a.strip||{};return c.left&&this.opcode("strip"),b=this[a.type](a),c.right&&this.opcode("strip"),b},program:function(a){for(var b=a.statements,c=0,d=b.length;d>c;c++)this.accept(b[c]);return this.isSimple=1===d,this.depths.list=this.depths.list.sort(function(a,b){return a-b}),this},compileProgram:function(a){var b,c=(new this.compiler).compile(a,this.options),d=this.guid++;this.usePartial=this.usePartial||c.usePartial,this.children[d]=c;for(var e=0,f=c.depths.list.length;f>e;e++)b=c.depths.list[e],2>b||this.addDepth(b-1);return d},block:function(a){var b=a.mustache,c=a.program,d=a.inverse;c&&(c=this.compileProgram(c)),d&&(d=this.compileProgram(d));var e=b.sexpr,f=this.classifySexpr(e);"helper"===f?this.helperSexpr(e,c,d):"simple"===f?(this.simpleSexpr(e),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("blockValue")):(this.ambiguousSexpr(e,c,d),this.opcode("pushProgram",c),this.opcode("pushProgram",d),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},hash:function(a){var b,c,d=a.pairs;this.opcode("pushHash");for(var e=0,f=d.length;f>e;e++)b=d[e],c=b[1],this.options.stringParams?(c.depth&&this.addDepth(c.depth),this.opcode("getContext",c.depth||0),this.opcode("pushStringParam",c.stringModeValue,c.type),"sexpr"===c.type&&this.sexpr(c)):this.accept(c),this.opcode("assignToHash",b[0]);this.opcode("popHash")},partial:function(a){var b=a.partialName;this.usePartial=!0,a.context?this.ID(a.context):this.opcode("push","depth0"),this.opcode("invokePartial",b.name),this.opcode("append")},content:function(a){this.opcode("appendContent",a.string)},mustache:function(a){this.sexpr(a.sexpr),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},ambiguousSexpr:function(a,b,c){var d=a.id,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.id;"DATA"===b.type?this.DATA(b):b.parts.length?this.ID(b):(this.addDepth(b.depth),this.opcode("getContext",b.depth),this.opcode("pushContext")),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.id.parts[0];if(this.options.knownHelpers[e])this.opcode("invokeKnownHelper",d.length,e);else{if(this.options.knownHelpersOnly)throw new f("You specified knownHelpersOnly, but used the unknown helper "+e,a);this.opcode("invokeHelper",d.length,e,a.isRoot)}},sexpr:function(a){var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ID:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0];b?this.opcode("lookupOnContext",a.parts[0]):this.opcode("pushContext");for(var c=1,d=a.parts.length;d>c;c++)this.opcode("lookup",a.parts[c])},DATA:function(a){if(this.options.data=!0,a.id.isScoped||a.id.depth)throw new f("Scoped data references are not supported: "+a.original,a);this.opcode("lookupData");for(var b=a.id.parts,c=0,d=b.length;d>c;c++)this.opcode("lookup",b[c])},STRING:function(a){this.opcode("pushString",a.string)},INTEGER:function(a){this.opcode("pushLiteral",a.integer)},BOOLEAN:function(a){this.opcode("pushLiteral",a.bool)},comment:function(){},opcode:function(a){this.opcodes.push({opcode:a,args:[].slice.call(arguments,1)})},declare:function(a,b){this.opcodes.push({opcode:"DECLARE",name:a,value:b})},addDepth:function(a){0!==a&&(this.depths[a]||(this.depths[a]=!0,this.depths.list.push(a)))},classifySexpr:function(a){var b=a.isHelper,c=a.eligibleHelper,d=this.options;if(c&&!b){var e=a.id.parts[0];d.knownHelpers[e]?b=!0:d.knownHelpersOnly&&(c=!1)}return b?"helper":c?"ambiguous":"simple"},pushParams:function(a){for(var b,c=a.length;c--;)b=a[c],this.options.stringParams?(b.depth&&this.addDepth(b.depth),this.opcode("getContext",b.depth||0),this.opcode("pushStringParam",b.stringModeValue,b.type),"sexpr"===b.type&&this.sexpr(b)):this[b.type](b)},setupFullMustacheParams:function(a,b,c){var d=a.params;return this.pushParams(d),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.hash(a.hash):this.opcode("emptyHash"),d}},e.precompile=c,e.compile=d,e}(c),k=function(a,b){"use strict";function c(a){this.value=a}function d(){}var e,f=a.COMPILER_REVISION,g=a.REVISION_CHANGES,h=a.log,i=b;d.prototype={nameLookup:function(a,b){var c,e;return 0===a.indexOf("depth")&&(c=!0),e=/^[0-9]+$/.test(b)?a+"["+b+"]":d.isValidJavaScriptVariableName(b)?a+"."+b:a+"['"+b+"']",c?"("+a+" && "+e+")":e},compilerInfo:function(){var a=f,b=g[a];return"this.compilerInfo = ["+a+",'"+b+"'];\n"},appendToBuffer:function(a){return this.environment.isSimple?"return "+a+";":{appendToBuffer:!0,content:a,toString:function(){return"buffer += "+a+";"}}},initializeBuffer:function(){return this.quotedString("")},namespace:"Handlebars",compile:function(a,b,c,d){this.environment=a,this.options=b||{},h("debug",this.environment.disassemble()+"\n\n"),this.name=this.environment.name,this.isChild=!!c,this.context=c||{programs:[],environments:[],aliases:{}},this.preamble(),this.stackSlot=0,this.stackVars=[],this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.compileChildren(a,b); +var e,f=a.opcodes;this.i=0;for(var g=f.length;this.ie;e++)d.push("depth"+this.environment.depths.list[e]);var g=this.mergeSource();if(this.isChild||(g=this.compilerInfo()+g),a)return d.push(g),Function.apply(this,d);var i="function "+(this.name||"")+"("+d.join(",")+") {\n "+g+"}";return h("debug",i+"\n\n"),i},mergeSource:function(){for(var a,b="",c=0,d=this.source.length;d>c;c++){var e=this.source[c];e.appendToBuffer?a=a?a+"\n + "+e.content:e.content:(a&&(b+="buffer += "+a+";\n ",a=void 0),b+=e+"\n ")}return b},blockValue:function(){this.context.aliases.blockHelperMissing="helpers.blockHelperMissing";var a=["depth0"];this.setupParams(0,a),this.replaceStack(function(b){return a.splice(1,0,b),"blockHelperMissing.call("+a.join(", ")+")"})},ambiguousBlockValue:function(){this.context.aliases.blockHelperMissing="helpers.blockHelperMissing";var a=["depth0"];this.setupParams(0,a);var b=this.topStack();a.splice(1,0,b),this.pushSource("if (!"+this.lastHelper+") { "+b+" = blockHelperMissing.call("+a.join(", ")+"); }")},appendContent:function(a){this.pendingContent&&(a=this.pendingContent+a),this.stripNext&&(a=a.replace(/^\s+/,"")),this.pendingContent=a},strip:function(){this.pendingContent&&(this.pendingContent=this.pendingContent.replace(/\s+$/,"")),this.stripNext="strip"},append:function(){this.flushInline();var a=this.popStack();this.pushSource("if("+a+" || "+a+" === 0) { "+this.appendToBuffer(a)+" }"),this.environment.isSimple&&this.pushSource("else { "+this.appendToBuffer("''")+" }")},appendEscaped:function(){this.context.aliases.escapeExpression="this.escapeExpression",this.pushSource(this.appendToBuffer("escapeExpression("+this.popStack()+")"))},getContext:function(a){this.lastContext!==a&&(this.lastContext=a)},lookupOnContext:function(a){this.push(this.nameLookup("depth"+this.lastContext,a,"context"))},pushContext:function(){this.pushStackLiteral("depth"+this.lastContext)},resolvePossibleLambda:function(){this.context.aliases.functionType='"function"',this.replaceStack(function(a){return"typeof "+a+" === functionType ? "+a+".apply(depth0) : "+a})},lookup:function(a){this.replaceStack(function(b){return b+" == null || "+b+" === false ? "+b+" : "+this.nameLookup(b,a,"context")})},lookupData:function(){this.pushStackLiteral("data")},pushStringParam:function(a,b){this.pushStackLiteral("depth"+this.lastContext),this.pushString(b),"sexpr"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(){this.pushStackLiteral("{}"),this.options.stringParams&&(this.push("{}"),this.push("{}"))},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.options.stringParams&&(this.push("{"+a.contexts.join(",")+"}"),this.push("{"+a.types.join(",")+"}")),this.push("{\n "+a.values.join(",\n ")+"\n }")},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},push:function(a){return this.inlineStack.push(a),a},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){null!=a?this.pushStackLiteral(this.programExpression(a)):this.pushStackLiteral(null)},invokeHelper:function(a,b,c){this.context.aliases.helperMissing="helpers.helperMissing",this.useRegister("helper");var d=this.lastHelper=this.setupHelper(a,b,!0),e=this.nameLookup("depth"+this.lastContext,b,"context"),f="helper = "+d.name+" || "+e;d.paramsInit&&(f+=","+d.paramsInit),this.push("("+f+",helper ? helper.call("+d.callParams+") : helperMissing.call("+d.helperMissingParams+"))"),c||this.flushInline()},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(c.name+".call("+c.callParams+")")},invokeAmbiguous:function(a,b){this.context.aliases.functionType='"function"',this.useRegister("helper"),this.emptyHash();var c=this.setupHelper(0,a,b),d=this.lastHelper=this.nameLookup("helpers",a,"helper"),e=this.nameLookup("depth"+this.lastContext,a,"context"),f=this.nextStack();c.paramsInit&&this.pushSource(c.paramsInit),this.pushSource("if (helper = "+d+") { "+f+" = helper.call("+c.callParams+"); }"),this.pushSource("else { helper = "+e+"; "+f+" = typeof helper === functionType ? helper.call("+c.callParams+") : helper; }")},invokePartial:function(a){var b=[this.nameLookup("partials",a,"partial"),"'"+a+"'",this.popStack(),"helpers","partials"];this.options.data&&b.push("data"),this.context.aliases.self="this",this.push("self.invokePartial("+b.join(", ")+")")},assignToHash:function(a){var b,c,d=this.popStack();this.options.stringParams&&(c=this.popStack(),b=this.popStack());var e=this.hash;b&&e.contexts.push("'"+a+"': "+b),c&&e.types.push("'"+a+"': "+c),e.values.push("'"+a+"': ("+d+")")},compiler:d,compileChildren:function(a,b){for(var c,d,e=a.children,f=0,g=e.length;g>f;f++){c=e[f],d=new this.compiler;var h=this.matchExistingProgram(c);null==h?(this.context.programs.push(""),h=this.context.programs.length,c.index=h,c.name="program"+h,this.context.programs[h]=d.compile(c,b,this.context),this.context.environments[h]=c):(c.index=h,c.name="program"+h)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){if(this.context.aliases.self="this",null==a)return"self.noop";for(var b,c=this.environment.children[a],d=c.depths.list,e=[c.index,c.name,"data"],f=0,g=d.length;g>f;f++)b=d[f],1===b?e.push("depth0"):e.push("depth"+(b-1));return(0===d.length?"self.program(":"self.programWithDepth(")+e.join(", ")+")"},register:function(a,b){this.useRegister(a),this.pushSource(a+" = "+b+";")},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},pushStackLiteral:function(a){return this.push(new c(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent))),this.pendingContent=void 0),a&&this.source.push(a)},pushStack:function(a){this.flushInline();var b=this.incrStack();return a&&this.pushSource(b+" = "+a+";"),this.compileStack.push(b),b},replaceStack:function(a){var b,d,e,f="",g=this.isInline();if(g){var h=this.popStack(!0);if(h instanceof c)b=h.value,e=!0;else{d=!this.stackSlot;var i=d?this.incrStack():this.topStackName();f="("+this.push(i)+" = "+h+"),",b=this.topStack()}}else b=this.topStack();var j=a.call(this,b);return g?(e||this.popStack(),d&&this.stackSlot--,this.push("("+f+j+")")):(/^stack/.test(b)||(b=this.nextStack()),this.pushSource(b+" = ("+f+j+");")),b},nextStack:function(){return this.pushStack()},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;if(a.length){this.inlineStack=[];for(var b=0,d=a.length;d>b;b++){var e=a[b];e instanceof c?this.compileStack.push(e):this.pushStack(e)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),d=(b?this.inlineStack:this.compileStack).pop();if(!a&&d instanceof c)return d.value;if(!b){if(!this.stackSlot)throw new i("Invalid stack pop");this.stackSlot--}return d},topStack:function(a){var b=this.isInline()?this.inlineStack:this.compileStack,d=b[b.length-1];return!a&&d instanceof c?d.value:d},quotedString:function(a){return'"'+a.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},setupHelper:function(a,b,c){var d=[],e=this.setupParams(a,d,c),f=this.nameLookup("helpers",b,"helper");return{params:d,paramsInit:e,name:f,callParams:["depth0"].concat(d).join(", "),helperMissingParams:c&&["depth0",this.quotedString(b)].concat(d).join(", ")}},setupOptions:function(a,b){var c,d,e,f=[],g=[],h=[];f.push("hash:"+this.popStack()),this.options.stringParams&&(f.push("hashTypes:"+this.popStack()),f.push("hashContexts:"+this.popStack())),d=this.popStack(),e=this.popStack(),(e||d)&&(e||(this.context.aliases.self="this",e="self.noop"),d||(this.context.aliases.self="this",d="self.noop"),f.push("inverse:"+d),f.push("fn:"+e));for(var i=0;a>i;i++)c=this.popStack(),b.push(c),this.options.stringParams&&(h.push(this.popStack()),g.push(this.popStack()));return this.options.stringParams&&(f.push("contexts:["+g.join(",")+"]"),f.push("types:["+h.join(",")+"]")),this.options.data&&f.push("data:data"),f},setupParams:function(a,b,c){var d="{"+this.setupOptions(a,b).join(",")+"}";return c?(this.useRegister("options"),b.push("options"),"options="+d):(b.push(d),"")}};for(var j="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield".split(" "),k=d.RESERVED_WORDS={},l=0,m=j.length;m>l;l++)k[j[l]]=!0;return d.isValidJavaScriptVariableName=function(a){return!d.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)?!0:!1},e=d}(d,c),l=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c.parser,j=c.parse,k=d.Compiler,l=d.compile,m=d.precompile,n=e,o=g.create,p=function(){var a=o();return a.compile=function(b,c){return l(b,c,a)},a.precompile=function(b,c){return m(b,c,a)},a.AST=h,a.Compiler=k,a.JavaScriptCompiler=n,a.Parser=i,a.parse=j,a};return g=p(),g.create=p,f=g}(f,g,i,j,k);return l}(); \ No newline at end of file diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js new file mode 100644 index 0000000000..b7eda97232 --- /dev/null +++ b/domain-server/resources/web/js/settings.js @@ -0,0 +1,8 @@ +$(document).ready(function(){ + $.getJSON('describe.json', function(data){ + var source = $('#template').html(); + var template = Handlebars.compile(source); + + $('#settings').html(template(data)); + }); +}); \ No newline at end of file diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json new file mode 100644 index 0000000000..d48b5b64ce --- /dev/null +++ b/domain-server/resources/web/settings/describe.json @@ -0,0 +1,10 @@ +{ + "groups": { + "Audio": { + "unattenuated-zone": { + "label": "Unattenuated Zone", + "desc": "Define two axis-aligned boxes for an unattenuated zone of audio (source x, source y, source z, size x, size y, size z, listener x, listener y, listener z)" + } + } + } +} \ No newline at end of file diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml new file mode 100644 index 0000000000..03382954b7 --- /dev/null +++ b/domain-server/resources/web/settings/index.shtml @@ -0,0 +1,13 @@ + + +
+ +
+ + + + \ No newline at end of file diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d55a9b52ca..78032f214d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1162,7 +1162,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } } - // didn't process the request, let the HTTPManager try and handle + // didn't process the request, let our HTTPManager handle return false; } diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp new file mode 100644 index 0000000000..b425b7a381 --- /dev/null +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -0,0 +1,12 @@ +// +// DomainServerSettingsManager.cpp +// domain-server/src +// +// Created by Stephen Birarda on 2014-06-24. +// 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 "DomainServerSettingsManager.h" \ No newline at end of file diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h new file mode 100644 index 0000000000..8d4afae4b9 --- /dev/null +++ b/domain-server/src/DomainServerSettingsManager.h @@ -0,0 +1,21 @@ +// +// DomainServerSettingsManager.h +// domain-server/src +// +// Created by Stephen Birarda on 2014-06-24. +// 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_DomainServerSettingsManager_h +#define hifi_DomainServerSettingsManager_h + +#include + +class DomainServerSettingsManager { + +}; + +#endif // hifi_DomainServerSettingsManager_h \ No newline at end of file From 7271f850413d56be65bbac7478181c82c3241a00 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Wed, 25 Jun 2014 01:49:17 +0530 Subject: [PATCH 24/88] Change font size values from pt to px in Chat Window. --- interface/src/ui/ChatWindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index fde77334f4..d42c40ac76 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -178,7 +178,7 @@ void ChatWindow::addTimeStamp() { QLabel* timeLabel = new QLabel(timeString); timeLabel->setStyleSheet("color: #333333;" "background-color: white;" - "font-size: 14pt;" + "font-size: 14px;" "padding: 4px;"); timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); timeLabel->setAlignment(Qt::AlignLeft); @@ -284,7 +284,7 @@ void ChatWindow::participantsChanged() { "padding-bottom: 2px;" "padding-left: 2px;" "border: 1px solid palette(shadow);" - "font-size: 14pt;" + "font-size: 14px;" "font-weight: bold"); userLabel->setProperty("user", participantName); userLabel->setCursor(Qt::PointingHandCursor); @@ -320,7 +320,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { "padding-right: 20px;" "margin: 0px;" "color: #333333;" - "font-size: 14pt;" + "font-size: 14px;" "background-color: rgba(0, 0, 0, 0%);" "border: 0; }" "QMenu{ border: 2px outset gray; }"); From cf0e1ab1a93bc26f9fe8e51d5481a86c5a86be20 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 24 Jun 2014 14:24:56 -0700 Subject: [PATCH 25/88] finish up handlebars template for settings --- domain-server/resources/web/css/style.css | 4 +-- domain-server/resources/web/js/settings.js | 5 ++++ .../resources/web/settings/describe.json | 12 ++++++--- .../resources/web/settings/index.shtml | 26 ++++++++++++++++--- 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index ff33cc206b..3b60ada78b 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -1,8 +1,8 @@ -#nodes-lead { +#nodes-lead, #settings-lead { color: #66CCCC; } -#nodes-lead .lead-line { +#nodes-lead .lead-line, #settings-lead .lead-line { background-color: #66CCCC; } diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index b7eda97232..d7d8315559 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -1,5 +1,10 @@ $(document).ready(function(){ $.getJSON('describe.json', function(data){ + + Handlebars.registerHelper('setKey', function(value){ + this.key = value; + }); + var source = $('#template').html(); var template = Handlebars.compile(source); diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index d48b5b64ce..763aeccdfc 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -1,9 +1,13 @@ { "groups": { - "Audio": { - "unattenuated-zone": { - "label": "Unattenuated Zone", - "desc": "Define two axis-aligned boxes for an unattenuated zone of audio (source x, source y, source z, size x, size y, size z, listener x, listener y, listener z)" + "audio": { + "label": "Audio", + "settings": { + "unattenuated-zone": { + "label": "Unattenuated Zone", + "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", + "placeholder": "0,0,0,20,20,20,50,50,50,10,10,10" + } } } } diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 03382954b7..8d186848b6 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -1,12 +1,30 @@ +

Settings

+
-
- -
+ +
From 11f23ca6f616f9faef084d92addf0ee134b63e3d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 24 Jun 2014 15:56:53 -0700 Subject: [PATCH 26/88] add POSTing of settings to DS via form2js --- domain-server/resources/web/js/form2js.min.js | 26 ++++++++++ domain-server/resources/web/js/settings.js | 51 +++++++++++++++---- .../resources/web/settings/index.shtml | 12 +++-- 3 files changed, 74 insertions(+), 15 deletions(-) create mode 100755 domain-server/resources/web/js/form2js.min.js diff --git a/domain-server/resources/web/js/form2js.min.js b/domain-server/resources/web/js/form2js.min.js new file mode 100755 index 0000000000..f1e610f7c3 --- /dev/null +++ b/domain-server/resources/web/js/form2js.min.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010 Maxim Vasiliev + * + * 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. + * + * 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. + * + * @author Maxim Vasiliev + * Date: 09.09.2010 + * Time: 19:02:33 + */ +(function(e,t){if(typeof define==="function"&&define.amd){define(t)}else{e.form2js=t()}})(this,function(){"use strict";function e(e,r,i,s,o,u){u=u?true:false;if(typeof i=="undefined"||i==null)i=true;if(typeof r=="undefined"||r==null)r=".";if(arguments.length<5)o=false;e=typeof e=="string"?document.getElementById(e):e;var a=[],f,l=0;if(e.constructor==Array||typeof NodeList!="undefined"&&e.constructor==NodeList){while(f=e[l++]){a=a.concat(n(f,s,o,u))}}else{a=n(e,s,o,u)}return t(a,i,r)}function t(e,t,n){var r={},i={},s,o,u,a,f,l,c,h,p,d,v,m,g;for(s=0;s1){for(u=0;u-1&&o==l.length-1){p=v.substr(0,v.indexOf("["));h+=p;if(!c[p])c[p]=[];c[p].push(f)}else if(v.indexOf("[")>-1){p=v.substr(0,v.indexOf("["));d=v.replace(/(^([a-z_]+)?\[)|(\]$)/gi,"");h+="_"+p+"_"+d;if(!i[h])i[h]={};if(p!=""&&!c[p])c[p]=[];if(o==l.length-1){if(p==""){c.push(f);i[h][d]=c[c.length-1]}else{c[p].push(f);i[h][d]=c[p][c[p].length-1]}}else{if(!i[h][d]){if(/^[0-9a-z_]+\[?/i.test(l[o+1]))c[p].push({});else c[p].push([]);i[h][d]=c[p][c[p].length-1]}}c=i[h][d]}else{h+=v;if(o0?o:r(e,t,n,s)}function r(e,t,n,r){var s=[],o=e.firstChild;while(o){s=s.concat(i(o,t,n,r));o=o.nextSibling}return s}function i(e,t,n,i){if(e.disabled&&!i)return[];var u,a,f,l=s(e,n);u=t&&t(e);if(u&&u.name){f=[u]}else if(l!=""&&e.nodeName.match(/INPUT|TEXTAREA/i)){a=o(e,i);if(null===a){f=[]}else{f=[{name:l,value:a}]}}else if(l!=""&&e.nodeName.match(/SELECT/i)){a=o(e,i);f=[{name:l.replace(/\[\]$/,""),value:a}]}else{f=r(e,t,n,i)}return f}function s(e,t){if(e.name&&e.name!="")return e.name;else if(t&&e.id&&e.id!="")return e.id;else return""}function o(e,t){if(e.disabled&&!t)return null;switch(e.nodeName){case"INPUT":case"TEXTAREA":switch(e.type.toLowerCase()){case"radio":if(e.checked&&e.value==="false")return false;case"checkbox":if(e.checked&&e.value==="true")return true;if(!e.checked&&e.value==="true")return false;if(e.checked)return e.value;break;case"button":case"reset":case"submit":case"image":return"";break;default:return e.value;break}break;case"SELECT":return u(e);break;default:break}return null}function u(e){var t=e.multiple,n=[],r,i,s;if(!t)return e.value;for(r=e.getElementsByTagName("option"),i=0,s=r.length;i

Settings

+ +
+
+
+ + \ No newline at end of file From 5bb2c3c62fdc96ff1104fff0ed00206b7716f900 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Jun 2014 16:14:40 -0700 Subject: [PATCH 27/88] Added in-world test tone JS file --- examples/inWorldTestTone.js | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 examples/inWorldTestTone.js diff --git a/examples/inWorldTestTone.js b/examples/inWorldTestTone.js new file mode 100644 index 0000000000..e4f34d87cd --- /dev/null +++ b/examples/inWorldTestTone.js @@ -0,0 +1,38 @@ +// +// inWorldTestTone.js +// +// +// Created by Philip Rosedale on 5/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// This example script plays a test tone that is useful for debugging audio dropout. 220Hz test tone played at the domain origin. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var sound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/220Sine.wav"); + +var soundPlaying = false; + +function update(deltaTime) { + if (!Audio.isInjectorPlaying(soundPlaying)) { + var options = new AudioInjectionOptions(); + options.position = { x:0, y:0, z:0 }; + options.volume = 1.0; + options.loop = true; + soundPlaying = Audio.playSound(sound, options); + print("Started sound loop"); + } +} + +function scriptEnding() { + if (Audio.isInjectorPlaying(soundPlaying)) { + Audio.stopInjector(soundPlaying); + print("Stopped sound loop"); + } +} + +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + From 9eb91e2b4498ad0d07e37cf387258df82e4398a0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Jun 2014 16:15:16 -0700 Subject: [PATCH 28/88] tweaking params --- interface/src/avatar/Avatar.cpp | 31 ++++++++++++++++++++++++++++--- interface/src/avatar/Avatar.h | 2 +- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 95399062ae..14e01536e2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -383,10 +383,10 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { renderHair(); } -const float HAIR_LENGTH = 0.5f; +const float HAIR_LENGTH = 0.4f; const float HAIR_LINK_LENGTH = HAIR_LENGTH / HAIR_LINKS; const float HAIR_DAMPING = 0.99f; -const float HEAD_RADIUS = 0.20f; +const float HEAD_RADIUS = 0.25f; const float COLLISION_RELAXATION = 10.f; const float CONSTRAINT_RELAXATION = 10.0f; const float NOISE = 0.0f; // 0.1f; @@ -395,9 +395,10 @@ const glm::vec3 HAIR_GRAVITY(0.f, -0.05f, 0.f); const float HAIR_ACCELERATION_COUPLING = 0.025f; const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.15f; const float HAIR_MAX_LINEAR_ACCELERATION = 5.f; -const float HAIR_THICKNESS = 0.015f; +const float HAIR_THICKNESS = 0.025f; const glm::vec3 HAIR_COLOR1(0.98f, 0.92f, 0.843f); const glm::vec3 HAIR_COLOR2(0.545f, 0.533f, 0.47f); +const glm::vec3 WIND_DIRECTION(1.0f, -1.0f, 0.f); void Avatar::renderHair() { // @@ -450,6 +451,8 @@ void Avatar::simulateHair(float deltaTime) { acceleration = acceleration * rotation; glm::vec3 angularVelocity = getAngularVelocity() + getHead()->getAngularVelocity(); + float windIntensity = randFloat() * 0.02f; + for (int strand = 0; strand < HAIR_STRANDS; strand++) { for (int link = 0; link < HAIR_LINKS; link++) { int vertexIndex = strand * HAIR_LINKS + link; @@ -478,6 +481,10 @@ void Avatar::simulateHair(float deltaTime) { // Add linear acceleration of the avatar body _hairPosition[vertexIndex] -= acceleration * HAIR_ACCELERATION_COUPLING * deltaTime; + // Add some wind + glm::vec3 wind = WIND_DIRECTION * windIntensity; + _hairPosition[vertexIndex] += wind * deltaTime; + const float ANGULAR_VELOCITY_MIN = 0.001f; // Add angular acceleration of the avatar body if (glm::length(angularVelocity) > ANGULAR_VELOCITY_MIN) { @@ -490,6 +497,24 @@ void Avatar::simulateHair(float deltaTime) { glm::vec3 delta = glm::vec3(-1.f, 0.f, 0.f) * glm::angleAxis(angle, glm::vec3(0, 1, 0)); _hairPosition[vertexIndex] -= delta * radius * angularVelocity.y * HAIR_ANGULAR_VELOCITY_COUPLING * deltaTime; } + glm::vec3 pitchVector = _hairPosition[vertexIndex]; + pitchVector.x = 0.f; + if (glm::length(pitchVector) > EPSILON) { + float radius = glm::length(pitchVector); + pitchVector = glm::normalize(pitchVector); + float angle = atan2f(pitchVector.y, -pitchVector.z) + PI; + glm::vec3 delta = glm::vec3(0.0f, 1.0f, 0.f) * glm::angleAxis(angle, glm::vec3(1, 0, 0)); + _hairPosition[vertexIndex] -= delta * radius * angularVelocity.x * HAIR_ANGULAR_VELOCITY_COUPLING * deltaTime; + } + glm::vec3 rollVector = _hairPosition[vertexIndex]; + rollVector.z = 0.f; + if (glm::length(rollVector) > EPSILON) { + float radius = glm::length(rollVector); + pitchVector = glm::normalize(rollVector); + float angle = atan2f(rollVector.x, rollVector.y) + PI; + glm::vec3 delta = glm::vec3(-1.0f, 0.0f, 0.f) * glm::angleAxis(angle, glm::vec3(0, 0, 1)); + _hairPosition[vertexIndex] -= delta * radius * angularVelocity.z * HAIR_ANGULAR_VELOCITY_COUPLING * deltaTime; + } } // Iterate length constraints to other links diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cf45cdf07f..bd4416f70d 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -32,7 +32,7 @@ static const float RESCALING_TOLERANCE = .02f; extern const float CHAT_MESSAGE_SCALE; extern const float CHAT_MESSAGE_HEIGHT; -const int HAIR_STRANDS = 100; // Number of strands of hair +const int HAIR_STRANDS = 200; // Number of strands of hair const int HAIR_LINKS = 10; // Number of links in a hair strand const int HAIR_MAX_CONSTRAINTS = 2; From 773e1b052279dec71344254b0ce7e91dcf945789 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 18:02:35 -0700 Subject: [PATCH 29/88] try to get tests to build --- tests/octree/CMakeLists.txt | 8 ++++---- tests/octree/src/ModelTests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index 1697064ff4..33c3bcd4a3 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -30,12 +30,12 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) # link in the shared libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(models ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) IF (WIN32) diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index 63653dac69..48be5e22c3 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -14,7 +14,7 @@ #include -#if 0 +#if 1 #include #include #include @@ -27,7 +27,7 @@ #include "ModelTests.h" void ModelTests::modelTreeTests(bool verbose) { -#if 0 +#if 1 int testsTaken = 0; int testsPassed = 0; int testsFailed = 0; From 40a842d25180c0664c8fec8d6c3ea865e7748e48 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 18:15:00 -0700 Subject: [PATCH 30/88] windows build issue --- libraries/models/src/ModelItem.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 9a558f2ef4..2440596278 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -12,9 +12,11 @@ #ifndef hifi_ModelItem_h #define hifi_ModelItem_h -#include +#include #include +#include + #include #include From 9a6f144da902110ca3d1f4dcc1efcab4654645f8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 24 Jun 2014 18:21:57 -0700 Subject: [PATCH 31/88] Added sitting points metadata for fst --- libraries/fbx/src/FBXReader.cpp | 15 ++++++++++++++- libraries/fbx/src/FBXReader.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 9aeb81a2a3..36773ec8bd 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1897,7 +1897,20 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } geometry.attachments.append(attachment); } - + + // Add sitting points + QVariantHash sittingPoints = mapping.value("sit").toHash(); + for (QVariantHash::const_iterator it = sittingPoints.constBegin(); it != sittingPoints.constEnd(); it++) { + SittingPoint sittingPoint; + sittingPoint.name = it.key(); + + QVariantList properties = it->toList(); + sittingPoint.position = parseVec3(properties.at(0).toString()); + sittingPoint.rotation = glm::quat(glm::radians(parseVec3(properties.at(1).toString()))); + + geometry.sittingPoints.append(sittingPoint); + } + return geometry; } diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 4c93f3dc5e..c336252574 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -182,6 +182,14 @@ public: glm::vec3 scale; }; +/// A point where an avatar can sit +class SittingPoint { +public: + QString name; + glm::vec3 position; // relative postion + glm::quat rotation; // relative orientation +}; + /// A set of meshes extracted from an FBX document. class FBXGeometry { public: @@ -209,6 +217,8 @@ public: glm::vec3 palmDirection; + QVector sittingPoints; + glm::vec3 neckPivot; Extents bindExtents; From fdb0cf9386a4ce69e03617f5e688e5158603d7d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 18:53:20 -0700 Subject: [PATCH 32/88] change order of headers --- tests/octree/src/ModelTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index 48be5e22c3..e12865f807 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -15,10 +15,10 @@ #include #if 1 +#include #include #include #include -#include #include #include #include From 3ad07f4b911fc74dfe8957e81d17b6aa8a8093ac Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:08:16 -0700 Subject: [PATCH 33/88] argggg --- libraries/models/src/ModelItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 2440596278..44f4285051 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -13,6 +13,7 @@ #define hifi_ModelItem_h #include +#include // for ssize_t #include #include From 65e50f32e489249dc5f54146f973da3e9107f072 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Jun 2014 19:10:52 -0700 Subject: [PATCH 34/88] Tests, fixes for SpanList. --- .../metavoxels/src/DatagramSequencer.cpp | 143 ++++++++------- libraries/metavoxels/src/DatagramSequencer.h | 5 +- tests/metavoxels/src/MetavoxelTests.cpp | 172 ++++++++++++++++-- tests/metavoxels/src/MetavoxelTests.h | 11 +- 4 files changed, 253 insertions(+), 78 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index f1f60e4d87..babbff6f2b 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -520,7 +520,9 @@ int SpanList::set(int offset, int length) { // look for an intersection within the list int position = 0; - for (QList::iterator it = _spans.begin(); it != _spans.end(); it++) { + for (int i = 0; i < _spans.size(); i++) { + QList::iterator it = _spans.begin() + i; + // if we intersect the unset portion, contract it position += it->unset; if (offset <= position) { @@ -530,16 +532,20 @@ int SpanList::set(int offset, int length) { // if we continue into the set portion, expand it and consume following spans int extra = offset + length - position; if (extra >= 0) { - int amount = setSpans(it + 1, extra); - it->set += amount; - _totalSet += amount; - + extra -= it->set; + it->set += remove; + _totalSet += remove; + if (extra > 0) { + int amount = setSpans(it + 1, extra); + _spans[i].set += amount; + _totalSet += amount; + } // otherwise, insert a new span } else { - Span span = { it->unset, length + extra }; - _spans.insert(it, span); + Span span = { it->unset, length }; it->unset = -extra; - _totalSet += span.set; + _spans.insert(it, span); + _totalSet += length; } return 0; } @@ -548,9 +554,11 @@ int SpanList::set(int offset, int length) { position += it->set; if (offset <= position) { int extra = offset + length - position; - int amount = setSpans(it + 1, extra); - it->set += amount; - _totalSet += amount; + if (extra > 0) { + int amount = setSpans(it + 1, extra); + _spans[i].set += amount; + _totalSet += amount; + } return 0; } } @@ -629,67 +637,71 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o } void ReliableChannel::writeData(QDataStream& out, int bytes, QVector& spans) { - // find out how many spans we want to write - int spanCount = 0; - int remainingBytes = bytes; - bool first = true; - while (remainingBytes > 0) { + if (bytes > 0) { + _writePosition %= _buffer.pos(); + int position = 0; - foreach (const SpanList::Span& span, _acknowledged.getSpans()) { - if (remainingBytes <= 0) { - break; + for (int i = 0; i < _acknowledged.getSpans().size(); i++) { + const SpanList::Span& span = _acknowledged.getSpans().at(i); + position += span.unset; + if (_writePosition < position) { + int start = qMax(position - span.unset, _writePosition); + int length = qMin(bytes, position - start); + writeSpan(out, start, length, spans); + writeFullSpans(out, bytes - length, i + 1, position + span.set, spans); + out << (quint32)0; + return; } - spanCount++; - remainingBytes -= getBytesToWrite(first, qMin(remainingBytes, span.unset)); - position += (span.unset + span.set); + position += span.set; } int leftover = _buffer.pos() - position; - if (remainingBytes > 0 && leftover > 0) { - spanCount++; - remainingBytes -= getBytesToWrite(first, qMin(remainingBytes, leftover)); + position = _buffer.pos(); + + if (_writePosition < position && leftover > 0) { + int start = qMax(position - leftover, _writePosition); + int length = qMin(bytes, position - start); + writeSpan(out, start, length, spans); + writeFullSpans(out, bytes - length, 0, 0, spans); } } - - // write the count and the spans - out << (quint32)spanCount; - remainingBytes = bytes; - first = true; - while (remainingBytes > 0) { - int position = 0; - foreach (const SpanList::Span& span, _acknowledged.getSpans()) { - if (remainingBytes <= 0) { - break; - } - remainingBytes -= writeSpan(out, first, position, qMin(remainingBytes, span.unset), spans); - position += (span.unset + span.set); + out << (quint32)0; +} + +void ReliableChannel::writeFullSpans(QDataStream& out, int bytes, int startingIndex, int position, + QVector& spans) { + int expandedSize = _acknowledged.getSpans().size() + 1; + for (int i = 0; i < expandedSize; i++) { + if (bytes == 0) { + return; } - int leftover = _buffer.pos() - position; - if (remainingBytes > 0 && leftover > 0) { - remainingBytes -= writeSpan(out, first, position, qMin(remainingBytes, leftover), spans); + int index = (startingIndex + i) % expandedSize; + if (index == _acknowledged.getSpans().size()) { + int leftover = _buffer.pos() - position; + if (leftover > 0) { + int length = qMin(leftover, bytes); + writeSpan(out, position, length, spans); + bytes -= length; + } + position = 0; + + } else { + const SpanList::Span& span = _acknowledged.getSpans().at(index); + int length = qMin(span.unset, bytes); + writeSpan(out, position, length, spans); + bytes -= length; + position += (span.unset + span.set); } } } -int ReliableChannel::getBytesToWrite(bool& first, int length) const { - if (first) { - first = false; - return length - (_writePosition % length); - } - return length; -} - -int ReliableChannel::writeSpan(QDataStream& out, bool& first, int position, int length, QVector& spans) { - if (first) { - first = false; - position = _writePosition % length; - length -= position; - _writePosition += length; - } +int ReliableChannel::writeSpan(QDataStream& out, int position, int length, QVector& spans) { DatagramSequencer::ChannelSpan span = { _index, _offset + position, length }; spans.append(span); - out << (quint32)span.offset; out << (quint32)length; + out << (quint32)span.offset; _buffer.writeToStream(position, length, out); + _writePosition = position + length; + return length; } @@ -700,17 +712,20 @@ void ReliableChannel::spanAcknowledged(const DatagramSequencer::ChannelSpan& spa _buffer.seek(_buffer.size()); _offset += advancement; - _writePosition = qMax(_writePosition - advancement, 0); - } + _writePosition = qMax(_writePosition - advancement, 0); + } } void ReliableChannel::readData(QDataStream& in) { - quint32 segments; - in >> segments; bool readSome = false; - for (quint32 i = 0; i < segments; i++) { - quint32 offset, size; - in >> offset >> size; + forever { + quint32 size; + in >> size; + if (size == 0) { + break; + } + quint32 offset; + in >> offset; int position = offset - _offset; int end = position + size; diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 5ac88556f0..47fef8e645 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -343,8 +343,9 @@ private: ReliableChannel(DatagramSequencer* sequencer, int index, bool output); void writeData(QDataStream& out, int bytes, QVector& spans); - int getBytesToWrite(bool& first, int length) const; - int writeSpan(QDataStream& out, bool& first, int position, int length, QVector& spans); + void writeFullSpans(QDataStream& out, int bytes, int startingIndex, int position, + QVector& spans); + int writeSpan(QDataStream& out, int position, int length, QVector& spans); void spanAcknowledged(const DatagramSequencer::ChannelSpan& span); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 609d36c085..688749f39b 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -28,6 +28,119 @@ MetavoxelTests::MetavoxelTests(int& argc, char** argv) : QCoreApplication(argc, argv) { } +static bool testSpanList() { + SpanList list; + + if (list.getTotalSet() != 0 || !list.getSpans().isEmpty()) { + qDebug() << "Failed empty state test."; + return true; + } + + if (list.set(-5, 15) != 10 || list.getTotalSet() != 0 || !list.getSpans().isEmpty()) { + qDebug() << "Failed initial front set."; + return true; + } + + if (list.set(5, 15) != 0 || list.getTotalSet() != 15 || list.getSpans().size() != 1 || + list.getSpans().at(0).unset != 5 || list.getSpans().at(0).set != 15) { + qDebug() << "Failed initial middle set."; + return true; + } + + if (list.set(25, 5) != 0 || list.getTotalSet() != 20 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 5 || list.getSpans().at(0).set != 15 || + list.getSpans().at(1).unset != 5 || list.getSpans().at(1).set != 5) { + qDebug() << "Failed initial end set."; + return true; + } + + if (list.set(1, 3) != 0 || list.getTotalSet() != 23 || list.getSpans().size() != 3 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 15 || + list.getSpans().at(2).unset != 5 || list.getSpans().at(2).set != 5) { + qDebug() << "Failed second front set."; + return true; + } + SpanList threeSet = list; + + if (list.set(20, 5) != 0 || list.getTotalSet() != 28 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 25) { + qDebug() << "Failed minimal join last two."; + return true; + } + + list = threeSet; + if (list.set(5, 25) != 0 || list.getTotalSet() != 28 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 25) { + qDebug() << "Failed maximal join last two."; + return true; + } + + list = threeSet; + if (list.set(10, 18) != 0 || list.getTotalSet() != 28 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 25) { + qDebug() << "Failed middle join last two."; + return true; + } + + list = threeSet; + if (list.set(10, 18) != 0 || list.getTotalSet() != 28 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 25) { + qDebug() << "Failed middle join last two."; + return true; + } + + list = threeSet; + if (list.set(2, 26) != 0 || list.getTotalSet() != 29 || list.getSpans().size() != 1 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 29) { + qDebug() << "Failed middle join three."; + return true; + } + + list = threeSet; + if (list.set(0, 2) != 4 || list.getTotalSet() != 20 || list.getSpans().size() != 2 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 15 || + list.getSpans().at(1).unset != 5 || list.getSpans().at(1).set != 5) { + qDebug() << "Failed front advance."; + return true; + } + + list = threeSet; + if (list.set(-10, 15) != 20 || list.getTotalSet() != 5 || list.getSpans().size() != 1 || + list.getSpans().at(0).unset != 5 || list.getSpans().at(0).set != 5) { + qDebug() << "Failed middle advance."; + return true; + } + + list = threeSet; + if (list.set(-10, 38) != 30 || list.getTotalSet() != 0 || list.getSpans().size() != 0) { + qDebug() << "Failed end advance."; + return true; + } + + list = threeSet; + if (list.set(-10, 100) != 90 || list.getTotalSet() != 0 || list.getSpans().size() != 0) { + qDebug() << "Failed clobber advance."; + return true; + } + + list = threeSet; + if (list.set(21, 3) != 0 || list.getTotalSet() != 26 || list.getSpans().size() != 4 || + list.getSpans().at(0).unset != 1 || list.getSpans().at(0).set != 3 || + list.getSpans().at(1).unset != 1 || list.getSpans().at(1).set != 15 || + list.getSpans().at(2).unset != 1 || list.getSpans().at(2).set != 3 || + list.getSpans().at(3).unset != 1 || list.getSpans().at(3).set != 5) { + qDebug() << "Failed adding fourth."; + return true; + } + + return false; +} + static int datagramsSent = 0; static int datagramsReceived = 0; static int bytesSent = 0; @@ -332,9 +445,18 @@ bool MetavoxelTests::run() { QStringList arguments = this->arguments(); int test = (arguments.size() > 1) ? arguments.at(1).toInt() : 0; + if (test == 0 || test == 1) { + qDebug() << "Running SpanList test..."; + qDebug(); + + if (testSpanList()) { + return true; + } + } + QByteArray datagramHeader("testheader"); const int SIMULATION_ITERATIONS = 10000; - if (test == 0 || test == 1) { + if (test == 0 || test == 2) { qDebug() << "Running transmission test..."; qDebug(); @@ -364,7 +486,7 @@ bool MetavoxelTests::run() { qDebug(); } - if (test == 0 || test == 2) { + if (test == 0 || test == 3) { qDebug() << "Running congestion control test..."; qDebug(); @@ -394,7 +516,7 @@ bool MetavoxelTests::run() { qDebug() << "Efficiency:" << ((float)streamedBytesReceived / bytesReceived); } - if (test == 0 || test == 3) { + if (test == 0 || test == 4) { qDebug() << "Running serialization test..."; qDebug(); @@ -403,7 +525,7 @@ bool MetavoxelTests::run() { } } - if (test == 0 || test == 4) { + if (test == 0 || test == 5) { qDebug() << "Running metavoxel data test..."; qDebug(); @@ -532,6 +654,13 @@ Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) : if (mode == CONGESTION_MODE) { const int HUGE_STREAM_BYTES = 50 * 1024 * 1024; bytes = createRandomBytes(HUGE_STREAM_BYTES, HUGE_STREAM_BYTES); + + // initialize the pipeline + for (int i = 0; i < 10; i++) { + _pipeline.append(ByteArrayVector()); + } + _remainingPipelineCapacity = 100 * 1024; + } else { const int MIN_STREAM_BYTES = 100000; const int MAX_STREAM_BYTES = 200000; @@ -669,10 +798,9 @@ int MutateVisitor::visit(MetavoxelInfo& info) { bool Endpoint::simulate(int iterationNumber) { // update/send our delayed datagrams - for (QList >::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) { + for (QList::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) { if (it->second-- == 1) { - _other->_sequencer->receivedDatagram(it->first); - datagramsReceived++; + _other->receiveDatagram(it->first); it = _delayedDatagrams.erase(it); } else { @@ -683,6 +811,16 @@ bool Endpoint::simulate(int iterationNumber) { int oldDatagramsSent = datagramsSent; int oldBytesSent = bytesSent; if (_mode == CONGESTION_MODE) { + // cycle our pipeline + ByteArrayVector datagrams = _pipeline.takeLast(); + _pipeline.prepend(ByteArrayVector()); + foreach (const QByteArray& datagram, datagrams) { + _sequencer->receivedDatagram(datagram); + datagramsReceived++; + bytesReceived += datagram.size(); + _remainingPipelineCapacity += datagram.size(); + } + Bitstream& out = _sequencer->startPacket(); out << QVariant(); _sequencer->endPacket(); @@ -804,7 +942,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { const int MIN_DELAY = 1; const int MAX_DELAY = 5; // have to copy the datagram; the one we're passed is a reference to a shared buffer - _delayedDatagrams.append(QPair(QByteArray(datagram.constData(), datagram.size()), + _delayedDatagrams.append(ByteArrayIntPair(QByteArray(datagram.constData(), datagram.size()), randIntInRange(MIN_DELAY, MAX_DELAY))); // and some are duplicated @@ -814,9 +952,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { } } - _other->_sequencer->receivedDatagram(datagram); - datagramsReceived++; - bytesReceived += datagram.size(); + _other->receiveDatagram(datagram); } void Endpoint::handleHighPriorityMessage(const QVariant& message) { @@ -942,6 +1078,20 @@ void Endpoint::clearReceiveRecordsBefore(int index) { _receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1); } +void Endpoint::receiveDatagram(const QByteArray& datagram) { + if (_mode == CONGESTION_MODE) { + if (datagram.size() <= _remainingPipelineCapacity) { + // have to copy the datagram; the one we're passed is a reference to a shared buffer + _pipeline[0].append(QByteArray(datagram.constData(), datagram.size())); + _remainingPipelineCapacity -= datagram.size(); + } + } else { + _sequencer->receivedDatagram(datagram); + datagramsReceived++; + bytesReceived += datagram.size(); + } +} + void Endpoint::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == ClientStateMessage::Type) { diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 46bac319fa..f9a314dcd7 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -63,6 +63,8 @@ private slots: private: + void receiveDatagram(const QByteArray& datagram); + void handleMessage(const QVariant& message, Bitstream& in); class SendRecord { @@ -96,7 +98,14 @@ private: SharedObjectPointer _sphere; Endpoint* _other; - QList > _delayedDatagrams; + + typedef QPair ByteArrayIntPair; + QList _delayedDatagrams; + + typedef QVector ByteArrayVector; + QList _pipeline; + int _remainingPipelineCapacity; + float _highPriorityMessagesToSend; QVariantList _highPriorityMessagesSent; QList _unreliableMessagesSent; From 7d759fc00cc1ca0b8f9756d267ac94f8cec4086f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:11:32 -0700 Subject: [PATCH 35/88] argggg --- libraries/models/src/ModelItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 44f4285051..617eae9ef5 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -25,6 +25,7 @@ #include #include #include +#include class ModelItem; class ModelEditPacketSender; From e5349024e6097dd1bac574e6322338e2e4fe053a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:15:48 -0700 Subject: [PATCH 36/88] argggg ssize_t --- libraries/models/src/ModelItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 617eae9ef5..eba8ca7ddf 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -12,6 +12,7 @@ #ifndef hifi_ModelItem_h #define hifi_ModelItem_h +#include // ??? #include #include // for ssize_t #include From 71afc3f4d4721c668edd2eb06772ec48b97d8658 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:26:24 -0700 Subject: [PATCH 37/88] argggg ssize_t --- libraries/models/src/ModelItem.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index eba8ca7ddf..218a9685b8 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -28,6 +28,13 @@ #include #include + +//#include +//#include +#include +#include +#include "ModelEditPacketSender.h" + class ModelItem; class ModelEditPacketSender; class ModelItemProperties; From 5486cd401911bf7347fa2b4d916efee95d8789af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:29:26 -0700 Subject: [PATCH 38/88] argggg ssize_t --- libraries/models/src/ModelItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 218a9685b8..5c2db93112 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -33,7 +33,7 @@ //#include #include #include -#include "ModelEditPacketSender.h" +//#include "ModelEditPacketSender.h" class ModelItem; class ModelEditPacketSender; From d913ac4486b50a9bd20f36b10f0d01427a1631e0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 24 Jun 2014 19:34:19 -0700 Subject: [PATCH 39/88] Fix for streams' getting stuck on the final part. --- libraries/metavoxels/src/DatagramSequencer.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index babbff6f2b..35d0876391 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -637,9 +637,12 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o } void ReliableChannel::writeData(QDataStream& out, int bytes, QVector& spans) { - if (bytes > 0) { - _writePosition %= _buffer.pos(); - + if (bytes == 0) { + out << (quint32)0; + return; + } + _writePosition %= _buffer.pos(); + while (bytes > 0) { int position = 0; for (int i = 0; i < _acknowledged.getSpans().size(); i++) { const SpanList::Span& span = _acknowledged.getSpans().at(i); @@ -662,9 +665,11 @@ void ReliableChannel::writeData(QDataStream& out, int bytes, QVector Date: Tue, 24 Jun 2014 19:57:52 -0700 Subject: [PATCH 40/88] argggg ssize_t from types.h --- libraries/models/src/ModelItem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 5c2db93112..16442e8d9d 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -16,6 +16,7 @@ #include #include // for ssize_t #include +#include #include From 1eb5b3dda189bdf1abe862b9c2e11d0b465866a3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 19:58:59 -0700 Subject: [PATCH 41/88] argggg ssize_t from stdlib.h --- libraries/models/src/ModelItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 16442e8d9d..db830eabf4 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -16,7 +16,7 @@ #include #include // for ssize_t #include -#include +#include #include From 1001ea5f87750b77f963923d817ff9769231692a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 20:07:47 -0700 Subject: [PATCH 42/88] fixed some windows warnings --- tests/physics/src/ShapeColliderTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 4d3c90b905..bde29ea588 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -1183,7 +1183,7 @@ void ShapeColliderTests::rayMissesCapsule() { void ShapeColliderTests::rayHitsPlane() { // make a simple plane - float planeDistanceFromOrigin = 3.579; + float planeDistanceFromOrigin = 3.579f; glm::vec3 planePosition(0.0f, planeDistanceFromOrigin, 0.0f); PlaneShape plane; plane.setTranslation(planePosition); @@ -1228,7 +1228,7 @@ void ShapeColliderTests::rayHitsPlane() { void ShapeColliderTests::rayMissesPlane() { // make a simple plane - float planeDistanceFromOrigin = 3.579; + float planeDistanceFromOrigin = 3.579f; glm::vec3 planePosition(0.0f, planeDistanceFromOrigin, 0.0f); PlaneShape plane; plane.setTranslation(planePosition); From fd3916e6626fcbe11830f33add58ef46e269e164 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 20:10:06 -0700 Subject: [PATCH 43/88] another hack attempt to fix unit tests on windows --- libraries/models/src/ModelItem.h | 11 ----------- tests/octree/src/ModelTests.cpp | 11 +++++++---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index db830eabf4..cd191846d5 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -12,11 +12,7 @@ #ifndef hifi_ModelItem_h #define hifi_ModelItem_h -#include // ??? -#include -#include // for ssize_t #include -#include #include @@ -27,15 +23,8 @@ #include #include #include -#include -//#include -//#include -#include -#include -//#include "ModelEditPacketSender.h" - class ModelItem; class ModelEditPacketSender; class ModelItemProperties; diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index e12865f807..b2c0923ef4 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -14,7 +14,13 @@ #include -#if 1 +#ifdef WIN32 +#ifndef ssize_t +#define ssize_t int +#endif +#endif + + #include #include #include @@ -22,12 +28,10 @@ #include #include #include -#endif #include "ModelTests.h" void ModelTests::modelTreeTests(bool verbose) { -#if 1 int testsTaken = 0; int testsPassed = 0; int testsFailed = 0; @@ -258,7 +262,6 @@ void ModelTests::modelTreeTests(bool verbose) { if (verbose) { qDebug() << "******************************************************************************************"; } -#endif } From a7f2d150a49b17fec6f93bd9fa61f778db267a69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 24 Jun 2014 20:15:34 -0700 Subject: [PATCH 44/88] what's this cmake defines ssize_t??? --- tests/octree/CMakeLists.txt | 5 +++++ tests/octree/src/ModelTests.cpp | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/octree/CMakeLists.txt b/tests/octree/CMakeLists.txt index 33c3bcd4a3..9c5e031d74 100644 --- a/tests/octree/CMakeLists.txt +++ b/tests/octree/CMakeLists.txt @@ -39,6 +39,11 @@ link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) IF (WIN32) + # add a definition for ssize_t so that windows doesn't bail + add_definitions(-Dssize_t=long) + #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) + target_link_libraries(${TARGET_NAME} wsock32.lib) ENDIF(WIN32) + diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index b2c0923ef4..2cca4b43f6 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -14,13 +14,6 @@ #include -#ifdef WIN32 -#ifndef ssize_t -#define ssize_t int -#endif -#endif - - #include #include #include From 60c33c18c397c70bc753fc8ba4329c414ee235e5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Jun 2014 20:32:41 -0700 Subject: [PATCH 45/88] Expose mode shift period to JS, remove default value --- examples/inspect.js | 2 ++ interface/src/Camera.cpp | 2 -- interface/src/Camera.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/inspect.js b/examples/inspect.js index b292d5f609..a4ff405c3f 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -195,6 +195,8 @@ function keyReleaseEvent(event) { } } + + function mousePressEvent(event) { if (alt && !isActive) { mouseLastX = event.x; diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 0e33e14f32..4490b60fc9 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -317,8 +317,6 @@ void CameraScriptableObject::setMode(const QString& mode) { } if (currentMode != targetMode) { _camera->setMode(targetMode); - const float DEFAULT_MODE_SHIFT_PERIOD = 0.5f; // half second - _camera->setModeShiftPeriod(DEFAULT_MODE_SHIFT_PERIOD); } } diff --git a/interface/src/Camera.h b/interface/src/Camera.h index 5e189c1111..2bbbf0e751 100644 --- a/interface/src/Camera.h +++ b/interface/src/Camera.h @@ -42,9 +42,8 @@ public: void setTargetPosition(const glm::vec3& t); void setTightness(float t) { _tightness = t; } void setTargetRotation(const glm::quat& rotation); - - void setMode(CameraMode m); void setModeShiftPeriod(float r); + void setMode(CameraMode m); void setFieldOfView(float f); void setAspectRatio(float a); void setNearClip(float n); @@ -130,6 +129,7 @@ public: public slots: QString getMode() const; void setMode(const QString& mode); + void setModeShiftPeriod(float r) {_camera->setModeShiftPeriod(r); } void setPosition(const glm::vec3& value) { _camera->setTargetPosition(value);} glm::vec3 getPosition() const { return _camera->getPosition(); } From 3bec59fd3397a7e5e873d5bfbb4b263aafd175bc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Jun 2014 20:38:46 -0700 Subject: [PATCH 46/88] Fix unindented line --- 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 ec095a4f59..67de203fa2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1286,7 +1286,7 @@ void Application::dropEvent(QDropEvent *event) { void Application::sendPingPackets() { QByteArray pingPacket = NodeList::getInstance()->constructPingPacket(); -controlledBroadcastToNodes(pingPacket, NodeSet() + controlledBroadcastToNodes(pingPacket, NodeSet() << NodeType::VoxelServer << NodeType::ParticleServer << NodeType::ModelServer << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::MetavoxelServer); From 88c01266abd1c9190e34e6a7a1d26322c2f6ab8b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 25 Jun 2014 03:29:08 -0700 Subject: [PATCH 47/88] =?UTF-8?q?more=20hair=20tweaks,=20don=E2=80=99t=20r?= =?UTF-8?q?ender=20in=201P,=20improved=20toy=20ball?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/toyball.js | 41 +++++++++++++++++++++---------- interface/src/avatar/Avatar.cpp | 39 +++++++++++++++-------------- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/MyAvatar.cpp | 2 +- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/examples/toyball.js b/examples/toyball.js index d312c1bc94..5fd522ef4a 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -26,14 +26,21 @@ var RIGHT_TIP = 3; var RIGHT_BUTTON_FWD = 11; var RIGHT_BUTTON_3 = 9; +var BALL_RADIUS = 0.08; +var GRAVITY_STRENGTH = 0.5; + +var HELD_COLOR = { red: 240, green: 0, blue: 0 }; +var THROWN_COLOR = { red: 128, green: 0, blue: 0 }; + var leftBallAlreadyInHand = false; var rightBallAlreadyInHand = false; var leftHandParticle; var rightHandParticle; -var throwSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); +var newSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); -var targetRadius = 0.25; +var throwSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); +var targetRadius = 1.0; var wantDebugging = false; @@ -54,7 +61,7 @@ function getBallHoldPosition(whichSide) { tipPosition = Controller.getSpatialControlPosition(RIGHT_TIP); } - var BALL_FORWARD_OFFSET = 0.08; // put the ball a bit forward of fingers + var BALL_FORWARD_OFFSET = 0.15; // put the ball a bit forward of fingers position = { x: BALL_FORWARD_OFFSET * normal.x, y: BALL_FORWARD_OFFSET * normal.y, z: BALL_FORWARD_OFFSET * normal.z }; @@ -69,6 +76,7 @@ function getBallHoldPosition(whichSide) { function checkControllerSide(whichSide) { var BUTTON_FWD; var BUTTON_3; + var TRIGGER; var palmPosition; var ballAlreadyInHand; var handMessage; @@ -76,18 +84,20 @@ function checkControllerSide(whichSide) { if (whichSide == LEFT_PALM) { BUTTON_FWD = LEFT_BUTTON_FWD; BUTTON_3 = LEFT_BUTTON_3; + TRIGGER = 0; palmPosition = Controller.getSpatialControlPosition(LEFT_PALM); ballAlreadyInHand = leftBallAlreadyInHand; handMessage = "LEFT"; } else { BUTTON_FWD = RIGHT_BUTTON_FWD; BUTTON_3 = RIGHT_BUTTON_3; + TRIGGER = 1; palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); ballAlreadyInHand = rightBallAlreadyInHand; handMessage = "RIGHT"; } - - var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3)); + + var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5)); // If I don't currently have a ball in my hand, then try to catch closest one if (!ballAlreadyInHand && grabButtonPressed) { @@ -107,8 +117,11 @@ function checkControllerSide(whichSide) { var ballPosition = getBallHoldPosition(whichSide); var properties = { position: { x: ballPosition.x, y: ballPosition.y, - z: ballPosition.z }, - velocity : { x: 0, y: 0, z: 0}, inHand: true }; + z: ballPosition.z }, + color: HELD_COLOR, + velocity : { x: 0, y: 0, z: 0}, + lifetime : 600, + inHand: true }; Particles.editParticle(closestParticle, properties); var options = new AudioInjectionOptions(); @@ -127,7 +140,7 @@ function checkControllerSide(whichSide) { //} // If '3' is pressed, and not holding a ball, make a new one - if (Controller.isButtonPressed(BUTTON_3) && !ballAlreadyInHand) { + if (grabButtonPressed && !ballAlreadyInHand) { var ballPosition = getBallHoldPosition(whichSide); var properties = { position: { x: ballPosition.x, y: ballPosition.y, @@ -135,11 +148,11 @@ function checkControllerSide(whichSide) { velocity: { x: 0, y: 0, z: 0}, gravity: { x: 0, y: 0, z: 0}, inHand: true, - radius: 0.05, + radius: BALL_RADIUS, damping: 0.999, - color: { red: 255, green: 0, blue: 0 }, + color: HELD_COLOR, - lifetime: 10 // 10 seconds - same as default, not needed but here as an example + lifetime: 600 // 10 seconds - same as default, not needed but here as an example }; newParticle = Particles.addParticle(properties); @@ -155,7 +168,7 @@ function checkControllerSide(whichSide) { var options = new AudioInjectionOptions(); options.position = ballPosition; options.volume = 1.0; - Audio.playSound(catchSound, options); + Audio.playSound(newSound, options); return; // exit early } @@ -188,7 +201,9 @@ function checkControllerSide(whichSide) { y: tipVelocity.y * THROWN_VELOCITY_SCALING, z: tipVelocity.z * THROWN_VELOCITY_SCALING } , inHand: false, - gravity: { x: 0, y: -2, z: 0}, + color: THROWN_COLOR, + lifetime: 10, + gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0}, }; Particles.editParticle(handParticle, properties); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2f4717dd3b..ee65b9c170 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -379,22 +379,22 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { renderHair(); } -const float HAIR_LENGTH = 0.4f; +const float HAIR_LENGTH = 0.2f; const float HAIR_LINK_LENGTH = HAIR_LENGTH / HAIR_LINKS; const float HAIR_DAMPING = 0.99f; -const float HEAD_RADIUS = 0.25f; +const float HEAD_RADIUS = 0.15f; const float COLLISION_RELAXATION = 10.f; const float CONSTRAINT_RELAXATION = 10.0f; -const float NOISE = 0.0f; // 0.1f; -const float NOISE_MAGNITUDE = 0.02f; -const glm::vec3 HAIR_GRAVITY(0.f, -0.05f, 0.f); +const glm::vec3 HAIR_GRAVITY(0.f, -0.005f, 0.f); const float HAIR_ACCELERATION_COUPLING = 0.025f; -const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.15f; -const float HAIR_MAX_LINEAR_ACCELERATION = 5.f; +const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.10f; +const float HAIR_MAX_LINEAR_ACCELERATION = 4.f; const float HAIR_THICKNESS = 0.025f; +const float HAIR_STIFFNESS = 0.002f; const glm::vec3 HAIR_COLOR1(0.98f, 0.92f, 0.843f); const glm::vec3 HAIR_COLOR2(0.545f, 0.533f, 0.47f); -const glm::vec3 WIND_DIRECTION(1.0f, -1.0f, 0.f); +const glm::vec3 WIND_DIRECTION(0.5f, -1.0f, 0.f); +const float MAX_WIND_STRENGTH = 0.01f; void Avatar::renderHair() { // @@ -447,18 +447,14 @@ void Avatar::simulateHair(float deltaTime) { acceleration = acceleration * rotation; glm::vec3 angularVelocity = getAngularVelocity() + getHead()->getAngularVelocity(); - float windIntensity = randFloat() * 0.02f; + float windIntensity = randFloat() * MAX_WIND_STRENGTH; for (int strand = 0; strand < HAIR_STRANDS; strand++) { for (int link = 0; link < HAIR_LINKS; link++) { int vertexIndex = strand * HAIR_LINKS + link; if (vertexIndex % HAIR_LINKS == 0) { // Base Joint - no integration - if (randFloat() < NOISE) { - // Move base of hair - _hairPosition[vertexIndex] += randVector() * NOISE_MAGNITUDE; - } - } else { + } else { // // Vertlet Integration // @@ -477,6 +473,10 @@ void Avatar::simulateHair(float deltaTime) { // Add linear acceleration of the avatar body _hairPosition[vertexIndex] -= acceleration * HAIR_ACCELERATION_COUPLING * deltaTime; + // Add stiffness (product) + _hairPosition[vertexIndex] += (_hairOriginalPosition[vertexIndex] - _hairPosition[vertexIndex]) + * powf(1.f - link / HAIR_LINKS, 2.f) * HAIR_STIFFNESS; + // Add some wind glm::vec3 wind = WIND_DIRECTION * windIntensity; _hairPosition[vertexIndex] += wind * deltaTime; @@ -529,17 +529,17 @@ void Avatar::simulateHair(float deltaTime) { } void Avatar::initializeHair() { - const float FACE_WIDTH = 0.25f * PI; + const float FACE_WIDTH = PI / 4.0f; glm::vec3 thisVertex; for (int strand = 0; strand < HAIR_STRANDS; strand++) { float strandAngle = randFloat() * PI; - float azimuth = randFloat() * 2.f * PI; - float elevation; - if ((azimuth > FACE_WIDTH) || (azimuth < -FACE_WIDTH)) { + float azimuth = FACE_WIDTH / 2.0f + (randFloat() * (2.0 * PI - FACE_WIDTH)); + float elevation = PI_OVER_TWO - (randFloat() * 0.75 * PI); + /*if ((azimuth > FACE_WIDTH) || (azimuth < -FACE_WIDTH)) { elevation = randFloat() * PI_OVER_TWO; } else { elevation = (PI_OVER_TWO / 2.f) + randFloat() * (PI_OVER_TWO / 2.f); - } + }*/ glm::vec3 thisStrand(sinf(azimuth) * cosf(elevation), sinf(elevation), -cosf(azimuth) * cosf(elevation)); thisStrand *= HEAD_RADIUS + 0.01f; @@ -562,6 +562,7 @@ void Avatar::initializeHair() { } _hairPosition[vertexIndex] = thisVertex; _hairLastPosition[vertexIndex] = _hairPosition[vertexIndex]; + _hairOriginalPosition[vertexIndex] = _hairPosition[vertexIndex]; _hairQuadDelta[vertexIndex] = glm::vec3(cos(strandAngle) * HAIR_THICKNESS, 0.f, sin(strandAngle) * HAIR_THICKNESS); _hairNormals[vertexIndex] = glm::normalize(randVector()); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index bb38cab5c5..40f92b468c 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -201,6 +201,7 @@ protected: virtual void updateJointMappings(); glm::vec3 _hairPosition[HAIR_STRANDS * HAIR_LINKS]; + glm::vec3 _hairOriginalPosition[HAIR_STRANDS * HAIR_LINKS]; glm::vec3 _hairLastPosition[HAIR_STRANDS * HAIR_LINKS]; glm::vec3 _hairQuadDelta[HAIR_STRANDS * HAIR_LINKS]; glm::vec3 _hairNormals[HAIR_STRANDS * HAIR_LINKS]; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6938e20313..bbdf041341 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -833,9 +833,9 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) { // Render head so long as the camera isn't inside it if (shouldRenderHead(Application::getInstance()->getCamera()->getPosition(), renderMode)) { getHead()->render(1.0f, modelRenderMode); + renderHair(); } getHand()->render(true, modelRenderMode); - renderHair(); } const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; From 40dee3b39eb01b1adf69b8d56f3eae1212ff8c21 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 25 Jun 2014 05:24:22 -0700 Subject: [PATCH 48/88] Added JS calls for left/right estimated palm position on skeleton model, improved toy ball to use them --- examples/toyball.js | 17 +------- interface/src/avatar/Avatar.cpp | 65 ++++++++++++++++++++++++++----- interface/src/avatar/MyAvatar.cpp | 19 +++++++++ interface/src/avatar/MyAvatar.h | 5 ++- 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/examples/toyball.js b/examples/toyball.js index 5fd522ef4a..e03fd67a5d 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -51,25 +51,12 @@ function debugPrint(message) { } function getBallHoldPosition(whichSide) { - var normal; - var tipPosition; if (whichSide == LEFT_PALM) { - normal = Controller.getSpatialControlNormal(LEFT_PALM); - tipPosition = Controller.getSpatialControlPosition(LEFT_TIP); + position = MyAvatar.getLeftPalmPosition(); } else { - normal = Controller.getSpatialControlNormal(RIGHT_PALM); - tipPosition = Controller.getSpatialControlPosition(RIGHT_TIP); + position = MyAvatar.getRightPalmPosition(); } - var BALL_FORWARD_OFFSET = 0.15; // put the ball a bit forward of fingers - position = { x: BALL_FORWARD_OFFSET * normal.x, - y: BALL_FORWARD_OFFSET * normal.y, - z: BALL_FORWARD_OFFSET * normal.z }; - - position.x += tipPosition.x; - position.y += tipPosition.y; - position.z += tipPosition.z; - return position; } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ee65b9c170..ee8e7266cb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -382,25 +382,46 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) { const float HAIR_LENGTH = 0.2f; const float HAIR_LINK_LENGTH = HAIR_LENGTH / HAIR_LINKS; const float HAIR_DAMPING = 0.99f; -const float HEAD_RADIUS = 0.15f; -const float COLLISION_RELAXATION = 10.f; -const float CONSTRAINT_RELAXATION = 10.0f; -const glm::vec3 HAIR_GRAVITY(0.f, -0.005f, 0.f); +const float HEAD_RADIUS = 0.18f; +const float CONSTRAINT_RELAXATION = 20.0f; +const glm::vec3 HAIR_GRAVITY(0.f, -0.015f, 0.f); const float HAIR_ACCELERATION_COUPLING = 0.025f; const float HAIR_ANGULAR_VELOCITY_COUPLING = 0.10f; const float HAIR_MAX_LINEAR_ACCELERATION = 4.f; -const float HAIR_THICKNESS = 0.025f; -const float HAIR_STIFFNESS = 0.002f; +const float HAIR_THICKNESS = 0.020f; +const float HAIR_STIFFNESS = 0.0006f; const glm::vec3 HAIR_COLOR1(0.98f, 0.92f, 0.843f); const glm::vec3 HAIR_COLOR2(0.545f, 0.533f, 0.47f); const glm::vec3 WIND_DIRECTION(0.5f, -1.0f, 0.f); const float MAX_WIND_STRENGTH = 0.01f; +const float FINGER_LENGTH = 0.25; +const float FINGER_RADIUS = 0.10; void Avatar::renderHair() { // // Render the avatar's moveable hair // + glm::vec3 headPosition = getHead()->getPosition(); + /* + glm::vec3 leftHandPosition, rightHandPosition; + getSkeletonModel().getLeftHandPosition(leftHandPosition); + getSkeletonModel().getRightHandPosition(rightHandPosition); + glm::quat leftRotation, rightRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); + rightHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(rightRotation); + + glPushMatrix(); + glTranslatef(leftHandPosition.x, leftHandPosition.y, leftHandPosition.z); + glColor4f(1.0f, 0.0f, 0.0f, 0.5f); + glutSolidSphere(FINGER_RADIUS, 20, 20); + glPopMatrix(); + glPushMatrix(); + glTranslatef(rightHandPosition.x, rightHandPosition.y, rightHandPosition.z); + glColor4f(1.0f, 0.0f, 0.0f, 0.5f); + glutSolidSphere(FINGER_RADIUS, 20, 20); + glPopMatrix(); + */ glPushMatrix(); glTranslatef(headPosition.x, headPosition.y, headPosition.z); @@ -431,13 +452,12 @@ void Avatar::renderHair() { } glEnd(); - //glColor4f(1.0f, 0.0f, 0.0f, 0.5f); - //glutSolidSphere(HEAD_RADIUS, 20, 20); glPopMatrix(); } void Avatar::simulateHair(float deltaTime) { + deltaTime = glm::clamp(deltaTime, 0.f, 1.f / 30.f); glm::vec3 acceleration = getAcceleration(); if (glm::length(acceleration) > HAIR_MAX_LINEAR_ACCELERATION) { @@ -447,6 +467,20 @@ void Avatar::simulateHair(float deltaTime) { acceleration = acceleration * rotation; glm::vec3 angularVelocity = getAngularVelocity() + getHead()->getAngularVelocity(); + // Get hand positions to allow touching hair + glm::vec3 leftHandPosition, rightHandPosition; + getSkeletonModel().getLeftHandPosition(leftHandPosition); + getSkeletonModel().getRightHandPosition(rightHandPosition); + leftHandPosition -= getHead()->getPosition(); + rightHandPosition -= getHead()->getPosition(); + glm::quat leftRotation, rightRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); + leftHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(leftRotation); + rightHandPosition += glm::vec3(0.0f, FINGER_LENGTH, 0.f) * glm::inverse(rightRotation); + leftHandPosition = leftHandPosition * rotation; + rightHandPosition = rightHandPosition * rotation; + float windIntensity = randFloat() * MAX_WIND_STRENGTH; for (int strand = 0; strand < HAIR_STRANDS; strand++) { @@ -462,11 +496,22 @@ void Avatar::simulateHair(float deltaTime) { glm::vec3 thisPosition = _hairPosition[vertexIndex]; glm::vec3 diff = thisPosition - _hairLastPosition[vertexIndex]; _hairPosition[vertexIndex] += diff * HAIR_DAMPING; - // Attempt to resolve collision with head sphere + // Resolve collision with head sphere if (glm::length(_hairPosition[vertexIndex]) < HEAD_RADIUS) { _hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex]) * - (HEAD_RADIUS - glm::length(_hairPosition[vertexIndex])) * COLLISION_RELAXATION * deltaTime; + (HEAD_RADIUS - glm::length(_hairPosition[vertexIndex])); // * COLLISION_RELAXATION * deltaTime; } + // Collide with hands + if (glm::length(_hairPosition[vertexIndex] - leftHandPosition) < FINGER_RADIUS) { + _hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex] - leftHandPosition) * + (FINGER_RADIUS - glm::length(_hairPosition[vertexIndex] - leftHandPosition)); + } + if (glm::length(_hairPosition[vertexIndex] - rightHandPosition) < FINGER_RADIUS) { + _hairPosition[vertexIndex] += glm::normalize(_hairPosition[vertexIndex] - rightHandPosition) * + (FINGER_RADIUS - glm::length(_hairPosition[vertexIndex] - rightHandPosition)); + } + + // Add a little gravity _hairPosition[vertexIndex] += HAIR_GRAVITY * rotation * deltaTime; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bbdf041341..5d6b381296 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -422,6 +422,25 @@ void MyAvatar::renderHeadMouse(int screenWidth, int screenHeight) const { } } +const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); + +glm::vec3 MyAvatar::getLeftPalmPosition() { + glm::vec3 leftHandPosition; + getSkeletonModel().getLeftHandPosition(leftHandPosition); + glm::quat leftRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); + leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation); + return leftHandPosition; +} +glm::vec3 MyAvatar::getRightPalmPosition() { + glm::vec3 rightHandPosition; + getSkeletonModel().getRightHandPosition(rightHandPosition); + glm::quat rightRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); + rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation); + return rightHandPosition; +} + void MyAvatar::setLocalGravity(glm::vec3 gravity) { _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; // Environmental and Local gravities are incompatible. Since Local is being set here diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e7023b45a1..0ee76c6b45 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -139,7 +139,10 @@ public slots: void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void updateMotionBehaviorsFromMenu(); - + + glm::vec3 getLeftPalmPosition(); + glm::vec3 getRightPalmPosition(); + signals: void transformChanged(); From e92ad862824240068238ca8cf29466b4d63175d0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 17 Jun 2014 10:54:55 -0700 Subject: [PATCH 49/88] Clear script engine errors once they have been reported So that an error is not repeatedly reported to the console and log file. Also consistently report filename. And scripts included after one in error will now be run. --- libraries/script-engine/src/ScriptEngine.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index b0cce114a9..350473cc87 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -314,8 +314,9 @@ void ScriptEngine::evaluate() { if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << result.toString(); - emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + result.toString()); + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); + _engine.clearExceptions(); } } @@ -324,7 +325,7 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN bool hasUncaughtException = _engine.hasUncaughtException(); if (hasUncaughtException) { int line = _engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ": " << result.toString(); + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString(); } emit evaluationFinished(result, hasUncaughtException); _engine.clearExceptions(); @@ -353,9 +354,9 @@ void ScriptEngine::run() { QScriptValue result = _engine.evaluate(_scriptContents); if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); - - qDebug() << "Uncaught exception at line" << line << ":" << result.toString(); - emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + result.toString()); + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); + _engine.clearExceptions(); } QElapsedTimer startTime; @@ -495,8 +496,9 @@ void ScriptEngine::run() { if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << _engine.uncaughtException().toString(); - emit errorMessage("Uncaught exception at line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << _engine.uncaughtException().toString(); + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); + _engine.clearExceptions(); } } emit scriptEnding(); @@ -656,5 +658,6 @@ void ScriptEngine::include(const QString& includeFile) { int line = _engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString(); emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString()); + _engine.clearExceptions(); } } From f8dccad6eca0149c576edabf7264106a4184ac3c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 25 Jun 2014 11:20:09 -0700 Subject: [PATCH 50/88] enable persisting of posted settings to a JSON file --- .../resources/web/settings/describe.json | 16 ++-- .../resources/web/settings/index.shtml | 2 +- domain-server/src/DomainServer.cpp | 7 +- domain-server/src/DomainServer.h | 3 + .../src/DomainServerSettingsManager.cpp | 89 ++++++++++++++++++- .../src/DomainServerSettingsManager.h | 14 ++- 6 files changed, 116 insertions(+), 15 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 763aeccdfc..b111018a30 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -1,13 +1,11 @@ { - "groups": { - "audio": { - "label": "Audio", - "settings": { - "unattenuated-zone": { - "label": "Unattenuated Zone", - "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", - "placeholder": "0,0,0,20,20,20,50,50,50,10,10,10" - } + "audio": { + "label": "Audio", + "settings": { + "unattenuated-zone": { + "label": "Unattenuated Zone", + "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", + "placeholder": "0,0,0,20,20,20,50,50,50,10,10,10" } } } diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index ee44442547..7d8a50f5b7 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -5,7 +5,7 @@
@@ -31,5 +38,5 @@ - + \ No newline at end of file From 5effcd24ff5e65c7d6551537232d68a6fe2a7cfb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 25 Jun 2014 16:56:02 -0700 Subject: [PATCH 65/88] Only increase/decrease rate when we want to send more/have sent more than the minimum, respectively. --- .../metavoxels/src/DatagramSequencer.cpp | 21 ++++++++++++++++++- libraries/metavoxels/src/DatagramSequencer.h | 3 ++- tests/metavoxels/src/MetavoxelTests.cpp | 12 ++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 0097c0fd1d..a75a4bf95b 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -79,11 +79,30 @@ ReliableChannel* DatagramSequencer::getReliableInputChannel(int index) { return channel; } -int DatagramSequencer::startPacketGroup() { +int DatagramSequencer::startPacketGroup(int desiredPackets) { + // figure out how much data we have enqueued and increase the number of packets desired + int totalAvailable = 0; + foreach (ReliableChannel* channel, _reliableOutputChannels) { + totalAvailable += channel->getBytesAvailable(); + } + desiredPackets += (totalAvailable / _maxPacketSize); + // increment our packet counter and subtract/return the integer portion _packetsToWrite += _packetsPerGroup; int wholePackets = (int)_packetsToWrite; _packetsToWrite -= wholePackets; + wholePackets = qMin(wholePackets, desiredPackets); + + // if we don't want to send any more, push out the rate increase number past the group + if (desiredPackets <= _packetsPerGroup) { + _packetRateIncreasePacketNumber = _outgoingPacketNumber + wholePackets + 1; + } + + // likewise, if we're only sending one packet, don't let its loss cause rate decrease + if (wholePackets == 1) { + _packetRateDecreasePacketNumber = _outgoingPacketNumber + 2; + } + return wholePackets; } diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index e2ea9d00af..9a4cd1334b 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -100,8 +100,9 @@ public: ReliableChannel* getReliableInputChannel(int index = 0); /// Starts a packet group. + /// \param desiredPackets the number of packets we'd like to write in the group /// \return the number of packets to write in the group - int startPacketGroup(); + int startPacketGroup(int desiredPackets = 1); /// Starts a new packet for transmission. /// \return a reference to the Bitstream to use for writing to the packet diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 9cb21faf06..68aaf7ec70 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -147,6 +147,8 @@ static int bytesSent = 0; static int bytesReceived = 0; static int maxDatagramsPerPacket = 0; static int maxBytesPerPacket = 0; +static int groupsSent = 0; +static int maxPacketsPerGroup = 0; static int highPriorityMessagesSent = 0; static int highPriorityMessagesReceived = 0; static int unreliableMessagesSent = 0; @@ -508,10 +510,12 @@ bool MetavoxelTests::run() { } qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; - qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << - datagramsReceived << "with" << bytesReceived << "bytes"; + qDebug() << "Sent" << datagramsSent << "datagrams in" << groupsSent << "groups with" << bytesSent << + "bytes, received" << datagramsReceived << "with" << bytesReceived << "bytes"; qDebug() << "Max" << maxDatagramsPerPacket << "datagrams," << maxBytesPerPacket << "bytes per packet"; - qDebug() << "Average" << (bytesReceived / datagramsReceived) << "bytes per datagram"; + qDebug() << "Max" << maxPacketsPerGroup << "packets per group"; + qDebug() << "Average" << (bytesReceived / datagramsReceived) << "bytes per datagram," << + (datagramsSent / groupsSent) << "datagrams per group"; qDebug() << "Speed:" << (bytesReceived / SIMULATION_ITERATIONS) << "bytes per iteration"; qDebug() << "Efficiency:" << ((float)streamedBytesReceived / bytesReceived); } @@ -821,6 +825,8 @@ bool Endpoint::simulate(int iterationNumber) { _remainingPipelineCapacity += datagram.size(); } int packetCount = _sequencer->startPacketGroup(); + groupsSent++; + maxPacketsPerGroup = qMax(maxPacketsPerGroup, packetCount); for (int i = 0; i < packetCount; i++) { oldDatagramsSent = datagramsSent; oldBytesSent = bytesSent; From c72e41dcd298c60026a6fb8b45b77df3eef9a819 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 25 Jun 2014 22:27:54 -0700 Subject: [PATCH 66/88] added Oculus angular velocity, moved sit icon up --- examples/sit.js | 2 +- interface/src/avatar/MyAvatar.cpp | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index 32d2eebf4d..77a626c63f 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -19,7 +19,7 @@ var buttonHeight = 46; var buttonPadding = 10; var buttonPositionX = windowDimensions.x - buttonPadding - buttonWidth; -var buttonPositionY = (windowDimensions.y - buttonHeight) / 2 ; +var buttonPositionY = (windowDimensions.y - buttonHeight) / 2 - (buttonHeight + buttonPadding); var sitDownButton = Overlays.addOverlay("image", { x: buttonPositionX, y: buttonPositionY, width: buttonWidth, height: buttonHeight, diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b853f3ff8f..7367f64d73 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -911,11 +911,19 @@ void MyAvatar::updateOrientation(float deltaTime) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); // ... so they need to be converted to degrees before we do math... - + yaw *= DEGREES_PER_RADIAN; + pitch *= DEGREES_PER_RADIAN; + roll *= DEGREES_PER_RADIAN; + + // Record the angular velocity Head* head = getHead(); - head->setBaseYaw(yaw * DEGREES_PER_RADIAN); - head->setBasePitch(pitch * DEGREES_PER_RADIAN); - head->setBaseRoll(roll * DEGREES_PER_RADIAN); + glm::vec3 angularVelocity(yaw - head->getBaseYaw(), pitch - head->getBasePitch(), roll - head->getBaseRoll()); + head->setAngularVelocity(angularVelocity); + + head->setBaseYaw(yaw); + head->setBasePitch(pitch); + head->setBaseRoll(roll); + } // update the euler angles From 5cd2dc594fff6f168c29b3f84844619e3530751e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 08:45:12 -0700 Subject: [PATCH 67/88] only post changed values to settings.json, fix for bool values --- domain-server/resources/web/js/settings.js | 27 +++++++++++++++++-- .../resources/web/settings/describe.json | 2 +- .../resources/web/settings/index.shtml | 8 +++--- .../src/DomainServerSettingsManager.cpp | 7 ++--- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 293ccce36d..487ec5b296 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -15,9 +15,19 @@ function reloadSettings() { var SETTINGS_ERROR_MESSAGE = "There was a problem saving domain settings. Please try again!"; -$('#settings').on('click', 'button', function(e){ +$('#settings').on('click', 'button', function(e){ + // disable any inputs not changed + $("input:not([data-changed])").each(function(){ + $(this).prop('disabled', true); + }); + // grab a JSON representation of the form via form2js - var formJSON = form2js('settings-form', ".", false, null, true); + var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true); + + // re-enable all inputs + $("input").each(function(){ + $(this).prop('disabled', false); + }); // POST the form JSON to the domain-server settings.json endpoint so the settings are saved $.ajax('/settings.json', { @@ -40,6 +50,19 @@ $('#settings').on('click', 'button', function(e){ return false; }); +$('#settings').on('change', 'input', function(){ + // this input was changed, add the changed data attribute to it + $(this).attr('data-changed', true); +}); + +function cleanupFormValues(node) { + if (node.type && node.type === 'checkbox') { + return { name: node.id, value: node.checked ? true : false }; + } else { + return false; + } +} + function showAlertMessage(message, isSuccess) { var alertBox = $('.alert'); alertBox.attr('class', 'alert'); diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 5e810baa12..2c0440ac01 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -13,7 +13,7 @@ "type": "checkbox", "label": "Dynamic Jitter Buffers", "help": "Dynamically buffer client audio based on perceived jitter in packet receipt timing", - "default": "false" + "default": false } } } diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index d95bd65d44..15ce842f30 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -13,13 +13,15 @@
<% _.each(group.settings, function(setting, setting_key){ %>
- + <% var setting_id = group_key + "." + setting_key %> +
<% if(setting.type) %> <% if (setting.type === "checkbox") { %> - + <% var checked_box = (_.isUndefined(values[group_key][setting_key]) ? setting.default : values[group_key][setting_key]) %> + > <% } else { %> - + <% } %>
diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index fabd26c8e0..4229e45191 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -81,10 +81,11 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ // we don't continue if this key is not present in our descriptionObject if (descriptionObject.contains(key)) { if (rootValue.isString()) { - // if this is a string then just set it in our settingsVariant settingsVariant[key] = rootValue.toString(); + } else if (rootValue.isBool()) { + settingsVariant[key] = rootValue.toBool(); } else if (rootValue.isObject()) { - + // there's a JSON Object to explore, so attempt to recurse into it QJsonObject nextDescriptionObject = descriptionObject[key].toObject(); if (nextDescriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) { @@ -93,7 +94,7 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ settingsVariant[key] = QVariantMap(); } - // there's a JSON Object to explore, so recurse into it + recurseJSONObjectAndOverwriteSettings(rootValue.toObject(), *reinterpret_cast(settingsVariant[key].data()), nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toObject()); From 0d18f2fbaba2b759b0663235c243fe1608d32f9c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Jun 2014 09:12:44 -0700 Subject: [PATCH 68/88] fix for avatar models with multiple roots --- interface/src/avatar/SkeletonModel.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index fdb3ce03d8..e9328d32ca 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -637,12 +637,15 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) - transforms[0] = _jointStates[0].getTransform(); - _ragdollPoints[0]._position = extractTranslation(transforms[0]); - _ragdollPoints[0]._lastPosition = _ragdollPoints[0]._position; - for (int i = 1; i < numJoints; i++) { + for (int i = 0; i < numJoints; i++) { const FBXJoint& joint = geometry.joints.at(i); int parentIndex = joint.parentIndex; + if (parentIndex == -1) { + transforms[i] = _jointStates[i].getTransform(); + _ragdollPoints[i]._position = extractTranslation(transforms[i]); + _ragdollPoints[i]._lastPosition = _ragdollPoints[i]._position; + continue; + } assert(parentIndex != -1); glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; From 64c89df5c1ce25aaeeaba7be6c669889b24b949e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 26 Jun 2014 10:52:37 -0700 Subject: [PATCH 69/88] Added another concert view --- examples/concertCamera.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/concertCamera.js b/examples/concertCamera.js index 0d26fd8ae0..7280958bc6 100644 --- a/examples/concertCamera.js +++ b/examples/concertCamera.js @@ -16,8 +16,8 @@ var avatarPosition; var cameraNumber = 0; var freeCamera = false; -var cameraLocations = [ {x: 7972.0, y: 241.6, z: 7304.1}, {x: 7973.7, y: 241.6, z: 7304.1}, {x: 7975.5, y: 241.6, z: 7304.1}, {x: 7972.3, y: 241.6, z: 7303.3}, {x: 7971.4, y: 241.6, z: 7304.3} ]; -var cameraLookAts = [ {x: 7971.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1} ]; +var cameraLocations = [ {x: 7972.2, y: 241.6, z: 7304.1}, {x: 7973.0, y: 241.6, z: 7304.1}, {x: 7975.5, y: 241.6, z: 7304.1}, {x: 7972.3, y: 241.6, z: 7303.3}, {x: 7971.4, y: 241.6, z: 7304.3}, {x: 7973.5, y: 240.6, z: 7302.5} ]; +var cameraLookAts = [ {x: 7971.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241., z: 7304.1} ]; function saveCameraState() { oldMode = Camera.getMode(); From e56f4aba0a7b93b4b9060d25103d01f4fa2657f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 15:40:10 -0700 Subject: [PATCH 70/88] use underscorejs for nodes table template --- domain-server/resources/web/index.shtml | 16 +++++++++++++++- domain-server/resources/web/js/tables.js | 24 ++++-------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index b6ba8f67db..9d5ee93857 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -18,7 +18,20 @@ - +

Queued Assignments

@@ -35,4 +48,5 @@ + \ No newline at end of file diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index b564d9392f..28e54b3773 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -1,4 +1,7 @@ $(document).ready(function(){ + // setup the underscore templates + var nodeTemplate = _.template($('#nodes-template').html()); + // setup a function to grab the assignments function getNodesAndAssignments() { $.getJSON("nodes.json", function(json){ @@ -29,26 +32,7 @@ $(document).ready(function(){ } }); - nodesTableBody = ""; - - $.each(json.nodes, function(index, data) { - nodesTableBody += ""; - nodesTableBody += "" + data.type + ""; - nodesTableBody += "" + data.uuid + ""; - nodesTableBody += "" + (data.pool ? data.pool : "") + ""; - nodesTableBody += "" + data.public.ip + ":" + data.public.port + ""; - nodesTableBody += "" + data.local.ip + ":" + data.local.port + ""; - - var uptimeSeconds = (Date.now() - data.wake_timestamp) / 1000; - nodesTableBody += "" + uptimeSeconds.toLocaleString() + ""; - - nodesTableBody += "" + (typeof data.pending_credits == 'number' ? data.pending_credits.toLocaleString() : 'N/A') + ""; - - nodesTableBody += ""; - nodesTableBody += ""; - }); - - $('#nodes-table tbody').html(nodesTableBody); + $('#nodes-table tbody').html(nodeTemplate(json)); }); $.getJSON("assignments.json", function(json){ From ab50432ead5d0ec74cf07c24b501880863ef2689 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 15:45:31 -0700 Subject: [PATCH 71/88] use underscorejs templating for queued assignments --- domain-server/resources/web/index.shtml | 9 +++++++++ domain-server/resources/web/js/tables.js | 13 ++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/domain-server/resources/web/index.shtml b/domain-server/resources/web/index.shtml index 9d5ee93857..f0315a113f 100644 --- a/domain-server/resources/web/index.shtml +++ b/domain-server/resources/web/index.shtml @@ -44,6 +44,15 @@ + diff --git a/domain-server/resources/web/js/tables.js b/domain-server/resources/web/js/tables.js index 28e54b3773..0b29d4e6c9 100644 --- a/domain-server/resources/web/js/tables.js +++ b/domain-server/resources/web/js/tables.js @@ -1,6 +1,7 @@ $(document).ready(function(){ // setup the underscore templates var nodeTemplate = _.template($('#nodes-template').html()); + var queuedTemplate = _.template($('#queued-template').html()); // setup a function to grab the assignments function getNodesAndAssignments() { @@ -36,17 +37,7 @@ $(document).ready(function(){ }); $.getJSON("assignments.json", function(json){ - queuedTableBody = ""; - - $.each(json.queued, function (uuid, data) { - queuedTableBody += ""; - queuedTableBody += "" + data.type + ""; - queuedTableBody += "" + uuid + ""; - queuedTableBody += "" + (data.pool ? data.pool : "") + ""; - queuedTableBody += ""; - }); - - $('#assignments-table tbody').html(queuedTableBody); + $('#assignments-table tbody').html(queuedTemplate(json)); }); } From 731690e3588958095d3f7216b9cd54c0edfdeff0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 16:29:44 -0700 Subject: [PATCH 72/88] add querying for settings that affect a specific type --- .../resources/web/settings/describe.json | 2 +- .../resources/web/settings/index.shtml | 6 +- .../src/DomainServerSettingsManager.cpp | 76 +++++++++++++++++-- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index 2c0440ac01..227b6bf0cd 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -1,7 +1,7 @@ { "audio": { "label": "Audio", - "types": [0], + "assignment-types": [0], "settings": { "unattenuated-zone": { "label": "Unattenuated Zone", diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 15ce842f30..3bb669b32e 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -18,10 +18,12 @@
<% if(setting.type) %> <% if (setting.type === "checkbox") { %> - <% var checked_box = (_.isUndefined(values[group_key][setting_key]) ? setting.default : values[group_key][setting_key]) %> + <% var checked_box = (values[group_key] || {})[setting_key] || setting.default %> > <% } else { %> - + <% } %>
diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 4229e45191..d7e2e05ca8 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -11,9 +11,12 @@ #include #include +#include #include #include +#include +#include #include #include "DomainServerSettingsManager.h" @@ -38,6 +41,9 @@ DomainServerSettingsManager::DomainServerSettingsManager() : _settingsMap = QJsonDocument::fromJson(configFile.readAll()).toVariant().toMap(); } +const QString DESCRIPTION_SETTINGS_KEY = "settings"; +const QString SETTING_DEFAULT_KEY = "default"; + bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, const QUrl &url) { if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == "/settings.json") { // this is a POST operation to change one or more settings @@ -57,20 +63,75 @@ bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, return true; } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") { // this is a GET operation for our settings - // combine the description object and our current settings map - QJsonObject combinedObject; - combinedObject["descriptions"] = _descriptionObject; - combinedObject["values"] = QJsonDocument::fromVariant(_settingsMap).object(); - connection->respond(HTTPConnection::StatusCode200, QJsonDocument(combinedObject).toJson(), "application/json"); + // check if there is a query parameter for settings affecting a particular type of assignment + const QString SETTINGS_TYPE_QUERY_KEY = "type"; + QUrlQuery settingsQuery(url); + QString typeValue = settingsQuery.queryItemValue(SETTINGS_TYPE_QUERY_KEY); + + QJsonObject responseObject; + + if (typeValue.isEmpty()) { + // combine the description object and our current settings map + responseObject["descriptions"] = _descriptionObject; + responseObject["values"] = QJsonDocument::fromVariant(_settingsMap).object(); + } else { + // convert the string type value to a QJsonValue + QJsonValue queryType = QJsonValue(typeValue.toInt()); + + const QString AFFECTED_TYPES_JSON_KEY = "assignment-types"; + + // enumerate the groups in the description object to find which settings to pass + foreach(const QString& group, _descriptionObject.keys()) { + QJsonObject groupObject = _descriptionObject[group].toObject(); + QJsonObject groupSettingsObject = groupObject[DESCRIPTION_SETTINGS_KEY].toObject(); + + QJsonObject groupResponseObject; + + + foreach(const QString& settingKey, groupSettingsObject.keys()) { + QJsonObject settingObject = groupSettingsObject[settingKey].toObject(); + + QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray(); + if (affectedTypesArray.isEmpty()) { + affectedTypesArray = groupObject[AFFECTED_TYPES_JSON_KEY].toArray(); + } + + if (affectedTypesArray.contains(queryType)) { + // this is a setting we should include in the responseObject + + // we need to check if the settings map has a value for this setting + QVariant variantValue; + QVariant settingsMapGroupValue = _settingsMap.value(group); + + if (!settingsMapGroupValue.isNull()) { + variantValue = settingsMapGroupValue.toMap().value(settingKey); + } + + if (variantValue.isNull()) { + // no value for this setting, pass the default + groupResponseObject[settingKey] = settingObject[SETTING_DEFAULT_KEY]; + } else { + groupResponseObject[settingKey] = QJsonValue::fromVariant(variantValue); + } + } + } + + if (!groupResponseObject.isEmpty()) { + // set this group's object to the constructed object + responseObject[group] = groupResponseObject; + } + } + + } + + connection->respond(HTTPConnection::StatusCode200, QJsonDocument(responseObject).toJson(), "application/json"); return true; } return false; } -const QString DESCRIPTION_SETTINGS_KEY = "settings"; - void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, QJsonObject descriptionObject) { @@ -94,7 +155,6 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ settingsVariant[key] = QVariantMap(); } - recurseJSONObjectAndOverwriteSettings(rootValue.toObject(), *reinterpret_cast(settingsVariant[key].data()), nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toObject()); From e41d3f407b4c8cd036f36ed95c5a24e0628cc303 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 26 Jun 2014 16:40:59 -0700 Subject: [PATCH 73/88] Removed nested lock --- libraries/models/src/ModelsScriptingInterface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/models/src/ModelsScriptingInterface.cpp b/libraries/models/src/ModelsScriptingInterface.cpp index 7e08571fe5..bac1213071 100644 --- a/libraries/models/src/ModelsScriptingInterface.cpp +++ b/libraries/models/src/ModelsScriptingInterface.cpp @@ -160,10 +160,8 @@ ModelItemID ModelsScriptingInterface::findClosestModel(const glm::vec3& center, QVector ModelsScriptingInterface::findModels(const glm::vec3& center, float radius) const { QVector result; if (_modelTree) { - _modelTree->lockForRead(); QVector models; _modelTree->findModels(center/(float)TREE_SCALE, radius/(float)TREE_SCALE, models); - _modelTree->unlock(); foreach (const ModelItem* model, models) { ModelItemID thisModelItemID(model->getID(), UNKNOWN_MODEL_TOKEN, true); From 95d266b30598082057302fdd128edae4cca09d6c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 16:55:22 -0700 Subject: [PATCH 74/88] initial setup of settings request from domain-server --- assignment-client/src/Agent.cpp | 2 - assignment-client/src/audio/AudioMixer.cpp | 39 +++++++++++++++++++ .../src/DomainServerSettingsManager.cpp | 2 +- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index fcc2288356..e6c14d06da 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -213,8 +213,6 @@ void Agent::run() { loop.exec(); - - // let the AvatarData and ResourceCache classes use our QNetworkAccessManager AvatarData::setNetworkAccessManager(networkManager); ResourceCache::setNetworkAccessManager(networkManager); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8e4ce04f0b..83e6c10c02 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include #include #include @@ -478,6 +481,42 @@ void AudioMixer::run() { nodeList->linkedDataCreateCallback = attachNewBufferToNode; + // setup a QNetworkAccessManager to ask the domain-server for our settings + QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); + + QUrl settingsJSONURL; + settingsJSONURL.setScheme("http"); + settingsJSONURL.setHost(nodeList->getDomainHandler().getHostname()); + settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); + settingsJSONURL.setPath("/settings.json/"); + settingsJSONURL.setQuery("type=" + QString(_type)); + + QNetworkReply *reply = NULL; + + int failedAttempts = 0; + const int MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS = 5; + + qDebug() << "Requesting settings for assignment from domain-server at" << settingsJSONURL.toString(); + + while (!reply || reply->error() != QNetworkReply::NoError) { + reply = networkManager->get(QNetworkRequest(settingsJSONURL)); + + QEventLoop loop; + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + + loop.exec(); + ++failedAttempts; + + if (failedAttempts == MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { + qDebug() << "Failed to get settings from domain-server. Bailing on assignment."; + setFinished(true); + return; + } + } + + QJsonDocument settingsJSON = QJsonDocument::fromJson(reply->readAll()); + qDebug() << settingsJSON; + // check the payload to see if we have any unattenuated zones const QString UNATTENUATED_ZONE_REGEX_STRING = "--unattenuated-zone ([\\d.,-]+)"; QRegExp unattenuatedZoneMatch(UNATTENUATED_ZONE_REGEX_STRING); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index d7e2e05ca8..f3315e8324 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -61,7 +61,7 @@ bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); return true; - } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") { + } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settingz.json") { // this is a GET operation for our settings // check if there is a query parameter for settings affecting a particular type of assignment From 3f70402e63eca22f5fbea9795de52a32be55a315 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 16:58:51 -0700 Subject: [PATCH 75/88] fix odd encoding in settings URL --- assignment-client/src/audio/AudioMixer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 83e6c10c02..9e52e895d3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -489,7 +489,7 @@ void AudioMixer::run() { settingsJSONURL.setHost(nodeList->getDomainHandler().getHostname()); settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); settingsJSONURL.setPath("/settings.json/"); - settingsJSONURL.setQuery("type=" + QString(_type)); + settingsJSONURL.setQuery(QString("type=%1").arg(_type)); QNetworkReply *reply = NULL; @@ -515,7 +515,6 @@ void AudioMixer::run() { } QJsonDocument settingsJSON = QJsonDocument::fromJson(reply->readAll()); - qDebug() << settingsJSON; // check the payload to see if we have any unattenuated zones const QString UNATTENUATED_ZONE_REGEX_STRING = "--unattenuated-zone ([\\d.,-]+)"; From 3ae46bc60d0cd0db3f3c67b50810a234c022ef74 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 26 Jun 2014 17:32:56 -0700 Subject: [PATCH 76/88] switch audio-mixer to pull settings from domain-server via JSON request --- assignment-client/src/audio/AudioMixer.cpp | 68 ++++++++++--------- .../src/DomainServerSettingsManager.cpp | 2 +- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9e52e895d3..407a4413d5 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -488,7 +488,7 @@ void AudioMixer::run() { settingsJSONURL.setScheme("http"); settingsJSONURL.setHost(nodeList->getDomainHandler().getHostname()); settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settings.json/"); + settingsJSONURL.setPath("/settings.json"); settingsJSONURL.setQuery(QString("type=%1").arg(_type)); QNetworkReply *reply = NULL; @@ -505,6 +505,7 @@ void AudioMixer::run() { QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); + ++failedAttempts; if (failedAttempts == MAX_SETTINGS_REQUEST_FAILED_ATTEMPTS) { @@ -514,42 +515,47 @@ void AudioMixer::run() { } } - QJsonDocument settingsJSON = QJsonDocument::fromJson(reply->readAll()); + QJsonObject settingsObject = QJsonDocument::fromJson(reply->readAll()).object(); - // check the payload to see if we have any unattenuated zones - const QString UNATTENUATED_ZONE_REGEX_STRING = "--unattenuated-zone ([\\d.,-]+)"; - QRegExp unattenuatedZoneMatch(UNATTENUATED_ZONE_REGEX_STRING); + // check the settings object to see if we have anything we can parse out + const QString AUDIO_GROUP_KEY = "audio"; - if (unattenuatedZoneMatch.indexIn(_payload) != -1) { - QString unattenuatedZoneString = unattenuatedZoneMatch.cap(1); - QStringList zoneStringList = unattenuatedZoneString.split(','); + if (settingsObject.contains(AUDIO_GROUP_KEY)) { + QJsonObject audioGroupObject = settingsObject[AUDIO_GROUP_KEY].toObject(); - glm::vec3 sourceCorner(zoneStringList[0].toFloat(), zoneStringList[1].toFloat(), zoneStringList[2].toFloat()); - glm::vec3 sourceDimensions(zoneStringList[3].toFloat(), zoneStringList[4].toFloat(), zoneStringList[5].toFloat()); - - glm::vec3 listenerCorner(zoneStringList[6].toFloat(), zoneStringList[7].toFloat(), zoneStringList[8].toFloat()); - glm::vec3 listenerDimensions(zoneStringList[9].toFloat(), zoneStringList[10].toFloat(), zoneStringList[11].toFloat()); + const QString UNATTENUATED_ZONE_KEY = "unattenuated-zone"; - _sourceUnattenuatedZone = new AABox(sourceCorner, sourceDimensions); - _listenerUnattenuatedZone = new AABox(listenerCorner, listenerDimensions); - - glm::vec3 sourceCenter = _sourceUnattenuatedZone->calcCenter(); - glm::vec3 destinationCenter = _listenerUnattenuatedZone->calcCenter(); - - qDebug() << "There is an unattenuated zone with source center at" + QString unattenuatedZoneString = audioGroupObject[UNATTENUATED_ZONE_KEY].toString(); + if (!unattenuatedZoneString.isEmpty()) { + QStringList zoneStringList = unattenuatedZoneString.split(','); + + glm::vec3 sourceCorner(zoneStringList[0].toFloat(), zoneStringList[1].toFloat(), zoneStringList[2].toFloat()); + glm::vec3 sourceDimensions(zoneStringList[3].toFloat(), zoneStringList[4].toFloat(), zoneStringList[5].toFloat()); + + glm::vec3 listenerCorner(zoneStringList[6].toFloat(), zoneStringList[7].toFloat(), zoneStringList[8].toFloat()); + glm::vec3 listenerDimensions(zoneStringList[9].toFloat(), zoneStringList[10].toFloat(), zoneStringList[11].toFloat()); + + _sourceUnattenuatedZone = new AABox(sourceCorner, sourceDimensions); + _listenerUnattenuatedZone = new AABox(listenerCorner, listenerDimensions); + + glm::vec3 sourceCenter = _sourceUnattenuatedZone->calcCenter(); + glm::vec3 destinationCenter = _listenerUnattenuatedZone->calcCenter(); + + qDebug() << "There is an unattenuated zone with source center at" << QString("%1, %2, %3").arg(sourceCenter.x).arg(sourceCenter.y).arg(sourceCenter.z); - qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at" + qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at" << QString("%1, %2, %3").arg(destinationCenter.x).arg(destinationCenter.y).arg(destinationCenter.z); - } - - // check the payload to see if we have asked for dynamicJitterBuffer support - const QString DYNAMIC_JITTER_BUFFER_REGEX_STRING = "--dynamicJitterBuffer"; - QRegExp dynamicJitterBufferMatch(DYNAMIC_JITTER_BUFFER_REGEX_STRING); - if (dynamicJitterBufferMatch.indexIn(_payload) != -1) { - qDebug() << "Enable dynamic jitter buffers."; - _useDynamicJitterBuffers = true; - } else { - qDebug() << "Dynamic jitter buffers disabled, using old behavior."; + } + + // check the payload to see if we have asked for dynamicJitterBuffer support + const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic-jitter-buffer"; + bool shouldUseDynamicJitterBuffers = audioGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool(); + if (shouldUseDynamicJitterBuffers) { + qDebug() << "Enable dynamic jitter buffers."; + _useDynamicJitterBuffers = true; + } else { + qDebug() << "Dynamic jitter buffers disabled, using old behavior."; + } } int nextFrame = 0; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index f3315e8324..d7e2e05ca8 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -61,7 +61,7 @@ bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); return true; - } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settingz.json") { + } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") { // this is a GET operation for our settings // check if there is a query parameter for settings affecting a particular type of assignment From bb44d8b478c72f7657028a59c38c94411a17af25 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 27 Jun 2014 09:36:47 -0700 Subject: [PATCH 77/88] fix place lookup for new APIs --- interface/src/location/LocationManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 1d783cc8e7..32172d6e38 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -15,7 +15,7 @@ #include "LocationManager.h" const QString GET_USER_ADDRESS = "/api/v1/users/%1/address"; -const QString GET_PLACE_ADDRESS = "/api/v1/places/%1/address"; +const QString GET_PLACE_ADDRESS = "/api/v1/places/%1"; const QString GET_ADDRESSES = "/api/v1/addresses/%1"; const QString POST_PLACE_CREATE = "/api/v1/places/"; From aad666be62a49a52c58d0063028013a26551ce3e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Jun 2014 09:48:27 -0700 Subject: [PATCH 78/88] more sitting work --- examples/sit.js | 184 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 177 insertions(+), 7 deletions(-) diff --git a/examples/sit.js b/examples/sit.js index 77a626c63f..576b17dcf5 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -38,9 +38,14 @@ var standUpButton = Overlays.addOverlay("image", { var passedTime = 0.0; var startPosition = null; +var startRotation = null; var animationLenght = 2.0; -var sitting = false; +var avatarOldPosition = { x: 0, y: 0, z: 0 }; + +var sitting = false; + +var seat = new Object(); // This is the pose we would like to end up var pose = [ @@ -83,7 +88,7 @@ var sittingDownAnimation = function(deltaTime) { } } -var standingUpAnimation = function(deltaTime){ +var standingUpAnimation = function(deltaTime) { passedTime += deltaTime; var factor = 1 - passedTime/animationLenght; @@ -97,6 +102,23 @@ var standingUpAnimation = function(deltaTime){ } } +var goToSeatAnimation = function(deltaTime) { + passedTime += deltaTime; + var factor = passedTime/animationLenght; + + if (passedTime <= animationLenght) { + var targetPosition = Vec3.sum(seat.position, { x: 0.3, y: 0.5, z: 0 }); + MyAvatar.position = Vec3.sum(Vec3.multiply(startPosition, 1 - factor), Vec3.multiply(targetPosition, factor)); + } else if (passedTime <= 2 * animationLenght) { + Quat.print("MyAvatar: ", MyAvatar.orientation); + Quat.print("Seat: ", seat.rotation); + MyAvatar.orientation = Quat.mix(startRotation, seat.rotation, factor - 1); + } else { + Script.update.disconnect(goToSeatAnimation); + sitDown(); + } +} + function sitDown() { sitting = true; passedTime = 0.0; @@ -124,15 +146,104 @@ function standUp() { Overlays.editOverlay(sitDownButton, { visible: true }); } -Controller.mousePressEvent.connect(function(event){ +var models = new Object(); +function SeatIndicator(modelProperties, seatIndex) { + this.position = Vec3.sum(modelProperties.position, + Vec3.multiply(Vec3.multiplyQbyV(modelProperties.modelRotation, + modelProperties.sittingPoints[seatIndex].position), + modelProperties.radius)); + + this.orientation = Quat.multiply(modelProperties.modelRotation, + modelProperties.sittingPoints[seatIndex].rotation); + this.scale = MyAvatar.scale / 12; + + this.sphere = Overlays.addOverlay("sphere", { + position: this.position, + size: this.scale, + solid: true, + color: { red: 0, green: 0, blue: 255 }, + alpha: 1, + visible: true + }); + + this.show = function(doShow) { + Overlays.editOverlay(this.sphere, { visible: doShow }); + } + + this.update = function() { + Overlays.editOverlay(this.sphere, { + position: this.position, + size: this.scale + }); + } + + this.cleanup = function() { + Overlays.deleteOverlay(this.sphere); + } +} +Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay == sitDownButton) { sitDown(); } else if (clickedOverlay == standUpButton) { standUp(); - } + } else { + var pickRay = Camera.computePickRay(event.x, event.y); + + var clickedOnSeat = false; + + for (index in models) { + var model = models[index]; + + for (var i = 0; i < model.properties.sittingPoints.length; ++i) { + if (raySphereIntersection(pickRay.origin, + pickRay.direction, + model.properties.sittingPoints[i].indicator.position, + model.properties.sittingPoints[i].indicator.scale / 2)) { + clickedOnSeat = true; + seat.position = model.properties.sittingPoints[i].indicator.position; + seat.rotation = model.properties.sittingPoints[i].indicator.orientation; + } + } + } + if (clickedOnSeat) { + passedTime = 0.0; + startPosition = MyAvatar.position; + startRotation = MyAvatar.orientation; + try{ Script.update.disconnect(standingUpAnimation); } catch(e){} + try{ Script.update.disconnect(sittingDownAnimation); } catch(e){} + Script.update.connect(goToSeatAnimation); + } + + + + return; + var intersection = Models.findRayIntersection(pickRay); + + if (intersection.accurate && intersection.intersects && false) { + var properties = intersection.modelProperties; + print("Intersecting with model, let's check for seats."); + + if (properties.sittingPoints.length > 0) { + print("Available seats, going to the first one: " + properties.sittingPoints[0].name); + seat.position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.modelRotation, properties.sittingPoints[0].position)); + Vec3.print("Seat position: ", seat.position); + seat.rotation = Quat.multiply(properties.modelRotation, properties.sittingPoints[0].rotation); + Quat.print("Seat rotation: ", seat.rotation); + + passedTime = 0.0; + startPosition = MyAvatar.position; + startRotation = MyAvatar.orientation; + try{ Script.update.disconnect(standingUpAnimation); } catch(e){} + try{ Script.update.disconnect(sittingDownAnimation); } catch(e){} + Script.update.connect(goToSeatAnimation); + } else { + print ("Sorry, no seats here."); + } + } + } }) function update(deltaTime){ @@ -143,7 +254,62 @@ function update(deltaTime){ var newY = (windowDimensions.y - buttonHeight) / 2 ; Overlays.editOverlay( standUpButton, {x: newX, y: newY} ); Overlays.editOverlay( sitDownButton, {x: newX, y: newY} ); - } + } + + if (MyAvatar.position.x != avatarOldPosition.x && + MyAvatar.position.y != avatarOldPosition.y && + MyAvatar.position.z != avatarOldPosition.z) { + avatarOldPosition = MyAvatar.position; + + var SEARCH_RADIUS = 5; + var foundModels = Models.findModels(MyAvatar.position, SEARCH_RADIUS); + // Let's remove indicator that got out of radius + for (model in models) { + if (Vec3.distance(models[model].properties.position, MyAvatar.position) > SEARCH_RADIUS) { + removeIndicators(models[model]); + } + } + + // Let's add indicators to new seats in radius + for (var i = 0; i < foundModels.length; ++i) { + var model = foundModels[i]; + if (typeof(models[model.id]) == "undefined") { + addIndicators(model); + } + } + } +} + +function addIndicators(modelID) { + modelID.properties = Models.getModelProperties(modelID); + if (modelID.properties.sittingPoints.length > 0) { + for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) { + modelID.properties.sittingPoints[i].indicator = new SeatIndicator(modelID.properties, i); + } + + models[modelID.id] = modelID; + } else { + Models.editModel(modelID, { glowLevel: 0.0 }); + } +} + +function removeIndicators(modelID) { + for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) { + modelID.properties.sittingPoints[i].indicator.cleanup(); + } + delete models[modelID.id]; +} + +function raySphereIntersection(origin, direction, center, radius) { + var A = origin; + var B = Vec3.normalize(direction); + var P = center; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + + return (x > 0 && d <= radius); } function keyPressEvent(event) { @@ -161,11 +327,15 @@ Script.update.connect(update); Controller.keyPressEvent.connect(keyPressEvent); Script.scriptEnding.connect(function() { - for (var i = 0; i < pose.length; i++){ MyAvatar.clearJointData(pose[i].joint); - } + } Overlays.deleteOverlay(sitDownButton); Overlays.deleteOverlay(standUpButton); + for (model in models){ + for (var i = 0; i < models[model].properties.sittingPoints.length; ++i) { + models[model].properties.sittingPoints[i].indicator.cleanup(); + } + } }); From baf4a82269fc528bbd39b0922a4ea5fd33561527 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Jun 2014 09:56:03 -0700 Subject: [PATCH 79/88] Fix crash occuring when geometry not yet available --- libraries/models/src/ModelTreeElement.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/models/src/ModelTreeElement.cpp b/libraries/models/src/ModelTreeElement.cpp index c9e5f0f309..960d1dd4cb 100644 --- a/libraries/models/src/ModelTreeElement.cpp +++ b/libraries/models/src/ModelTreeElement.cpp @@ -330,7 +330,9 @@ bool ModelTreeElement::updateModel(const ModelItemID& modelID, const ModelItemPr } if (found) { thisModel.setProperties(properties); - thisModel.setSittingPoints(_myTree->getGeometryForModel(thisModel)->sittingPoints); + if (_myTree->getGeometryForModel(thisModel)) { + thisModel.setSittingPoints(_myTree->getGeometryForModel(thisModel)->sittingPoints); + } markWithChangedTime(); // mark our element as changed.. const bool wantDebug = false; if (wantDebug) { From 4281168fe99e06dcf6fd77854fce326385231731 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Jun 2014 10:03:50 -0700 Subject: [PATCH 80/88] Hide seat once you are seated --- examples/sit.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/sit.js b/examples/sit.js index 576b17dcf5..57828afc52 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -46,6 +46,7 @@ var avatarOldPosition = { x: 0, y: 0, z: 0 }; var sitting = false; var seat = new Object(); +var hiddingSeats = false; // This is the pose we would like to end up var pose = [ @@ -116,6 +117,7 @@ var goToSeatAnimation = function(deltaTime) { } else { Script.update.disconnect(goToSeatAnimation); sitDown(); + showIndicators(false); } } @@ -277,6 +279,10 @@ function update(deltaTime){ addIndicators(model); } } + + if (hiddingSeats && passedTime >= animationLenght) { + showIndicators(true); + } } } @@ -300,6 +306,16 @@ function removeIndicators(modelID) { delete models[modelID.id]; } +function showIndicators(doShow) { + for (model in models) { + var modelID = models[model]; + for (var i = 0; i < modelID.properties.sittingPoints.length; ++i) { + modelID.properties.sittingPoints[i].indicator.show(doShow); + } + } + hiddingSeats = !doShow; +} + function raySphereIntersection(origin, direction, center, radius) { var A = origin; var B = Vec3.normalize(direction); From 8edc4bf9d177abc147a976389c14106c5b4b0ab9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 27 Jun 2014 10:38:39 -0700 Subject: [PATCH 81/88] add HTTPS request debugged to domain-server --- domain-server/src/DomainServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index fcfe1ff582..7a2d5f4f99 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1169,6 +1169,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url) { const QString URI_OAUTH = "/oauth"; + qDebug() << "HTTPS request received at" << url.toString(); if (url.path() == URI_OAUTH) { QUrlQuery codeURLQuery(url); From 5bea267cd25dd4b1fe954ef8c8f4bb34551d9abf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 27 Jun 2014 10:54:57 -0700 Subject: [PATCH 82/88] make sitting points semi transparent --- examples/sit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sit.js b/examples/sit.js index 57828afc52..056a65fbf1 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -164,7 +164,7 @@ function SeatIndicator(modelProperties, seatIndex) { size: this.scale, solid: true, color: { red: 0, green: 0, blue: 255 }, - alpha: 1, + alpha: 0.3, visible: true }); From 21b839a8b5d3301a7b4354916f0ecad92eab5e1c Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Fri, 27 Jun 2014 11:08:24 -0700 Subject: [PATCH 83/88] Updating concertCamera script --- examples/concertCamera.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/concertCamera.js b/examples/concertCamera.js index 7280958bc6..03908d0b57 100644 --- a/examples/concertCamera.js +++ b/examples/concertCamera.js @@ -16,8 +16,8 @@ var avatarPosition; var cameraNumber = 0; var freeCamera = false; -var cameraLocations = [ {x: 7972.2, y: 241.6, z: 7304.1}, {x: 7973.0, y: 241.6, z: 7304.1}, {x: 7975.5, y: 241.6, z: 7304.1}, {x: 7972.3, y: 241.6, z: 7303.3}, {x: 7971.4, y: 241.6, z: 7304.3}, {x: 7973.5, y: 240.6, z: 7302.5} ]; -var cameraLookAts = [ {x: 7971.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241.6, z: 7304.1}, {x: 7972.1, y: 241., z: 7304.1} ]; +var cameraLocations = [ {x: 7971.9, y: 241.3, z: 7304.1}, {x: 7973.0, y: 241.3, z: 7304.1}, {x: 7975.5, y: 241.3, z: 7304.1}, {x: 7972.3, y: 241.3, z: 7303.3}, {x: 7971.0, y: 241.3, z: 7304.3}, {x: 7973.5, y: 240.7, z: 7302.5} ]; +var cameraLookAts = [ {x: 7971.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7972.1, y: 241.3, z: 7304.1}, {x: 7971.3, y: 241.3, z: 7304.2} ]; function saveCameraState() { oldMode = Camera.getMode(); @@ -56,6 +56,11 @@ function keyPressEvent(event) { Camera.setPosition(cameraLocations[choice - 1]); Camera.keepLookingAt(cameraLookAts[choice - 1]); } + if (event.text == "ESC") { + cameraNumber = 0; + freeCamera = false; + restoreCameraState(); + } if (event.text == "0") { // Show camera location in log var cameraLocation = Camera.getPosition(); From 657bf6b3d5f8d22c234adcf2c3cfe777a8bce39b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 27 Jun 2014 11:41:35 -0700 Subject: [PATCH 84/88] repairs so OAuth flow doesn't get stuck after an error --- interface/src/ui/OAuthWebViewHandler.cpp | 11 +++++++++++ interface/src/ui/OAuthWebViewHandler.h | 1 + 2 files changed, 12 insertions(+) diff --git a/interface/src/ui/OAuthWebViewHandler.cpp b/interface/src/ui/OAuthWebViewHandler.cpp index 5b4431bd0f..8ec415584d 100644 --- a/interface/src/ui/OAuthWebViewHandler.cpp +++ b/interface/src/ui/OAuthWebViewHandler.cpp @@ -109,6 +109,8 @@ void OAuthWebViewHandler::displayWebviewForAuthorizationURL(const QUrl& authoriz connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::sslErrors, this, &OAuthWebViewHandler::handleSSLErrors); + connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::finished, + this, &OAuthWebViewHandler::handleReplyFinished); connect(_activeWebView.data(), &QWebView::loadFinished, this, &OAuthWebViewHandler::handleLoadFinished); // connect to the destroyed signal so after the web view closes we can start a timer @@ -132,6 +134,14 @@ void OAuthWebViewHandler::handleLoadFinished(bool success) { NodeList::getInstance()->setSessionUUID(QUuid(authQuery.queryItemValue(AUTH_STATE_QUERY_KEY))); _activeWebView->close(); + _activeWebView = NULL; + } +} + +void OAuthWebViewHandler::handleReplyFinished(QNetworkReply* reply) { + if (_activeWebView && reply->error() != QNetworkReply::NoError) { + qDebug() << "Error loading" << reply->url() << "-" << reply->errorString(); + _activeWebView->close(); } } @@ -148,6 +158,7 @@ void OAuthWebViewHandler::handleURLChanged(const QUrl& url) { _activeWebView->show(); } else if (url.toString() == DEFAULT_NODE_AUTH_URL.toString() + "/login") { // this is a login request - we're going to close the webview and signal the AccountManager that we need a login + qDebug() << "data-server replied with login request. Signalling that login is required to proceed with OAuth."; _activeWebView->close(); AccountManager::getInstance().checkAndSignalForAccessToken(); } diff --git a/interface/src/ui/OAuthWebViewHandler.h b/interface/src/ui/OAuthWebViewHandler.h index 8f0c01c90d..1a95f17dfd 100644 --- a/interface/src/ui/OAuthWebViewHandler.h +++ b/interface/src/ui/OAuthWebViewHandler.h @@ -31,6 +31,7 @@ public slots: private slots: void handleSSLErrors(QNetworkReply* networkReply, const QList& errorList); void handleLoadFinished(bool success); + void handleReplyFinished(QNetworkReply* reply); void handleWebViewDestroyed(QObject* destroyedObject); void handleURLChanged(const QUrl& url); private: From 1bc2f214a563d16fca20ac2b903514ebb471bb64 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 27 Jun 2014 22:18:38 +0200 Subject: [PATCH 85/88] Compiler warning fixes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes all warnings that I got while compiling with g++ 4.7.2: In file included from interface/src/Application.h:53:0, from interface/src/Menu.cpp:36: interface/src/Menu.h: In constructor ‘Menu::Menu()’: interface/src/Menu.h:292:13: warning: ‘Menu::_scriptsLocation’ will be initialized after [-Wreorder] interface/src/Menu.h:289:27: warning: ‘QPointer Menu::_loginDialog’ [-Wreorder] interface/src/Menu.cpp:82:1: warning: when initialized here [-Wreorder] libraries/audio/src/AudioRingBuffer.cpp: In member function ‘qint64 AudioRingBuffer::writeData(const char*, qint64)’: libraries/audio/src/AudioRingBuffer.cpp:126:75: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] libraries/audio/src/PositionalAudioRingBuffer.cpp: In member function ‘bool PositionalAudioRingBuffer::shouldBeAddedToMix()’: libraries/audio/src/PositionalAudioRingBuffer.cpp:212:37: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] interface/ui/preferencesDialog.ui: Warning: The name 'horizontalLayout_11' (QHBoxLayout) is already in use, defaulting to 'horizontalLayout_111'. interface/ui/preferencesDialog.ui: Warning: The name 'horizontalSpacer_11' (QSpacerItem) is already in use, defaulting to 'horizontalSpacer_111'. interface/src/avatar/Avatar.cpp: In member function ‘void Avatar::initializeHair()’: interface/src/avatar/Avatar.cpp:587:21: warning: name lookup of ‘link’ changed [enabled by default] interface/src/avatar/Avatar.cpp:574:18: warning: matches this ‘link’ under ISO standard rules [enabled by default] interface/src/avatar/Avatar.cpp:577:22: warning: matches this ‘link’ under old rules [enabled by default] interface/src/ui/ApplicationOverlay.cpp: In member function ‘void ApplicationOverlay::renderControllerPointers()’: interface/src/ui/ApplicationOverlay.cpp:379:59: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] In file included from interface/src/ui/RunningScriptsWidget.cpp:14:0: interface/src/ui/RunningScriptsWidget.h: In constructor ‘RunningScriptsWidget::RunningScriptsWidget(QWidget*)’: interface/src/ui/RunningScriptsWidget.h:61:18: warning: ‘RunningScriptsWidget::_scriptsModel’ will be initialized after [-Wreorder] interface/src/ui/RunningScriptsWidget.h:60:27: warning: ‘QSortFilterProxyModel RunningScriptsWidget::_proxyModel’ [-Wreorder] interface/src/ui/RunningScriptsWidget.cpp:27:1: warning: when initialized here [-Wreorder] --- interface/src/Menu.cpp | 4 ++-- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/RunningScriptsWidget.cpp | 4 ++-- interface/ui/preferencesDialog.ui | 4 ++-- libraries/audio/src/AudioRingBuffer.cpp | 2 +- libraries/audio/src/PositionalAudioRingBuffer.cpp | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6269d4a8c0..9357ba2004 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -108,9 +108,9 @@ Menu::Menu() : _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), _preferencesDialog(NULL), - _scriptsLocation(), _loginDialog(NULL), - _snapshotsLocation() + _snapshotsLocation(), + _scriptsLocation() { Application *appInstance = Application::getInstance(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5a294bb2a5..9b136980f4 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -574,8 +574,8 @@ void Avatar::initializeHair() { for (int link = 0; link < HAIR_LINKS; link++) { int vertexIndex = strand * HAIR_LINKS + link; // Clear constraints - for (int link = 0; link < HAIR_MAX_CONSTRAINTS; link++) { - _hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + link] = -1; + for (int link2 = 0; link2 < HAIR_MAX_CONSTRAINTS; link2++) { + _hairConstraints[vertexIndex * HAIR_MAX_CONSTRAINTS + link2] = -1; } if (vertexIndex % HAIR_LINKS == 0) { // start of strand diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 342a145953..77e8986297 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -376,7 +376,7 @@ void ApplicationOverlay::renderControllerPointers() { //then disable it. const int MAX_BUTTON_PRESS_TIME = 250 * MSECS_TO_USECS; - if (usecTimestampNow() - pressedTime[index] < MAX_BUTTON_PRESS_TIME) { + if (usecTimestampNow() < pressedTime[index] + MAX_BUTTON_PRESS_TIME) { _magActive[index] = !stateWhenPressed[index]; } } diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 136d0a2d38..8a7ebcbfd4 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -28,8 +28,8 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) : FramelessDialog(parent, 0, POSITION_LEFT), ui(new Ui::RunningScriptsWidget), _signalMapper(this), - _scriptsModel(this), - _proxyModel(this) { + _proxyModel(this), + _scriptsModel(this) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, false); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index a75c2bdec2..95678bf6f8 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -902,7 +902,7 @@ padding: 10px;margin-top:10px - + 0 @@ -937,7 +937,7 @@ padding: 10px;margin-top:10px - + Arial diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index ee4027841b..a2d3715462 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -121,7 +121,7 @@ qint64 AudioRingBuffer::writeData(const char* data, qint64 maxSize) { // make sure we have enough bytes left for this to be the right amount of audio // otherwise we should not copy that data, and leave the buffer pointers where they are - int samplesToCopy = std::min((quint64)(maxSize / sizeof(int16_t)), (quint64)_sampleCapacity); + quint64 samplesToCopy = std::min((quint64)(maxSize / sizeof(int16_t)), (quint64)_sampleCapacity); if (_hasStarted && samplesToCopy > _sampleCapacity - samplesAvailable()) { // this read will cross the next output, so call us starved and reset the buffer diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 23e258fe87..acd688bdc0 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -209,7 +209,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { } return false; - } else if (samplesAvailable() < samplesPerFrame) { + } else if (samplesAvailable() < (unsigned int)samplesPerFrame) { // if the buffer doesn't have a full frame of samples to take for mixing, it is starved _isStarved = true; From f33728b6152076f8ac90cc338672ceb639464fa5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 30 Jun 2014 09:13:42 -0700 Subject: [PATCH 86/88] guarantee that ragdoll is clear before initialized --- interface/src/avatar/SkeletonModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e9328d32ca..763aa27f00 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -505,8 +505,7 @@ void SkeletonModel::renderRagdoll() { // virtual void SkeletonModel::initRagdollPoints() { - assert(_ragdollPoints.size() == 0); - assert(_ragdollConstraints.size() == 0); + clearRagdollConstraintsAndPoints(); // one point for each joint int numJoints = _jointStates.size(); From 57c17eb972f92eaf3ff110426c7f7d6a5230b15c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 30 Jun 2014 09:18:31 -0700 Subject: [PATCH 87/88] remove unecessary clearRagdollConstraintsAndPoints() --- interface/src/avatar/SkeletonModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 763aa27f00..3b09a1a2ba 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -39,7 +39,6 @@ void SkeletonModel::setJointStates(QVector states) { } clearShapes(); - clearRagdollConstraintsAndPoints(); if (_enableShapes) { buildShapes(); } From 146cd2b59d7cee3e7c25cf5388ef0afe8622b0e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Jun 2014 12:23:33 -0700 Subject: [PATCH 88/88] update BUILD.md to remove zlib requirement --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index b8bc1cd14c..674f0d24cc 100644 --- a/BUILD.md +++ b/BUILD.md @@ -63,7 +63,7 @@ If `libgnutls28-dev` 3.2.12 or higher is available via your package manager, it [Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of all hifi dependencies very simple. brew tap highfidelity/homebrew-formulas - brew install cmake glm zlib gnutls + brew install cmake glm gnutls brew install highfidelity/formulas/qt5 brew link qt5 --force brew install highfidelity/formulas/qxmpp