From 52df77b4b560005aece460c907058fc055ac054b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 16:25:35 -0700 Subject: [PATCH 1/5] Final work on models metadata support --- interface/src/ui/ModelsBrowser.cpp | 114 +++++++++++++++++------- interface/src/ui/ModelsBrowser.h | 14 ++- libraries/shared/src/FileDownloader.cpp | 45 ---------- libraries/shared/src/FileDownloader.h | 41 --------- 4 files changed, 87 insertions(+), 127 deletions(-) delete mode 100644 libraries/shared/src/FileDownloader.cpp delete mode 100644 libraries/shared/src/FileDownloader.h diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 15f1e9111e..e128d047ef 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -8,11 +8,10 @@ #include #include -#include #include #include #include -#include +#include #include #include @@ -33,27 +32,39 @@ static const QString KEY_NAME = "Key"; static const QString LOADING_MSG = "Loading..."; static const QString ERROR_MSG = "Error loading files"; +static const QString DO_NOT_MODIFY_TAG = "DoNotModify"; + enum ModelMetaData { NAME, - CREATOR, - UPLOAD_DATE, TYPE, GENDER, + CREATOR, + UPLOAD_DATE, MODEL_METADATA_COUNT }; static const QString propertiesNames[MODEL_METADATA_COUNT] = { "Name", - "Creator", - "Upload Date", "Type", - "Gender" + "Gender", + "Creator", + "Last Modified" +}; +static const QString propertiesIds[MODEL_METADATA_COUNT] = { + DO_NOT_MODIFY_TAG, + "Type", + "Gender", + "x-amz-request-id", + "Last-Modified" }; ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : QWidget(parent), _handler(new ModelHandler(modelsType)) { + connect(_handler, SIGNAL(doneDownloading()), SLOT(resizeView())); + connect(_handler, SIGNAL(updated()), SLOT(resizeView())); + // Connect handler _handler->connect(this, SIGNAL(startDownloading()), SLOT(download())); _handler->connect(_handler, SIGNAL(doneDownloading()), SLOT(update())); @@ -106,6 +117,12 @@ void ModelsBrowser::applyFilter(const QString &filter) { _handler->unlockModel(); } +void ModelsBrowser::resizeView() { + for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { + _view.resizeColumnToContents(i); + } +} + void ModelsBrowser::browse() { QDialog dialog; dialog.setWindowTitle("Browse models"); @@ -145,8 +162,6 @@ ModelHandler::ModelHandler(ModelType modelsType, QWidget* parent) : _initiateExit(false), _type(modelsType) { - connect(&_downloader, SIGNAL(done(QNetworkReply::NetworkError)), SLOT(downloadFinished())); - // set headers data QStringList headerData; for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { @@ -156,9 +171,6 @@ ModelHandler::ModelHandler(ModelType modelsType, QWidget* parent) : } void ModelHandler::download() { - // Query models list - queryNewFiles(); - _lock.lockForWrite(); if (_initiateExit) { _lock.unlock(); @@ -169,10 +181,25 @@ void ModelHandler::download() { loadingItem->setEnabled(false); _model.appendRow(loadingItem); _lock.unlock(); + + // Query models list + queryNewFiles(); } void ModelHandler::update() { - // Will be implemented in my next PR + _lock.lockForWrite(); + if (_initiateExit) { + _lock.unlock(); + return; + } + for (int i = 0; i < _model.rowCount(); ++i) { + QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); + QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + QNetworkRequest request(url); + accessManager->head(request); + connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + } + _lock.unlock(); } void ModelHandler::exit() { @@ -180,7 +207,6 @@ void ModelHandler::exit() { _initiateExit = true; // Disconnect everything - _downloader.disconnect(); disconnect(); thread()->disconnect(); @@ -191,12 +217,16 @@ void ModelHandler::exit() { _lock.unlock(); } -void ModelHandler::downloadFinished() { - if (_downloader.getData().startsWith("readAll(); + + if (!data.isEmpty()) { + parseXML(data); } else { - qDebug() << _downloader.getData(); + parseHeaders(reply); } + reply->deleteLater(); + sender()->deleteLater(); } void ModelHandler::queryNewFiles(QString marker) { @@ -219,7 +249,11 @@ void ModelHandler::queryNewFiles(QString marker) { // Download url.setQuery(query); - _downloader.download(url); + QNetworkAccessManager* accessManager = new QNetworkAccessManager(this); + QNetworkRequest request(url); + accessManager->get(request); + connect(accessManager, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); + } bool ModelHandler::parseXML(QByteArray xmlFile) { @@ -266,18 +300,9 @@ bool ModelHandler::parseXML(QByteArray xmlFile) { QList model; model << new QStandardItem(QFileInfo(xml.text().toString()).baseName()); model.first()->setData(PUBLIC_URL + "/" + xml.text().toString(), Qt::UserRole); - - // Rand properties for now (Will be taken out in the next PR) - static QString creator[] = {"Ryan", "Philip", "Andzrej"}; - static QString type[] = {"human", "beast", "pet", "elfe"}; - static QString gender[] = {"male", "female", "none"}; - model << new QStandardItem(creator[randIntInRange(0, 2)]); - model << new QStandardItem(QDate(randIntInRange(2013, 2014), - randIntInRange(1, 12), - randIntInRange(1, 30)).toString()); - model << new QStandardItem(type[randIntInRange(0, 3)]); - model << new QStandardItem(gender[randIntInRange(0, 2)]); - //////////////////////////////////////////////////////////// + for (int i = 1; i < MODEL_METADATA_COUNT; ++i) { + model << new QStandardItem(); + } _model.appendRow(model); } @@ -312,9 +337,32 @@ bool ModelHandler::parseXML(QByteArray xmlFile) { _lock.unlock(); if (!truncated) { - qDebug() << "Emitting..."; emit doneDownloading(); } return true; -} \ No newline at end of file +} + +bool ModelHandler::parseHeaders(QNetworkReply* reply) { + _lock.lockForWrite(); + + QList items = _model.findItems(QFileInfo(reply->url().toString()).baseName()); + if (items.isEmpty() || items.first()->text() == DO_NOT_MODIFY_TAG) { + return false; + } + + for (int i = 0; i < MODEL_METADATA_COUNT; ++i) { + for (int k = 1; k < reply->rawHeaderPairs().count(); ++k) { + QString key = reply->rawHeaderPairs().at(k).first.data(); + QString item = reply->rawHeaderPairs().at(k).second.data(); + if (key == propertiesIds[i]) { + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); + } + } + } + _lock.unlock(); + + emit updated(); + return true; +} + diff --git a/interface/src/ui/ModelsBrowser.h b/interface/src/ui/ModelsBrowser.h index 9bc239ba18..30320de1c1 100644 --- a/interface/src/ui/ModelsBrowser.h +++ b/interface/src/ui/ModelsBrowser.h @@ -9,13 +9,10 @@ #ifndef __hifi__ModelsBrowser__ #define __hifi__ModelsBrowser__ -#include -#include -#include -#include #include +#include +#include -#include "FileDownloader.h" enum ModelType { Head, @@ -33,7 +30,7 @@ public: signals: void doneDownloading(); - void doneUpdating(); + void updated(); public slots: void download(); @@ -41,17 +38,17 @@ public slots: void exit(); private slots: - void downloadFinished(); + void downloadFinished(QNetworkReply* reply); private: bool _initiateExit; ModelType _type; - FileDownloader _downloader; QReadWriteLock _lock; QStandardItemModel _model; void queryNewFiles(QString marker = QString()); bool parseXML(QByteArray xmlFile); + bool parseHeaders(QNetworkReply* reply); }; @@ -71,6 +68,7 @@ public slots: private slots: void applyFilter(const QString& filter); + void resizeView(); private: ModelHandler* _handler; diff --git a/libraries/shared/src/FileDownloader.cpp b/libraries/shared/src/FileDownloader.cpp deleted file mode 100644 index 8b13b129fe..0000000000 --- a/libraries/shared/src/FileDownloader.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// FileDownloader.cpp -// hifi -// -// Created by Clement Brisset on 3/14/14. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// - -#include -#include -#include -#include - -#include "FileDownloader.h" - -FileDownloader::FileDownloader(QObject* parent) : QObject(parent) { - connect(&_networkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(processReply(QNetworkReply*))); -} - -void FileDownloader::download(const QUrl& dataURL, QNetworkAccessManager::Operation operation) { - QNetworkRequest request(dataURL); - - _downloadedData.clear(); - switch (operation) { - case QNetworkAccessManager::GetOperation: - _networkAccessManager.get(request); - break; - case QNetworkAccessManager::HeadOperation: - _networkAccessManager.head(request); - break; - default: - emit done(QNetworkReply::ProtocolInvalidOperationError); - break; - } -} - -void FileDownloader::processReply(QNetworkReply *reply) { - if (reply->error() == QNetworkReply::NoError) { - _downloadedData = reply->readAll(); - } - - reply->deleteLater(); - emit done(reply->error()); -} \ No newline at end of file diff --git a/libraries/shared/src/FileDownloader.h b/libraries/shared/src/FileDownloader.h deleted file mode 100644 index ad1351a575..0000000000 --- a/libraries/shared/src/FileDownloader.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// FileDownloader.h -// hifi -// -// Created by Clement Brisset on 3/14/14. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// - -#ifndef __hifi__FileDownloader__ -#define __hifi__FileDownloader__ - -#include -#include -#include -#include - -class FileDownloader : public QObject { - Q_OBJECT - -public: - FileDownloader(QObject* parent = NULL); - QByteArray getData() const { return _downloadedData; } - - -signals: - void done(QNetworkReply::NetworkError error); - -public slots: - void download(const QUrl& dataURL, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation); - -private slots: - void processReply(QNetworkReply* reply); - -private: - QNetworkAccessManager _networkAccessManager; - QByteArray _downloadedData; -}; - - -#endif /* defined(__hifi__FileDownloader__) */ From cf20c448a3100ab1ca51bbee858b4f15d7d70d6f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 16:46:03 -0700 Subject: [PATCH 2/5] Few tweaks before PR --- interface/src/ui/ModelsBrowser.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index e128d047ef..276fdd24c1 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -54,7 +54,7 @@ static const QString propertiesIds[MODEL_METADATA_COUNT] = { DO_NOT_MODIFY_TAG, "Type", "Gender", - "x-amz-request-id", + "Creator", "Last-Modified" }; @@ -97,7 +97,7 @@ void ModelsBrowser::applyFilter(const QString &filter) { for (int k = 0; k < filters.count(); ++k) { match = false; for (int j = 0; j < MODEL_METADATA_COUNT; ++j) { - if (model->item(i, j)->text().contains(filters.at(k))) { + if (model->item(i, j)->text().contains(filters.at(k), Qt::CaseInsensitive)) { match = true; break; } @@ -359,6 +359,22 @@ bool ModelHandler::parseHeaders(QNetworkReply* reply) { _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); } } + + // Rand properties for now (Will be taken out when we have real metadata on the server) + if (_model.item(_model.indexFromItem(items.first()).row(), i)->text().isEmpty()) { + if (i == CREATOR) { + static QString creator[] = {"Ryan", "Philip", "Andzrej", "Phteven", "Brad"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(creator[randIntInRange(0, 4)]); + } else if (i == TYPE) { + static QString type[] = {"human", "beast", "pet", "elfe"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(type[randIntInRange(0, 3)]); + } else if (i == GENDER) { + static QString gender[] = {"male", "female", "none"}; + _model.item(_model.indexFromItem(items.first()).row(), i)->setText(gender[randIntInRange(0, 2)]); + } + } + //////////////////////////////////////////////////////////// + } _lock.unlock(); From c2f0545d96c3af7fc1c1f047a3b42d66d0a58826 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Apr 2014 17:12:11 -0700 Subject: [PATCH 3/5] Setup for actual metadata --- interface/src/ui/ModelsBrowser.cpp | 37 ++++++++++-------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 276fdd24c1..616aba3881 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -36,26 +36,29 @@ static const QString DO_NOT_MODIFY_TAG = "DoNotModify"; enum ModelMetaData { NAME, - TYPE, - GENDER, CREATOR, - UPLOAD_DATE, + DATE_ADDED, + TOTAL_SIZE, + POLY_NUM, + TAGS, MODEL_METADATA_COUNT }; static const QString propertiesNames[MODEL_METADATA_COUNT] = { "Name", - "Type", - "Gender", "Creator", - "Last Modified" + "Date Added", + "Total Size", + "Poly#", + "Tags" }; static const QString propertiesIds[MODEL_METADATA_COUNT] = { DO_NOT_MODIFY_TAG, - "Type", - "Gender", "Creator", - "Last-Modified" + "Date-Added", + "Total-Size", + "Poly-Num", + "Tags" }; ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) : @@ -359,22 +362,6 @@ bool ModelHandler::parseHeaders(QNetworkReply* reply) { _model.item(_model.indexFromItem(items.first()).row(), i)->setText(item); } } - - // Rand properties for now (Will be taken out when we have real metadata on the server) - if (_model.item(_model.indexFromItem(items.first()).row(), i)->text().isEmpty()) { - if (i == CREATOR) { - static QString creator[] = {"Ryan", "Philip", "Andzrej", "Phteven", "Brad"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(creator[randIntInRange(0, 4)]); - } else if (i == TYPE) { - static QString type[] = {"human", "beast", "pet", "elfe"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(type[randIntInRange(0, 3)]); - } else if (i == GENDER) { - static QString gender[] = {"male", "female", "none"}; - _model.item(_model.indexFromItem(items.first()).row(), i)->setText(gender[randIntInRange(0, 2)]); - } - } - //////////////////////////////////////////////////////////// - } _lock.unlock(); From 3a125db1f8241999e0457141a1fe14c728eb688d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 4 Apr 2014 14:31:30 -0700 Subject: [PATCH 4/5] Increase the rate at which we increase detail and put a limit on the LOD multiplier so that it never takes more than about five seconds to return to default detail. Also, since there seems to be a weird issue where OS X throttles the frame rate to 30 fps (independent of our own throttling), use that as the lower adjustment range. --- interface/src/Menu.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5530c57281..5deb9474cf 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1260,20 +1260,22 @@ void Menu::autoAdjustLOD(float currentFPS) { quint64 now = usecTimestampNow(); + const float ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f; const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000; - if (_fastFPSAverage.getAverage() < ADJUST_LOD_DOWN_FPS) { + if (_fastFPSAverage.getAverage() < ADJUST_AVATAR_LOD_DOWN_FPS) { if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) { // attempt to lower the detail in proportion to the fps difference - float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f; + float targetFps = (ADJUST_AVATAR_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f; float averageFps = _fastFPSAverage.getAverage(); const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; - _avatarLODDistanceMultiplier *= (averageFps < EPSILON) ? MAXIMUM_MULTIPLIER_SCALE : - qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps); + const float MAXIMUM_DISTANCE_MULTIPLIER = 15.0f; + _avatarLODDistanceMultiplier = qMin(MAXIMUM_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * + (averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); _lastAvatarDetailDrop = now; } } else if (_fastFPSAverage.getAverage() > ADJUST_LOD_UP_FPS) { // let the detail level creep slowly upwards - const float DISTANCE_DECREASE_RATE = 0.02f; + const float DISTANCE_DECREASE_RATE = 0.05f; const float MINIMUM_DISTANCE_MULTIPLIER = 0.1f; _avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); From 01c42c741c57ecd01c51238ab3996228a45d2e0c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 4 Apr 2014 14:46:54 -0700 Subject: [PATCH 5/5] fix #2567 thrust + oculus doesn't change body rot --- interface/src/Application.cpp | 2 +- interface/src/avatar/Head.cpp | 4 ++++ interface/src/avatar/MyAvatar.cpp | 28 +--------------------------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 83eab37318..d54cceb245 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -510,7 +510,7 @@ void Application::paintGL() { _myCamera.setDistance(0.0f); _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); - _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation()); + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ffa0975ccb..8a25c14574 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -14,6 +14,7 @@ #include "Head.h" #include "Menu.h" #include "Util.h" +#include "devices/OculusManager.h" using namespace std; @@ -198,6 +199,9 @@ glm::quat Head::getFinalOrientation() const { } glm::quat Head::getCameraOrientation () const { + if (OculusManager::isConnected()) { + return getOrientation(); + } Avatar* owningAvatar = static_cast(_owningAvatar); return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.f, 0.0f))); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9dcfaa09ba..1ff93794c5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -169,9 +169,6 @@ void MyAvatar::simulate(float deltaTime) { // Collect thrust forces from keyboard and devices updateThrust(deltaTime); - // copy velocity so we can use it later for acceleration - glm::vec3 oldVelocity = getVelocity(); - // calculate speed _speed = glm::length(_velocity); @@ -231,29 +228,6 @@ void MyAvatar::simulate(float deltaTime) { // update the euler angles setOrientation(orientation); - // Compute instantaneous acceleration - float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; - const float OCULUS_ACCELERATION_PULL_THRESHOLD = 1.0f; - const int OCULUS_YAW_OFFSET_THRESHOLD = 10; - - if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() && - fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD && - fabs(getHead()->getBaseYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { - - // if we're wearing the oculus - // and this acceleration is above the pull threshold - // and the head yaw if off the body by more than OCULUS_YAW_OFFSET_THRESHOLD - - // match the body yaw to the oculus yaw - _bodyYaw = getAbsoluteHeadYaw(); - - // set the head yaw to zero for this draw - getHead()->setBaseYaw(0); - - // correct the oculus yaw offset - OculusManager::updateYawOffset(); - } - const float WALKING_SPEED_THRESHOLD = 0.2f; // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > WALKING_SPEED_THRESHOLD) { @@ -308,7 +282,7 @@ void MyAvatar::simulate(float deltaTime) { head->simulate(deltaTime, true); // Zero thrust out now that we've added it to velocity in this frame - _thrust = glm::vec3(0, 0, 0); + _thrust = glm::vec3(0.f); // now that we're done stepping the avatar forward in time, compute new collisions if (_collisionFlags != 0) {