From 855f6fcf598c1eae6a866bff69fd78f9d1b4923d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:46:41 -0700 Subject: [PATCH 01/25] Moved Avatar upload to file Menu --- interface/src/Menu.cpp | 6 ++++-- interface/src/Menu.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f0d4d8c133..26747aad86 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -129,7 +129,10 @@ Menu::Menu() : this, SLOT(goTo())); - + addDisabledActionAndSeparator(fileMenu, "Upload/Browse"); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploaderAvatarHead, 0, Application::getInstance(), SLOT(uploadFST())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::UploaderAvatarSkeleton, 0, Application::getInstance(), SLOT(uploadFST())); + addDisabledActionAndSeparator(fileMenu, "Settings"); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings())); @@ -161,7 +164,6 @@ Menu::Menu() : QMenu* toolsMenu = addMenu("Tools"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); - addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST())); _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 380fe2d3b7..1e5ada9e84 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -242,7 +242,6 @@ namespace MenuOption { const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; - const QString FstUploader = "Upload .fst file"; const QString Fullscreen = "Fullscreen"; const QString FullscreenMirror = "Fullscreen Mirror"; const QString GlowMode = "Cycle Glow Mode"; @@ -291,6 +290,8 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString UploaderAvatarHead = "Upload Avatar Head"; + const QString UploaderAvatarSkeleton = "Upload Avatar Skeleton"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; From b9ee60ba41107635d4cdc370b0d62e7d3c7fbd35 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:47:47 -0700 Subject: [PATCH 02/25] FstReader not a member anymore --- interface/src/Application.cpp | 6 +++++- interface/src/Application.h | 3 --- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13e3d36fad..8e64ba4d04 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include "Application.h" #include "ClipboardScriptingInterface.h" @@ -3432,7 +3433,10 @@ void Application::reloadAllScripts() { } void Application::uploadFST() { - _fstReader.zip(); + FstReader reader; + if(reader.zip()) { + reader.send(); + } } void Application::removeScriptName(const QString& fileNameString) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 70b7347654..5b1f2e8c03 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -28,7 +28,6 @@ #include #include #include -#include #include "Audio.h" #include "BandwidthMeter.h" @@ -472,8 +471,6 @@ private: TouchEvent _lastTouchEvent; Overlays _overlays; - - FstReader _fstReader; }; #endif /* defined(__interface__Application__) */ From 3aa534d47c3a99d40626fa425b25708f5336ac56 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 12 Mar 2014 11:48:41 -0700 Subject: [PATCH 03/25] Added the send method --- libraries/shared/src/FstReader.cpp | 80 +++++++++++++++--------------- libraries/shared/src/FstReader.h | 17 +++++-- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index fa2aebb2fe..d94f036af0 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -17,7 +17,6 @@ #include "FstReader.h" FstReader::FstReader() { - } @@ -37,8 +36,7 @@ bool FstReader::zip() { qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); - QTemporaryDir tempRootDir(_zipDir.path() + "/" + QFileInfo(fst).baseName()); - QDir rootDir(tempRootDir.path()); + QDir rootDir(_zipDir.path()); // Let's read through the FST file QTextStream stream(&fst); @@ -50,56 +48,66 @@ bool FstReader::zip() { } // according to what is read, we modify the command - if (line.first() == filenameField) { - QFileInfo fbx(QFileInfo(fst).path() + "/" + line.at(1)); + if (line.first() == nameField) { + _modelName = line[1]; + } else if (line.first() == filenameField) { + QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " doesn't exist."; return false; - } else if (fbx.size() > MAX_FBX_SIZE) { // Check size - qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " too big, over " << MAX_FBX_SIZE << " MB."; - return false; } else { // Compress and copy - compressFile(fbx.filePath(), - rootDir.path() + "/" + line.at(1)); + _fbxFile = rootDir.path() + "/" + line[1]; + _totalSize += fbx.size(); + compressFile(fbx.filePath(), _fbxFile); } } else if (line.first() == texdirField) { // Check existence - QFileInfo texdir(QFileInfo(fst).path() + "/" + line.at(1)); + QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { qDebug() << "[ERROR] Texture directory " << texdir.absolutePath() << " doesn't exist."; return false; } - QDir newTexdir(rootDir.canonicalPath() + "/" + line.at(1)); - if (!newTexdir.exists() && !rootDir.mkpath(line.at(1))) { // Create texdir - qDebug() << "[ERROR] Couldn't create " << line.at(1) << "."; - return false; - } - if (!addTextures(texdir, newTexdir)) { // Recursive compress and copy + if (!addTextures(texdir)) { // Recursive compress and copy return false; } } else if (line.first() == lodField) { - QFileInfo lod(QFileInfo(fst).path() + "/" + line.at(1)); + QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " doesn't exist."; - return false; - } else if (lod.size() > MAX_FBX_SIZE) { // Check size - qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " too big, over " << MAX_FBX_SIZE << " MB.";\ - return false; + //return false; } else { // Compress and copy - compressFile(lod.filePath(), rootDir.path() + "/" + line.at(1)); + _lodFiles.push_back(rootDir.path() + "/" + line[1]); + _totalSize += lod.size(); + compressFile(lod.filePath(), _lodFiles.back()); } } } // Compress and copy the fst - compressFile(fst.fileName(), - rootDir.path() + "/" + QFileInfo(fst).fileName()); - - tempRootDir.setAutoRemove(false); + _fstFile = rootDir.path() + "/" + QFileInfo(fst).fileName(); + _totalSize += QFileInfo(fst).size(); + compressFile(fst.fileName(), _fstFile); return true; } -bool FstReader::addTextures(QFileInfo& texdir, QDir newTexdir) { +bool FstReader::send() { + QString command = QString("curl -F \"model_name=%1\"").arg(_modelName); + + command += QString(" -F \"fst=@%1\" -F \"fbx=@%2\"").arg(_fstFile, _fbxFile); + for (int i = 0; i < _lodFiles.size(); ++i) { + command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_lodFiles[i]); + } + for (int i = 0; i < _textureFiles.size(); ++i) { + command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_textureFiles[i]); + } + command += " http://localhost:3000/api/v1/models/?access_token\\=017894b7312316a2b5025613fcc58c13bc701da9b797cca34b60aae9d1c53acb --trace-ascii /dev/stdout"; + + qDebug() << "[DEBUG] " << command; + + return true; +} + +bool FstReader::addTextures(QFileInfo& texdir) { QStringList filter; filter << "*.png" << "*.tiff" << "*.jpg" << "*.jpeg"; @@ -110,19 +118,11 @@ bool FstReader::addTextures(QFileInfo& texdir, QDir newTexdir) { QDir::NoSymLinks); foreach (QFileInfo info, list) { if (info.isFile()) { - if (info.size() > MAX_TEXTURE_SIZE) { - qDebug() << "[ERROR] Texture " << info.absoluteFilePath() - << "too big, file over " << MAX_TEXTURE_SIZE << " Bytes."; - return false; - } - compressFile(info.canonicalFilePath(), newTexdir.path() + "/" + info.fileName()); + _textureFiles.push_back(_zipDir.path() + "/" + info.fileName()); + _totalSize += info.size(); + compressFile(info.canonicalFilePath(), _textureFiles.back()); } else if (info.isDir()) { - if (newTexdir.mkdir(info.fileName())) { - qDebug() << "[ERROR] Couldn't create texdir."; - return false; - } - QDir texdirChild(newTexdir.canonicalPath() + "/" + info.fileName()); - if (!addTextures(info, QDir(info.canonicalFilePath()))) { + if (!addTextures(info)) { return false; } } else { diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index 44cd3f95cd..c5816ea415 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -14,23 +14,34 @@ #include #include + +static const QString nameField = "name"; static const QString filenameField = "filename"; static const QString texdirField = "texdir"; static const QString lodField = "lod"; -static const int MAX_FBX_SIZE = 1024 * 1024; // 1 MB -static const int MAX_TEXTURE_SIZE = 1024 * 1024; // 1 MB +static const int MAX_SIZE = 1024 * 1024; // 1 MB class FstReader { public: FstReader(); bool zip(); + bool send(); private: QTemporaryDir _zipDir; - bool addTextures(QFileInfo& texdir, QDir newTexdir); + QString _modelName; + QString _fstFile; + QString _fbxFile; + QStringList _lodFiles; + QStringList _textureFiles; + + int _totalSize; + + + bool addTextures(QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); }; From 9c61f12926719adff0d7305f77461daa52b3faee Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 19:10:26 -0400 Subject: [PATCH 04/25] Support for an idle render time step. The basics of this is, if the application has changed its active state then we only call paintGL every N milliseconds. Currently the default time step is 100 milliseconds. --- interface/src/GLCanvas.cpp | 29 +++++++++++++++++++++++++++-- interface/src/GLCanvas.h | 8 ++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 7bc79e56d8..a098af7fbe 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -12,17 +12,21 @@ #include #include -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)) { +GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { } void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); + connect(Application::getInstance(), &Application::focusChanged, this, &GLCanvas::activeChanged); + connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); } void GLCanvas::paintGL() { - Application::getInstance()->paintGL(); + if (!_throttleRendering) { + Application::getInstance()->paintGL(); + } } void GLCanvas::resizeGL(int width, int height) { @@ -49,6 +53,27 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } +void GLCanvas::activeChanged() +{ + if (!isActiveWindow()) + { + if (!_throttleRendering) + { + _frameTimer.start(_idleRenderInterval); + _throttleRendering = true; + } + } else { + _frameTimer.stop(); + _throttleRendering = false; + } +} + +void GLCanvas::throttleRender() +{ + _frameTimer.start(_idleRenderInterval); + Application::getInstance()->paintGL(); +} + int updateTime = 0; bool GLCanvas::event(QEvent* event) { switch (event->type()) { diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 0f0cb5c7d0..7e4a4d0334 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -10,6 +10,7 @@ #define __hifi__GLCanvas__ #include +#include /// customized canvas that simply forwards requests/events to the singleton application class GLCanvas : public QGLWidget { @@ -17,6 +18,10 @@ public: GLCanvas(); protected: + QTimer _frameTimer; + bool _throttleRendering; + int _idleRenderInterval; + virtual void initializeGL(); virtual void paintGL(); virtual void resizeGL(int width, int height); @@ -34,6 +39,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent* event); + + void activeChanged(); + void throttleRender(); }; #endif /* defined(__hifi__GLCanvas__) */ From e27af75ad2b00b8c6eab3b802a0b4850f9bad49c Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 20:49:58 -0400 Subject: [PATCH 05/25] Use QApplication::applicationState to detect if we're in the background. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit May want to expand upon this at some point; if we’re hidden we most definitely *do not* want to render anything --- interface/src/GLCanvas.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index a098af7fbe..dc76858e1b 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -53,12 +53,9 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } -void GLCanvas::activeChanged() -{ - if (!isActiveWindow()) - { - if (!_throttleRendering) - { +void GLCanvas::activeChanged() { + if (Application::applicationState() != Qt::ApplicationActive) { + if (!_throttleRendering) { _frameTimer.start(_idleRenderInterval); _throttleRendering = true; } From 292f37154bab0feaf189fe3eef169119303b0f59 Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 21:08:55 -0400 Subject: [PATCH 06/25] Use the applicationStateChanged signal. --- interface/src/GLCanvas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index dc76858e1b..52fd91130c 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -19,7 +19,7 @@ void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), &Application::focusChanged, this, &GLCanvas::activeChanged); + connect(Application::getInstance(), &Application::applicationStateChanged, this, &GLCanvas::activeChanged); connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); } From d580f177a3f93cbbc5158c637e396248be5dd8cc Mon Sep 17 00:00:00 2001 From: Geenz Date: Wed, 12 Mar 2014 21:17:54 -0400 Subject: [PATCH 07/25] Refactor if..else into a switch. Also support the hidden and suspended states. --- interface/src/GLCanvas.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 52fd91130c..f2a88fea6d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -54,14 +54,27 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { } void GLCanvas::activeChanged() { - if (Application::applicationState() != Qt::ApplicationActive) { - if (!_throttleRendering) { - _frameTimer.start(_idleRenderInterval); - _throttleRendering = true; - } - } else { - _frameTimer.stop(); - _throttleRendering = false; + switch (Application::applicationState()) { + case Qt::ApplicationActive: + // If we're active, stop the frame timer and the throttle. + _frameTimer.stop(); + _throttleRendering = false; + break; + + case Qt::ApplicationSuspended: + case Qt::ApplicationHidden: + // If we're hidden or are about to suspend, don't render anything. + _throttleRendering = false; + _frameTimer.stop(); + break; + + default: + // Otherwise, throttle. + if (!_throttleRendering) { + _frameTimer.start(_idleRenderInterval); + _throttleRendering = true; + } + break; } } From 2e119fa0fe24152e95472f4928ee187f6c51effc Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 11:41:15 -0400 Subject: [PATCH 08/25] Skip rendering when we're minimized. --- interface/src/GLCanvas.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index f2a88fea6d..bf99608c07 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -11,6 +11,7 @@ #include "GLCanvas.h" #include #include +#include GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { } @@ -24,7 +25,7 @@ void GLCanvas::initializeGL() { } void GLCanvas::paintGL() { - if (!_throttleRendering) { + if (!_throttleRendering && !Application::getInstance()->getWindow()->isMinimized()) { Application::getInstance()->paintGL(); } } @@ -78,10 +79,11 @@ void GLCanvas::activeChanged() { } } -void GLCanvas::throttleRender() -{ +void GLCanvas::throttleRender() { _frameTimer.start(_idleRenderInterval); - Application::getInstance()->paintGL(); + if (!Application::getInstance()->getWindow()->isMinimized()) { + Application::getInstance()->paintGL(); + } } int updateTime = 0; From b2a29cb84f282b6eae3b3f4d6ce81509b43c7dec Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 10:56:19 -0700 Subject: [PATCH 09/25] Fixes for Linux build. --- interface/CMakeLists.txt | 6 +----- interface/interface_en.ts | 8 ++++---- interface/src/Application.cpp | 2 -- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1cb0344f86..f39e7d7e50 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -230,11 +230,7 @@ if (APPLE) RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime ) else (APPLE) - # remove and then copy the resources files beside the executable - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E remove_directory - $/resources - ) + # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/resources" diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 1d962393d7..80433032dc 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8091e58545..96129e0161 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -121,8 +121,6 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt QString& Application::resourcesPath() { #ifdef Q_OS_MAC static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/"; -#elif defined Q_OS_LINUX - static QString staticResourcePath = "resources/"; #else static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/"; #endif From 43feef3ebdd7a871cbd7858f800054d255b37e89 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 12:03:02 -0700 Subject: [PATCH 10/25] Only update the full set of joints when we've received new data from the mixer. Closes #2274. --- interface/src/avatar/Avatar.cpp | 9 ++++++-- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/FaceModel.cpp | 6 +++--- interface/src/avatar/FaceModel.h | 2 +- interface/src/avatar/SkeletonModel.cpp | 4 ++-- interface/src/avatar/SkeletonModel.h | 2 +- interface/src/renderer/Model.cpp | 29 +++++++++++++------------- interface/src/renderer/Model.h | 4 ++-- 8 files changed, 32 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b7e3d675a5..8333b51aaf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -56,7 +56,8 @@ Avatar::Avatar() : _owningAvatarMixer(), _collisionFlags(0), _initialized(false), - _shouldRenderBillboard(true) + _shouldRenderBillboard(true), + _modelsDirty(true) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -119,7 +120,8 @@ void Avatar::simulate(float deltaTime) { } glm::vec3 headPosition = _position; if (!_shouldRenderBillboard) { - _skeletonModel.simulate(deltaTime); + _skeletonModel.simulate(deltaTime, _modelsDirty); + _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); } Head* head = getHead(); @@ -618,6 +620,9 @@ int Avatar::parseData(const QByteArray& packet) { const float MOVE_DISTANCE_THRESHOLD = 0.001f; _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; + // note that we need to update our models + _modelsDirty = true; + return bytesRead; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index bba86828cb..b1812a12a9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -187,6 +187,7 @@ private: bool _initialized; QScopedPointer _billboardTexture; bool _shouldRenderBillboard; + bool _modelsDirty; void renderBody(); void renderBillboard(); diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index eba8f7bf1a..f4ee6859ed 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -18,9 +18,9 @@ FaceModel::FaceModel(Head* owningHead) : { } -void FaceModel::simulate(float deltaTime, bool delayLoad) { +void FaceModel::simulate(float deltaTime) { if (!isActive()) { - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -41,7 +41,7 @@ void FaceModel::simulate(float deltaTime, bool delayLoad) { setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime); } bool FaceModel::render(float alpha) { diff --git a/interface/src/avatar/FaceModel.h b/interface/src/avatar/FaceModel.h index 597075dc42..d0f0f6baef 100644 --- a/interface/src/avatar/FaceModel.h +++ b/interface/src/avatar/FaceModel.h @@ -21,7 +21,7 @@ public: FaceModel(Head* owningHead); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime); bool render(float alpha); protected: diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f405358710..44d1dd6d07 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -18,13 +18,13 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : _owningAvatar(owningAvatar) { } -void SkeletonModel::simulate(float deltaTime, bool delayLoad) { +void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale() * MODEL_SCALE); - Model::simulate(deltaTime, delayLoad); + Model::simulate(deltaTime, fullUpdate); if (!(isActive() && _owningAvatar->isMyAvatar())) { return; // only simulate for own avatar diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 3d95d805ea..7018e331f0 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -22,7 +22,7 @@ public: SkeletonModel(Avatar* owningAvatar); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// \param jointIndex index of hand joint diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 21fdc80858..9951a94dd5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -156,9 +156,9 @@ void Model::updateShapePositions() { } } -void Model::simulate(float deltaTime, bool delayLoad) { +void Model::simulate(float deltaTime, bool fullUpdate) { // update our LOD - QVector newJointStates = updateGeometry(delayLoad); + QVector newJointStates = updateGeometry(); if (!isActive()) { return; } @@ -183,10 +183,15 @@ void Model::simulate(float deltaTime, bool delayLoad) { model->setURL(attachment.url); _attachments.append(model); } - _resetStates = true; + _resetStates = fullUpdate = true; createCollisionShapes(); } + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + // update the world space transforms for all joints for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i); @@ -868,14 +873,12 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry(bool delayLoad) { +QVector Model::updateGeometry() { QVector newJointStates; if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis, delayLoad); - if (!delayLoad) { - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - } + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); if (_nextGeometry->isLoaded()) { applyNextGeometry(); return newJointStates; @@ -884,7 +887,7 @@ QVector Model::updateGeometry(bool delayLoad) { if (!_geometry) { return newJointStates; } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis, delayLoad); + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); if (_geometry != geometry) { if (!_jointStates.isEmpty()) { // copy the existing joint states @@ -904,10 +907,8 @@ QVector Model::updateGeometry(bool delayLoad) { _dilatedTextures.clear(); _geometry = geometry; } - if (!delayLoad) { - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); return newJointStates; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index c7aadee8dc..ae38423242 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -57,7 +57,7 @@ public: void clearShapes(); void createCollisionShapes(); void updateShapePositions(); - void simulate(float deltaTime, bool delayLoad = false); + void simulate(float deltaTime, bool fullUpdate = true); bool render(float alpha); /// Sets the URL of the model to render. @@ -256,7 +256,7 @@ protected: private: - QVector updateGeometry(bool delayLoad); + QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From b4cb1457a27ac51bd64411ad7fcbce93de346c34 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 13:29:18 -0700 Subject: [PATCH 11/25] Do a simple frustum check for rendering the avatar or doing a full joint update. Closes #2071. --- interface/src/avatar/Avatar.cpp | 19 +++++++++++++++++-- interface/src/avatar/Avatar.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8333b51aaf..bcf24a7bfb 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -110,6 +110,11 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; } + // simple frustum check + float boundingRadius = getBillboardSize(); + bool inViewFrustum = Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) != + ViewFrustum::OUTSIDE; + getHand()->simulate(deltaTime, false); _skeletonModel.setLODDistance(getLODDistance()); @@ -119,7 +124,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.setJointState(i, data.valid, data.rotation); } glm::vec3 headPosition = _position; - if (!_shouldRenderBillboard) { + if (!_shouldRenderBillboard && inViewFrustum) { _skeletonModel.simulate(deltaTime, _modelsDirty); _modelsDirty = false; _skeletonModel.getHeadPosition(headPosition); @@ -185,6 +190,12 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(bool forShadowMap) { + // simple frustum check + float boundingRadius = getBillboardSize(); + if (Application::getInstance()->getViewFrustum()->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { + return; + } + glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition(); float lengthToTarget = glm::length(toTarget); @@ -338,7 +349,7 @@ void Avatar::renderBillboard() { glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // compute the size from the billboard camera parameters and scale - float size = _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + float size = getBillboardSize(); glScalef(size, size, size); glColor3f(1.0f, 1.0f, 1.0f); @@ -363,6 +374,10 @@ void Avatar::renderBillboard() { glBindTexture(GL_TEXTURE_2D, 0); } +float Avatar::getBillboardSize() const { + return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); +} + void Avatar::renderDisplayName() { if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index b1812a12a9..2bd7fc89e8 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -191,6 +191,8 @@ private: void renderBody(); void renderBillboard(); + + float getBillboardSize() const; }; #endif From 5b30f932c1e88d1ff6ccdc262477bac0456be384 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 14:09:12 -0700 Subject: [PATCH 12/25] Fix for slight graphical glitches on loading avatars. --- interface/src/avatar/FaceModel.cpp | 5 +- interface/src/renderer/Model.cpp | 361 +++++++++++++++-------------- interface/src/renderer/Model.h | 4 +- 3 files changed, 188 insertions(+), 182 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index f4ee6859ed..db6c3fe98d 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -19,8 +19,8 @@ FaceModel::FaceModel(Head* owningHead) : } void FaceModel::simulate(float deltaTime) { + QVector newJointStates = updateGeometry(); if (!isActive()) { - Model::simulate(deltaTime); return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -36,12 +36,13 @@ void FaceModel::simulate(float deltaTime) { setRotation(neckRotation); const float MODEL_SCALE = 0.0006f; setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE); + setOffset(-_geometry->getFBXGeometry().neckPivot); setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulate(deltaTime); + Model::simulate(deltaTime, true, newJointStates); } bool FaceModel::render(float alpha) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9951a94dd5..60fae5e596 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -157,146 +157,8 @@ void Model::updateShapePositions() { } void Model::simulate(float deltaTime, bool fullUpdate) { - // update our LOD - QVector newJointStates = updateGeometry(); - if (!isActive()) { - return; - } - - // set up world vertices on first simulate after load - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (_jointStates.isEmpty()) { - _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; - foreach (const FBXMesh& mesh, geometry.meshes) { - MeshState state; - state.clusterMatrices.resize(mesh.clusters.size()); - if (mesh.springiness > 0.0f) { - state.worldSpaceVertices.resize(mesh.vertices.size()); - state.vertexVelocities.resize(mesh.vertices.size()); - state.worldSpaceNormals.resize(mesh.vertices.size()); - } - _meshStates.append(state); - } - foreach (const FBXAttachment& attachment, geometry.attachments) { - Model* model = new Model(this); - model->init(); - model->setURL(attachment.url); - _attachments.append(model); - } - _resetStates = fullUpdate = true; - createCollisionShapes(); - } - - // exit early if we don't have to perform a full update - if (!(fullUpdate || _resetStates)) { - return; - } - - // update the world space transforms for all joints - for (int i = 0; i < _jointStates.size(); i++) { - updateJointState(i); - } - - // update the attachment transforms and simulate them - for (int i = 0; i < _attachments.size(); i++) { - const FBXAttachment& attachment = geometry.attachments.at(i); - Model* model = _attachments.at(i); - - glm::vec3 jointTranslation = _translation; - glm::quat jointRotation = _rotation; - getJointPosition(attachment.jointIndex, jointTranslation); - getJointRotation(attachment.jointIndex, jointRotation); - - model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); - model->setRotation(jointRotation * attachment.rotation); - model->setScale(_scale * attachment.scale); - - model->simulate(deltaTime); - } - - for (int i = 0; i < _meshStates.size(); i++) { - MeshState& state = _meshStates[i]; - const FBXMesh& mesh = geometry.meshes.at(i); - for (int j = 0; j < mesh.clusters.size(); j++) { - const FBXCluster& cluster = mesh.clusters.at(j); - state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; - } - int vertexCount = state.worldSpaceVertices.size(); - if (vertexCount == 0) { - continue; - } - glm::vec3* destVertices = state.worldSpaceVertices.data(); - glm::vec3* destVelocities = state.vertexVelocities.data(); - glm::vec3* destNormals = state.worldSpaceNormals.data(); - - const glm::vec3* sourceVertices = mesh.vertices.constData(); - if (!mesh.blendshapes.isEmpty()) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); - - // blend in each coefficient - for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { - float coefficient = _blendshapeCoefficients[j]; - if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { - continue; - } - const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); - for (const int* index = mesh.blendshapes[j].indices.constData(), - *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { - _blendedVertices[*index] += *vertex * coefficient; - } - } - sourceVertices = _blendedVertices.constData(); - } - glm::mat4 transform = glm::translate(_translation); - if (mesh.clusters.size() > 1) { - _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); - - // skin each vertex - const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); - const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); - for (int j = 0; j < vertexCount; j++) { - _blendedVertices[j] = - glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + - glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + - glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + - glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * - glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; - } - sourceVertices = _blendedVertices.constData(); - - } else { - transform = state.clusterMatrices[0]; - } - if (_resetStates) { - for (int j = 0; j < vertexCount; j++) { - destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); - destVelocities[j] = glm::vec3(); - } - } else { - const float SPRINGINESS_MULTIPLIER = 200.0f; - const float DAMPING = 5.0f; - for (int j = 0; j < vertexCount; j++) { - destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * - mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; - destVertices[j] += destVelocities[j] * deltaTime; - } - } - for (int j = 0; j < vertexCount; j++) { - destNormals[j] = glm::vec3(); - - const glm::vec3& middle = destVertices[j]; - for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); - connection != mesh.vertexConnections.at(j).constEnd(); connection++) { - destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, - destVertices[connection->first] - middle)); - } - } - } - _resetStates = false; + // update our LOD, then simulate + simulate(deltaTime, fullUpdate, updateGeometry()); } bool Model::render(float alpha) { @@ -577,6 +439,186 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi return collided; } +QVector Model::updateGeometry() { + QVector newJointStates; + if (_nextGeometry) { + _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); + _nextGeometry->setLoadPriority(this, -_lodDistance); + _nextGeometry->ensureLoading(); + if (_nextGeometry->isLoaded()) { + applyNextGeometry(); + return newJointStates; + } + } + if (!_geometry) { + return newJointStates; + } + QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); + if (_geometry != geometry) { + if (!_jointStates.isEmpty()) { + // copy the existing joint states + const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& newGeometry = geometry->getFBXGeometry(); + newJointStates = createJointStates(newGeometry); + for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); + it != oldGeometry.jointIndices.constEnd(); it++) { + int oldIndex = it.value() - 1; + int newIndex = newGeometry.getJointIndex(it.key()); + if (newIndex != -1) { + newJointStates[newIndex] = _jointStates.at(oldIndex); + } + } + } + deleteGeometry(); + _dilatedTextures.clear(); + _geometry = geometry; + } + _geometry->setLoadPriority(this, -_lodDistance); + _geometry->ensureLoading(); + return newJointStates; +} + +void Model::simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates) { + if (!isActive()) { + return; + } + + // set up world vertices on first simulate after load + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + if (_jointStates.isEmpty()) { + _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; + foreach (const FBXMesh& mesh, geometry.meshes) { + MeshState state; + state.clusterMatrices.resize(mesh.clusters.size()); + if (mesh.springiness > 0.0f) { + state.worldSpaceVertices.resize(mesh.vertices.size()); + state.vertexVelocities.resize(mesh.vertices.size()); + state.worldSpaceNormals.resize(mesh.vertices.size()); + } + _meshStates.append(state); + } + foreach (const FBXAttachment& attachment, geometry.attachments) { + Model* model = new Model(this); + model->init(); + model->setURL(attachment.url); + _attachments.append(model); + } + _resetStates = fullUpdate = true; + createCollisionShapes(); + } + + // exit early if we don't have to perform a full update + if (!(fullUpdate || _resetStates)) { + return; + } + + // update the world space transforms for all joints + for (int i = 0; i < _jointStates.size(); i++) { + updateJointState(i); + } + + // update the attachment transforms and simulate them + for (int i = 0; i < _attachments.size(); i++) { + const FBXAttachment& attachment = geometry.attachments.at(i); + Model* model = _attachments.at(i); + + glm::vec3 jointTranslation = _translation; + glm::quat jointRotation = _rotation; + getJointPosition(attachment.jointIndex, jointTranslation); + getJointRotation(attachment.jointIndex, jointRotation); + + model->setTranslation(jointTranslation + jointRotation * attachment.translation * _scale); + model->setRotation(jointRotation * attachment.rotation); + model->setScale(_scale * attachment.scale); + + model->simulate(deltaTime); + } + + for (int i = 0; i < _meshStates.size(); i++) { + MeshState& state = _meshStates[i]; + const FBXMesh& mesh = geometry.meshes.at(i); + for (int j = 0; j < mesh.clusters.size(); j++) { + const FBXCluster& cluster = mesh.clusters.at(j); + state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; + } + int vertexCount = state.worldSpaceVertices.size(); + if (vertexCount == 0) { + continue; + } + glm::vec3* destVertices = state.worldSpaceVertices.data(); + glm::vec3* destVelocities = state.vertexVelocities.data(); + glm::vec3* destNormals = state.worldSpaceNormals.data(); + + const glm::vec3* sourceVertices = mesh.vertices.constData(); + if (!mesh.blendshapes.isEmpty()) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + memcpy(_blendedVertices.data(), mesh.vertices.constData(), vertexCount * sizeof(glm::vec3)); + + // blend in each coefficient + for (unsigned int j = 0; j < _blendshapeCoefficients.size(); j++) { + float coefficient = _blendshapeCoefficients[j]; + if (coefficient == 0.0f || j >= (unsigned int)mesh.blendshapes.size() || mesh.blendshapes[j].vertices.isEmpty()) { + continue; + } + const glm::vec3* vertex = mesh.blendshapes[j].vertices.constData(); + for (const int* index = mesh.blendshapes[j].indices.constData(), + *end = index + mesh.blendshapes[j].indices.size(); index != end; index++, vertex++) { + _blendedVertices[*index] += *vertex * coefficient; + } + } + sourceVertices = _blendedVertices.constData(); + } + glm::mat4 transform = glm::translate(_translation); + if (mesh.clusters.size() > 1) { + _blendedVertices.resize(max(_blendedVertices.size(), vertexCount)); + + // skin each vertex + const glm::vec4* clusterIndices = mesh.clusterIndices.constData(); + const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); + for (int j = 0; j < vertexCount; j++) { + _blendedVertices[j] = + glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + + glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + + glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + + glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * + glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; + } + sourceVertices = _blendedVertices.constData(); + + } else { + transform = state.clusterMatrices[0]; + } + if (_resetStates) { + for (int j = 0; j < vertexCount; j++) { + destVertices[j] = glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)); + destVelocities[j] = glm::vec3(); + } + } else { + const float SPRINGINESS_MULTIPLIER = 200.0f; + const float DAMPING = 5.0f; + for (int j = 0; j < vertexCount; j++) { + destVelocities[j] += ((glm::vec3(transform * glm::vec4(sourceVertices[j], 1.0f)) - destVertices[j]) * + mesh.springiness * SPRINGINESS_MULTIPLIER - destVelocities[j] * DAMPING) * deltaTime; + destVertices[j] += destVelocities[j] * deltaTime; + } + } + for (int j = 0; j < vertexCount; j++) { + destNormals[j] = glm::vec3(); + + const glm::vec3& middle = destVertices[j]; + for (QVarLengthArray, 4>::const_iterator connection = mesh.vertexConnections.at(j).constBegin(); + connection != mesh.vertexConnections.at(j).constEnd(); connection++) { + destNormals[j] += glm::normalize(glm::cross(destVertices[connection->second] - middle, + destVertices[connection->first] - middle)); + } + } + } + _resetStates = false; +} + void Model::updateJointState(int index) { _shapesAreDirty = true; JointState& state = _jointStates[index]; @@ -873,45 +915,6 @@ void Model::applyCollision(CollisionInfo& collision) { } } -QVector Model::updateGeometry() { - QVector newJointStates; - if (_nextGeometry) { - _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); - _nextGeometry->setLoadPriority(this, -_lodDistance); - _nextGeometry->ensureLoading(); - if (_nextGeometry->isLoaded()) { - applyNextGeometry(); - return newJointStates; - } - } - if (!_geometry) { - return newJointStates; - } - QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); - if (_geometry != geometry) { - if (!_jointStates.isEmpty()) { - // copy the existing joint states - const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); - const FBXGeometry& newGeometry = geometry->getFBXGeometry(); - newJointStates = createJointStates(newGeometry); - for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); - it != oldGeometry.jointIndices.constEnd(); it++) { - int oldIndex = it.value() - 1; - int newIndex = newGeometry.getJointIndex(it.key()); - if (newIndex != -1) { - newJointStates[newIndex] = _jointStates.at(oldIndex); - } - } - } - deleteGeometry(); - _dilatedTextures.clear(); - _geometry = geometry; - } - _geometry->setLoadPriority(this, -_lodDistance); - _geometry->ensureLoading(); - return newJointStates; -} - void Model::applyNextGeometry() { // delete our local geometry and custom textures deleteGeometry(); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index ae38423242..165465d2cc 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -226,6 +226,9 @@ protected: QVector _meshStates; + QVector updateGeometry(); + void simulate(float deltaTime, bool fullUpdate, const QVector& newJointStates); + /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); @@ -256,7 +259,6 @@ protected: private: - QVector updateGeometry(); void applyNextGeometry(); void deleteGeometry(); void renderMeshes(float alpha, bool translucent); From e5b5778caf2ba2e9b80edd17e25ed4a414211359 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Mar 2014 15:04:22 -0700 Subject: [PATCH 13/25] Upload FST --- libraries/shared/src/AccountManager.cpp | 31 ++++-- libraries/shared/src/AccountManager.h | 7 +- libraries/shared/src/FstReader.cpp | 141 +++++++++++++++++------- libraries/shared/src/FstReader.h | 26 ++--- 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 7915a60690..6517d080ed 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "NodeList.h" #include "PacketHeaders.h" @@ -30,6 +31,7 @@ Q_DECLARE_METATYPE(OAuthAccessToken) Q_DECLARE_METATYPE(DataServerAccountInfo) Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) Q_DECLARE_METATYPE(JSONCallbackParameters) +Q_DECLARE_METATYPE(QHttpMultiPart) const QString ACCOUNTS_GROUP = "accounts"; @@ -99,21 +101,25 @@ void AccountManager::setAuthURL(const QUrl& authURL) { } void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart) { QMetaObject::invokeMethod(this, "invokedRequest", Q_ARG(const QString&, path), Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(const JSONCallbackParameters&, callbackParams), - Q_ARG(const QByteArray&, dataByteArray)); + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart)); } void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray) { - + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { + if (!_networkAccessManager) { _networkAccessManager = new QNetworkAccessManager(this); } - + if (hasValidAccessToken()) { QNetworkRequest authenticatedRequest; @@ -140,11 +146,18 @@ void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager:: case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::PutOperation: authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - if (operation == QNetworkAccessManager::PostOperation) { - networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + if (dataMultiPart) { + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataMultiPart); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataMultiPart); + } } else { - networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + if (operation == QNetworkAccessManager::PostOperation) { + networkReply = _networkAccessManager->post(authenticatedRequest, dataByteArray); + } else { + networkReply = _networkAccessManager->put(authenticatedRequest, dataByteArray); + } } break; diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index ee821fa43c..bfe84f392e 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -39,7 +39,8 @@ public: void authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), - const QByteArray& dataByteArray = QByteArray()); + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -77,7 +78,9 @@ private: void operator=(AccountManager const& other); // not implemented Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray); + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart); QUrl _authURL; QNetworkAccessManager* _networkAccessManager; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index d94f036af0..0e99a7b2f4 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -10,15 +10,38 @@ #include #include #include -#include #include #include +#include +#include + +#include "AccountManager.h" #include "FstReader.h" -FstReader::FstReader() { + +static const QString NAME_FIELD = "name"; +static const QString FILENAME_FIELD = "filename"; +static const QString TEXDIR_FIELD = "texdir"; +static const QString LOD_FIELD = "lod"; + +static const QString MODEL_URL = "/api/v1/models"; + +static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB + +FstReader::FstReader() : + _lodCount(-1), + _texturesCount(-1), + _readyToSend(false), + _dataMultiPart(new QHttpMultiPart(QHttpMultiPart::FormDataType)) +{ } +FstReader::~FstReader() { + if (_dataMultiPart) { + delete _dataMultiPart; + } +} bool FstReader::zip() { // File Dialog @@ -33,11 +56,18 @@ bool FstReader::zip() { qDebug() << "[ERROR] Could not open FST file : " << fst.fileName(); return false; } + + // Compress and copy the fst + if (!compressFile(QFileInfo(fst).filePath(), _zipDir.path() + "/" + QFileInfo(fst).fileName())) { + return false; + } + _totalSize += QFileInfo(fst).size(); + if (!addPart(_zipDir.path() + "/" + QFileInfo(fst).fileName(), + QString("fst"))) { + return false; + } qDebug() << "Reading FST file : " << QFileInfo(fst).filePath(); - - QDir rootDir(_zipDir.path()); - // Let's read through the FST file QTextStream stream(&fst); QList line; @@ -47,20 +77,34 @@ bool FstReader::zip() { continue; } + if (_totalSize > MAX_SIZE) { + qDebug() << "[ERROR] Model too big, over " << MAX_SIZE << " Bytes."; + return false; + } + // according to what is read, we modify the command - if (line.first() == nameField) { - _modelName = line[1]; - } else if (line.first() == filenameField) { + if (line.first() == NAME_FIELD) { + QHttpPart textPart; + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"model_name\""); + //textPart.setRawHeader("name", "\"model_name\""); + textPart.setBody(line[1].toUtf8()); + _dataMultiPart->append(textPart); + } else if (line.first() == FILENAME_FIELD) { QFileInfo fbx(QFileInfo(fst).path() + "/" + line[1]); if (!fbx.exists() || !fbx.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << fbx.absoluteFilePath() << " doesn't exist."; return false; - } else { // Compress and copy - _fbxFile = rootDir.path() + "/" + line[1]; - _totalSize += fbx.size(); - compressFile(fbx.filePath(), _fbxFile); } - } else if (line.first() == texdirField) { // Check existence + // Compress and copy + if (!compressFile(fbx.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += fbx.size(); + if (!addPart(_zipDir.path() + "/" + line[1], "fbx")) { + return false; + } + } else if (line.first() == TEXDIR_FIELD) { // Check existence QFileInfo texdir(QFileInfo(fst).path() + "/" + line[1]); if (!texdir.exists() || !texdir.isDir()) { qDebug() << "[ERROR] Texture directory " << texdir.absolutePath() << " doesn't exist."; @@ -69,47 +113,41 @@ bool FstReader::zip() { if (!addTextures(texdir)) { // Recursive compress and copy return false; } - } else if (line.first() == lodField) { + } else if (line.first() == LOD_FIELD) { QFileInfo lod(QFileInfo(fst).path() + "/" + line[1]); if (!lod.exists() || !lod.isFile()) { // Check existence qDebug() << "[ERROR] FBX file " << lod.absoluteFilePath() << " doesn't exist."; - //return false; - } else { // Compress and copy - _lodFiles.push_back(rootDir.path() + "/" + line[1]); - _totalSize += lod.size(); - compressFile(lod.filePath(), _lodFiles.back()); + return false; + } + // Compress and copy + if (!compressFile(lod.filePath(), _zipDir.path() + "/" + line[1])) { + return false; + } + _totalSize += lod.size(); + if (!addPart(_zipDir.path() + "/" + line[1], QString("lod%1").arg(++_lodCount))) { + return false; } } } - // Compress and copy the fst - _fstFile = rootDir.path() + "/" + QFileInfo(fst).fileName(); - _totalSize += QFileInfo(fst).size(); - compressFile(fst.fileName(), _fstFile); - + _readyToSend = true; return true; } bool FstReader::send() { - QString command = QString("curl -F \"model_name=%1\"").arg(_modelName); - - command += QString(" -F \"fst=@%1\" -F \"fbx=@%2\"").arg(_fstFile, _fbxFile); - for (int i = 0; i < _lodFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_lodFiles[i]); + if (!_readyToSend) { + return false; } - for (int i = 0; i < _textureFiles.size(); ++i) { - command += QString(" -F \"lod%1=@%2\"").arg(i).arg(_textureFiles[i]); - } - command += " http://localhost:3000/api/v1/models/?access_token\\=017894b7312316a2b5025613fcc58c13bc701da9b797cca34b60aae9d1c53acb --trace-ascii /dev/stdout"; - qDebug() << "[DEBUG] " << command; + AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); + _dataMultiPart = NULL; return true; } -bool FstReader::addTextures(QFileInfo& texdir) { +bool FstReader::addTextures(const QFileInfo& texdir) { QStringList filter; - filter << "*.png" << "*.tiff" << "*.jpg" << "*.jpeg"; + filter << "*.png" << "*.tif" << "*.jpg" << "*.jpeg"; QFileInfoList list = QDir(texdir.filePath()).entryInfoList(filter, QDir::Files | @@ -118,9 +156,15 @@ bool FstReader::addTextures(QFileInfo& texdir) { QDir::NoSymLinks); foreach (QFileInfo info, list) { if (info.isFile()) { - _textureFiles.push_back(_zipDir.path() + "/" + info.fileName()); + // Compress and copy + if (!compressFile(info.filePath(), _zipDir.path() + "/" + info.fileName())) { + return false; + } _totalSize += info.size(); - compressFile(info.canonicalFilePath(), _textureFiles.back()); + if (!addPart(_zipDir.path() + "/" + info.fileName(), + QString("texture%1").arg(++_texturesCount))) { + return false; + } } else if (info.isDir()) { if (!addTextures(info)) { return false; @@ -153,7 +197,26 @@ bool FstReader::compressFile(const QString &inFileName, const QString &outFileNa } - +bool FstReader::addPart(const QString &path, const QString& name) { + QFile* file = new QFile(path); + if (!file->open(QIODevice::ReadOnly)) { + qDebug() << "[ERROR] Couldn't open " << file->fileName(); + return false; + } + + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" + " name=\"" + name.toUtf8() + "\";" + " filename=\"" + QFileInfo(*file).fileName().toUtf8() + "\""); + part.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream"); + part.setBodyDevice(file); + _dataMultiPart->append(part); + file->setParent(_dataMultiPart); + + qDebug() << QFileInfo(*file).fileName().toUtf8(); + + return true; +} diff --git a/libraries/shared/src/FstReader.h b/libraries/shared/src/FstReader.h index c5816ea415..aab42bd967 100644 --- a/libraries/shared/src/FstReader.h +++ b/libraries/shared/src/FstReader.h @@ -10,39 +10,31 @@ #ifndef __hifi__FstReader__ #define __hifi__FstReader__ -#include -#include #include - -static const QString nameField = "name"; -static const QString filenameField = "filename"; -static const QString texdirField = "texdir"; -static const QString lodField = "lod"; - -static const int MAX_SIZE = 1024 * 1024; // 1 MB +class QHttpMultiPart; class FstReader { public: FstReader(); + ~FstReader(); bool zip(); bool send(); private: QTemporaryDir _zipDir; - - QString _modelName; - QString _fstFile; - QString _fbxFile; - QStringList _lodFiles; - QStringList _textureFiles; - + int _lodCount; + int _texturesCount; int _totalSize; + bool _readyToSend; + + QHttpMultiPart* _dataMultiPart; - bool addTextures(QFileInfo& texdir); + bool addTextures(const QFileInfo& texdir); bool compressFile(const QString& inFileName, const QString& outFileName); + bool addPart(const QString& path, const QString& name); }; #endif /* defined(__hifi__FstReader__) */ From fc32d9581dda05e5586eb8bd3ec35ca989113137 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:17:16 -0700 Subject: [PATCH 14/25] Visage toggle bits. --- interface/interface_en.ts | 8 +++---- interface/src/Menu.cpp | 9 ++++++-- interface/src/Menu.h | 3 ++- interface/src/devices/Visage.cpp | 36 +++++++++++++++++++------------- interface/src/devices/Visage.h | 10 +++++++-- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 80433032dc..496e3a66e5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 00ae0a3772..4e880f2512 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -270,11 +270,16 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, - MenuOption::FaceshiftTCP, + MenuOption::Faceshift, 0, - false, + true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); +#ifdef HAVE_VISAGE + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, + appInstance->getVisage(), SLOT(setEnabled(bool))); +#endif + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 00ef51178a..f02db150ba 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -239,7 +239,7 @@ namespace MenuOption { const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString HandsCollideWithSelf = "Collide With Self"; - const QString FaceshiftTCP = "Faceshift (TCP)"; + const QString Faceshift = "Faceshift"; const QString FirstPerson = "First Person"; const QString FrameTimer = "Show Timer"; const QString FrustumRenderMode = "Render Mode"; @@ -292,6 +292,7 @@ namespace MenuOption { const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TransmitterDrive = "Transmitter Drive"; + const QString Visage = "Visage"; const QString Quit = "Quit"; const QString Voxels = "Voxels"; const QString VoxelMode = "Cycle Voxel Mode"; diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 727c083265..745b543d87 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -40,25 +40,11 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - if (_tracker->trackFromCam()) { - _data = new FaceData(); - - } else { - delete _tracker; - _tracker = NULL; - } #endif } Visage::~Visage() { -#ifdef HAVE_VISAGE - if (_tracker) { - _tracker->stop(); - delete _tracker; - delete _data; - } -#endif + setEnabled(false); } #ifdef HAVE_VISAGE @@ -160,3 +146,23 @@ void Visage::update() { void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } + +void Visage::setEnabled(bool enabled) { +#ifdef HAVE_VISAGE + if (enabled == (_tracker != NULL)) { + return; + } + if (enabled) { + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); + if (_tracker->trackFromCam()) { + return; + } + } + _tracker->stop(); + delete _tracker; + delete _data; + _tracker = NULL; + _data = NULL; +#endif +} diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index c238b3bb8c..28d990ae7a 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -24,11 +24,13 @@ namespace VisageSDK { } /// Handles input from the Visage webcam feature tracking software. -class Visage { +class Visage : public QObject { + Q_OBJECT + public: Visage(); - ~Visage(); + virtual ~Visage(); bool isActive() const { return _active; } @@ -42,6 +44,10 @@ public: void update(); void reset(); + +public slots: + + void setEnabled(bool enabled); private: From 423f26f669db865b41de3fdb10da79a639b254fd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 13 Mar 2014 15:26:02 -0700 Subject: [PATCH 15/25] Review comments --- interface/src/Application.cpp | 2 +- libraries/shared/src/AccountManager.cpp | 1 - libraries/shared/src/FstReader.cpp | 8 +------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bc8b0f22d..aed212c692 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3462,7 +3462,7 @@ void Application::reloadAllScripts() { void Application::uploadFST() { FstReader reader; - if(reader.zip()) { + if (reader.zip()) { reader.send(); } } diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 6517d080ed..bb32896ca0 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -31,7 +31,6 @@ Q_DECLARE_METATYPE(OAuthAccessToken) Q_DECLARE_METATYPE(DataServerAccountInfo) Q_DECLARE_METATYPE(QNetworkAccessManager::Operation) Q_DECLARE_METATYPE(JSONCallbackParameters) -Q_DECLARE_METATYPE(QHttpMultiPart) const QString ACCOUNTS_GROUP = "accounts"; diff --git a/libraries/shared/src/FstReader.cpp b/libraries/shared/src/FstReader.cpp index 0e99a7b2f4..d82ddf68a3 100644 --- a/libraries/shared/src/FstReader.cpp +++ b/libraries/shared/src/FstReader.cpp @@ -38,9 +38,7 @@ FstReader::FstReader() : } FstReader::~FstReader() { - if (_dataMultiPart) { - delete _dataMultiPart; - } + delete _dataMultiPart; } bool FstReader::zip() { @@ -87,7 +85,6 @@ bool FstReader::zip() { QHttpPart textPart; textPart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data;" " name=\"model_name\""); - //textPart.setRawHeader("name", "\"model_name\""); textPart.setBody(line[1].toUtf8()); _dataMultiPart->append(textPart); } else if (line.first() == FILENAME_FIELD) { @@ -141,7 +138,6 @@ bool FstReader::send() { AccountManager::getInstance().authenticatedRequest(MODEL_URL, QNetworkAccessManager::PostOperation, JSONCallbackParameters(), QByteArray(), _dataMultiPart); - _dataMultiPart = NULL; return true; } @@ -213,8 +209,6 @@ bool FstReader::addPart(const QString &path, const QString& name) { _dataMultiPart->append(part); file->setParent(_dataMultiPart); - qDebug() << QFileInfo(*file).fileName().toUtf8(); - return true; } From 007bfa8866ce3234f025110b617303610aacf896 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 15:26:07 -0700 Subject: [PATCH 16/25] Tweak to Visage toggle. --- interface/src/devices/Visage.cpp | 27 +++++++++++++-------------- interface/src/devices/Visage.h | 1 + 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 745b543d87..876a810431 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -32,6 +32,7 @@ using namespace VisageSDK; const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f); Visage::Visage() : + _enabled(false), _active(false), _headOrigin(DEFAULT_HEAD_ORIGIN), _estimatedEyePitch(0.0f), @@ -40,11 +41,16 @@ Visage::Visage() : #ifdef HAVE_VISAGE QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc"; initializeLicenseManager(licensePath.data()); + _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); + _data = new FaceData(); #endif } Visage::~Visage() { - setEnabled(false); +#ifdef HAVE_VISAGE + delete _tracker; + delete _data; +#endif } #ifdef HAVE_VISAGE @@ -105,7 +111,7 @@ const float TRANSLATION_SCALE = 20.0f; void Visage::update() { #ifdef HAVE_VISAGE - _active = (_tracker && _tracker->getTrackingData(_data) == TRACK_STAT_OK); + _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); if (!_active) { return; } @@ -149,20 +155,13 @@ void Visage::reset() { void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE - if (enabled == (_tracker != NULL)) { + if (_enabled == enabled) { return; } - if (enabled) { - _tracker = new VisageTracker2(Application::resourcesPath().toLatin1() + "visage/tracker.cfg"); - _data = new FaceData(); - if (_tracker->trackFromCam()) { - return; - } + if (_enabled = enabled) { + _tracker->trackFromCam(); + } else { + _tracker->stop(); } - _tracker->stop(); - delete _tracker; - delete _data; - _tracker = NULL; - _data = NULL; #endif } diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index 28d990ae7a..e71bdc0fb5 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -57,6 +57,7 @@ private: QMultiHash > _actionUnitIndexMap; #endif + bool _enabled; bool _active; glm::quat _headRotation; glm::vec3 _headTranslation; From 4523ae742e0b2d018a443a13265106f16b39d0be Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 18:51:14 -0400 Subject: [PATCH 17/25] =?UTF-8?q?Tweak=20in=20code=20styling=20per=20Brad?= =?UTF-8?q?=E2=80=99s=20feedback,=20along=20with=20using=20SIGNAL=20and=20?= =?UTF-8?q?SLOT=20instead=20of=20function=20pointers=20directly.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- interface/src/GLCanvas.cpp | 13 ++++++++----- interface/src/GLCanvas.h | 6 ++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index bf99608c07..249f7a373d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,15 +13,18 @@ #include #include -GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), _throttleRendering(false), _idleRenderInterval(100) { +GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), + _throttleRendering(false), + _idleRenderInterval(100) +{ } void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); setAcceptDrops(true); - connect(Application::getInstance(), &Application::applicationStateChanged, this, &GLCanvas::activeChanged); - connect(&_frameTimer, &QTimer::timeout, this, &GLCanvas::throttleRender); + connect(Application::getInstance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(activeChanged(Qt::ApplicationState))); + connect(&_frameTimer, SIGNAL(timeout()), this, SLOT(throttleRender())); } void GLCanvas::paintGL() { @@ -54,8 +57,8 @@ void GLCanvas::mouseReleaseEvent(QMouseEvent* event) { Application::getInstance()->mouseReleaseEvent(event); } -void GLCanvas::activeChanged() { - switch (Application::applicationState()) { +void GLCanvas::activeChanged(Qt::ApplicationState state) { + switch (state) { case Qt::ApplicationActive: // If we're active, stop the frame timer and the throttle. _frameTimer.stop(); diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 7e4a4d0334..e6dcc38977 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -14,6 +14,7 @@ /// customized canvas that simply forwards requests/events to the singleton application class GLCanvas : public QGLWidget { + Q_OBJECT public: GLCanvas(); protected: @@ -39,8 +40,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent* event); - - void activeChanged(); + +private slots: + void activeChanged(Qt::ApplicationState state); void throttleRender(); }; From 881ecb07cd3268d2622d9a8249e09018132e8cdd Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 13 Mar 2014 23:00:01 +0200 Subject: [PATCH 18/25] Changed the font of the entire chat window to Helvetica/Arial. --- interface/interface_en.ts | 10 +++++----- interface/ui/chatWindow.ui | 13 +++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 80433032dc..b6e35f3f5f 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -28,19 +28,19 @@ ChatWindow - + Chat - - + + Connecting to XMPP... - - + + online now: diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index ecb4d79c41..22f2dcd5dd 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -13,6 +13,9 @@ Chat + + font-family: Helvetica, Arial, sans-serif; + 0 @@ -100,7 +103,7 @@ - margin-top: 12px; font-family: Helvetica, Arial, sans-serif; + margin-top: 12px; Qt::ScrollBarAlwaysOff @@ -114,7 +117,7 @@ 0 0 358 - 452 + 464 @@ -154,6 +157,12 @@ 0 + + + 0 + 60 + + border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; From 55d0835ba1645256d9ba83bfe7403ee82518fed0 Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 13 Mar 2014 19:08:18 -0400 Subject: [PATCH 19/25] Indentation! --- interface/src/GLCanvas.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 249f7a373d..b68c4fdacd 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -14,8 +14,8 @@ #include GLCanvas::GLCanvas() : QGLWidget(QGLFormat(QGL::NoDepthBuffer, QGL::NoStencilBuffer)), - _throttleRendering(false), - _idleRenderInterval(100) + _throttleRendering(false), + _idleRenderInterval(100) { } From 85a15a2284513d2a0a3481dc5aaf7ddcd8af1251 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 14 Mar 2014 00:43:02 +0200 Subject: [PATCH 20/25] Moved the chat from a window to a built-in panel. --- interface/interface_en.ts | 30 +++++++++++++++--------------- interface/src/Application.cpp | 10 +++++++++- interface/src/Menu.cpp | 16 +++++++--------- interface/src/ui/ChatWindow.cpp | 17 +++++++++++++---- interface/src/ui/ChatWindow.h | 7 ++++--- interface/ui/chatWindow.ui | 8 +++++++- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index b6e35f3f5f..23ea3cc3ba 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -27,25 +27,25 @@ ChatWindow - + Chat - + Connecting to XMPP... - + online now: - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aed212c692..b08f8f77f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -291,7 +292,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : ResourceCache::setNetworkAccessManager(_networkAccessManager); ResourceCache::setRequestLimit(3); - _window->setCentralWidget(_glWidget); + QWidget* centralWidget = new QWidget(); + QHBoxLayout* mainLayout = new QHBoxLayout(); + mainLayout->setSpacing(0); + mainLayout->setContentsMargins(0, 0, 0, 0); + centralWidget->setLayout(mainLayout); + _glWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + centralWidget->layout()->addWidget(_glWidget); + _window->setCentralWidget(centralWidget); restoreSizeAndPosition(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 71e24e2382..c92d550fd6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1041,22 +1041,20 @@ void Menu::showChat() { if (!_chatWindow) { _chatWindow = new ChatWindow(); QMainWindow* mainWindow = Application::getInstance()->getWindow(); - _chatWindow->setGeometry(mainWindow->width() - _chatWindow->width(), - mainWindow->geometry().y(), - _chatWindow->width(), - mainWindow->height()); + QBoxLayout* boxLayout = static_cast(mainWindow->centralWidget()->layout()); + boxLayout->addWidget(_chatWindow, 0, Qt::AlignRight); + } else { + if (!_chatWindow->isVisible()) { + _chatWindow->show(); + } } - if (!_chatWindow->isVisible()) { - _chatWindow->show(); - } - _chatWindow->raise(); } void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); if (!_chatAction->isEnabled() && _chatWindow) { - _chatWindow->close(); + _chatWindow->hide(); } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index d4f257c0f7..103f045cfa 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -28,7 +28,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); ChatWindow::ChatWindow() : - QDialog(Application::getInstance()->getGLWidget(), Qt::CustomizeWindowHint), + QWidget(), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { @@ -39,7 +39,6 @@ ChatWindow::ChatWindow() : ui->messagePlainTextEdit->installEventFilter(this); - setAttribute(Qt::WA_DeleteOnClose); #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { @@ -72,8 +71,18 @@ ChatWindow::~ChatWindow() { delete ui; } -void ChatWindow::reject() { - hide(); +void ChatWindow::keyPressEvent(QKeyEvent* event) { + QWidget::keyPressEvent(event); + if (event->key() == Qt::Key_Escape) { + hide(); + } +} + +void ChatWindow::showEvent(QShowEvent* event) { + QWidget::showEvent(event); + if (!event->spontaneous()) { + ui->messagePlainTextEdit->setFocus(); + } } bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 57da4da45d..fbf9fc0859 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -9,9 +9,9 @@ #ifndef __interface__ChatWindow__ #define __interface__ChatWindow__ -#include #include #include +#include #include @@ -26,14 +26,15 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QDialog { +class ChatWindow : public QWidget { Q_OBJECT public: ChatWindow(); ~ChatWindow(); - virtual void reject(); + virtual void keyPressEvent(QKeyEvent *event); + virtual void showEvent(QShowEvent* event); protected: bool eventFilter(QObject* sender, QEvent* event); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 22f2dcd5dd..1106fca3cd 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -1,7 +1,7 @@ ChatWindow - + 0 @@ -10,6 +10,12 @@ 608 + + + 400 + 0 + + Chat From 9d1278b6637415b821cc8ed7a23e9a2fc5a2b426 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:18:47 -0700 Subject: [PATCH 21/25] Wait until we know that Faceshift didn't connect before we attempt to initialize Visage. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 +++ interface/src/Menu.cpp | 2 +- interface/src/devices/Faceshift.cpp | 6 ++++++ interface/src/devices/Faceshift.h | 6 ++++++ interface/src/devices/Visage.cpp | 13 ++++++++++++- interface/src/devices/Visage.h | 6 +++++- 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 496e3a66e5..5eeacc67d8 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 96129e0161..a8b28f2c0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,6 +1525,9 @@ void Application::init() { } qDebug("Loaded settings"); + // initialize Visage after loading the menu settings + _visage.init(); + // fire off an immediate domain-server check in now that settings are loaded NodeList::getInstance()->sendDomainServerCheckIn(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4e880f2512..a42fe9da65 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -277,7 +277,7 @@ Menu::Menu() : SLOT(setTCPEnabled(bool))); #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true, - appInstance->getVisage(), SLOT(setEnabled(bool))); + appInstance->getVisage(), SLOT(updateEnabled())); #endif addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 4fe89ff98b..8aa57fa792 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -49,12 +49,18 @@ Faceshift::Faceshift() : connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected())); connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError))); connect(&_tcpSocket, SIGNAL(readyRead()), SLOT(readFromSocket())); + connect(&_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), SIGNAL(connectionStateChanged())); connect(&_udpSocket, SIGNAL(readyRead()), SLOT(readPendingDatagrams())); _udpSocket.bind(FACESHIFT_PORT); } +bool Faceshift::isConnectedOrConnecting() const { + return _tcpSocket.state() == QAbstractSocket::ConnectedState || + (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); +} + bool Faceshift::isActive() const { const quint64 ACTIVE_TIMEOUT_USECS = 1000000; return (usecTimestampNow() - _lastTrackingStateReceived) < ACTIVE_TIMEOUT_USECS; diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 908354ae9d..66403715cd 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + bool isConnectedOrConnecting() const; + bool isActive() const; const glm::quat& getHeadRotation() const { return _headRotation; } @@ -66,6 +68,10 @@ public: void updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, float jawOpen, std::vector& coefficients) const; +signals: + + void connectionStateChanged(); + public slots: void setTCPEnabled(bool enabled); diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 876a810431..51b7324568 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -109,6 +109,11 @@ static const QMultiHash >& getActionUnitNameMap() const float TRANSLATION_SCALE = 20.0f; +void Visage::init() { + connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); + updateEnabled(); +} + void Visage::update() { #ifdef HAVE_VISAGE _active = (_tracker->getTrackingData(_data) == TRACK_STAT_OK); @@ -153,12 +158,18 @@ void Visage::reset() { _headOrigin += _headTranslation / TRANSLATION_SCALE; } +void Visage::updateEnabled() { + setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) && + !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && + Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); +} + void Visage::setEnabled(bool enabled) { #ifdef HAVE_VISAGE if (_enabled == enabled) { return; } - if (_enabled = enabled) { + if ((_enabled = enabled)) { _tracker->trackFromCam(); } else { _tracker->stop(); diff --git a/interface/src/devices/Visage.h b/interface/src/devices/Visage.h index e71bdc0fb5..7e50812ba7 100644 --- a/interface/src/devices/Visage.h +++ b/interface/src/devices/Visage.h @@ -32,6 +32,8 @@ public: Visage(); virtual ~Visage(); + void init(); + bool isActive() const { return _active; } const glm::quat& getHeadRotation() const { return _headRotation; } @@ -47,7 +49,7 @@ public: public slots: - void setEnabled(bool enabled); + void updateEnabled(); private: @@ -57,6 +59,8 @@ private: QMultiHash > _actionUnitIndexMap; #endif + void setEnabled(bool enabled); + bool _enabled; bool _active; glm::quat _headRotation; From 92bc675c97b03e8de2824150b166f2e6e9acbc91 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:21:45 -0700 Subject: [PATCH 22/25] Make sure to stop Visage before deleting it. --- interface/src/devices/Visage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/devices/Visage.cpp b/interface/src/devices/Visage.cpp index 51b7324568..b96ef1ee72 100644 --- a/interface/src/devices/Visage.cpp +++ b/interface/src/devices/Visage.cpp @@ -48,6 +48,7 @@ Visage::Visage() : Visage::~Visage() { #ifdef HAVE_VISAGE + _tracker->stop(); delete _tracker; delete _data; #endif From 5f6f4b3d37480abf3b373e2946028d0336b45253 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:45:27 -0700 Subject: [PATCH 23/25] Fixes required since enabling Faceshift is now the default. --- interface/interface_en.ts | 4 ++-- interface/src/Application.cpp | 3 ++- interface/src/devices/Faceshift.cpp | 6 +++++- interface/src/devices/Faceshift.h | 2 ++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 5eeacc67d8..53b8c8a0c5 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8b28f2c0a..f616234cbc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1525,7 +1525,8 @@ void Application::init() { } qDebug("Loaded settings"); - // initialize Visage after loading the menu settings + // initialize Visage and Faceshift after loading the menu settings + _faceshift.init(); _visage.init(); // fire off an immediate domain-server check in now that settings are loaded diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 8aa57fa792..88974ce493 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -21,7 +21,7 @@ using namespace std; const quint16 FACESHIFT_PORT = 33433; Faceshift::Faceshift() : - _tcpEnabled(false), + _tcpEnabled(true), _tcpRetryCount(0), _lastTrackingStateReceived(0), _eyeGazeLeftPitch(0.0f), @@ -56,6 +56,10 @@ Faceshift::Faceshift() : _udpSocket.bind(FACESHIFT_PORT); } +void Faceshift::init() { + setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift)); +} + bool Faceshift::isConnectedOrConnecting() const { return _tcpSocket.state() == QAbstractSocket::ConnectedState || (_tcpRetryCount == 0 && _tcpSocket.state() != QAbstractSocket::UnconnectedState); diff --git a/interface/src/devices/Faceshift.h b/interface/src/devices/Faceshift.h index 66403715cd..a0898c446d 100644 --- a/interface/src/devices/Faceshift.h +++ b/interface/src/devices/Faceshift.h @@ -27,6 +27,8 @@ public: Faceshift(); + void init(); + bool isConnectedOrConnecting() const; bool isActive() const; From 38d03febbc7ccb1790119878c65550949782e2e9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 16:58:15 -0700 Subject: [PATCH 24/25] Add this file back. Hope it didn't have anything important! --- interface/interface_en.ts | 154 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 interface/interface_en.ts diff --git a/interface/interface_en.ts b/interface/interface_en.ts new file mode 100644 index 0000000000..531e8966dc --- /dev/null +++ b/interface/interface_en.ts @@ -0,0 +1,154 @@ + + + + + Application + + + Export Voxels + + + + + Sparse Voxel Octree Files (*.svo) + + + + + Open Script + + + + + JavaScript Files (*.js) + + + + + ChatWindow + + + + Chat + + + + + + Connecting to XMPP... + + + + + + online now: + + + + + day + + + + + + + + hour + + + + + + + + minute + + + + + + + + %1 online now: + + + + + Dialog + + + + + + Update Required + + + + + + Download + + + + + + Skip Version + + + + + + Close + + + + + Menu + + + Open .ini config file + + + + + + Text files (*.ini) + + + + + Save .ini config file + + + + + QObject + + + + Import Voxels + + + + + Loading ... + + + + + Place voxels + + + + + <b>Import</b> %1 as voxels + + + + + Cancel + + + + From 3f78ef40f1aef043d4f2cd811ceb9656ddf8ec59 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Mar 2014 17:08:23 -0700 Subject: [PATCH 25/25] Fixed the translation file. --- interface/interface_en.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 531e8966dc..c52ec91671 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -47,25 +47,32 @@ day - - - + + %n day + %n days hour - - - + + %n hour + %n hours minute - - - + + %n minute + %n minutes + + + + second + + %n second + %n seconds