From 39241bec133f90e7c018116b6a0f34f2690fb6ef Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 11 May 2017 15:58:31 -0700 Subject: [PATCH 01/79] Prototyping a way to produce a selfie and use the rendering directly --- interface/src/Application.cpp | 16 +++- interface/src/PrototypeSelfie.cpp | 77 +++++++++++++++++++ interface/src/PrototypeSelfie.h | 44 +++++++++++ .../src/model-networking/TextureCache.cpp | 42 ++++++++++ .../src/model-networking/TextureCache.h | 16 ++++ .../developer/utilities/render/debugSelfie.js | 38 +++++++++ 6 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 interface/src/PrototypeSelfie.cpp create mode 100644 interface/src/PrototypeSelfie.h create mode 100644 scripts/developer/utilities/render/debugSelfie.js diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d3a690b020..764d9882f4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -110,6 +110,7 @@ #include #include #include +#include #include #include #include @@ -1898,8 +1899,18 @@ void Application::initializeGL() { qCDebug(interfaceapp, "Initialized Display."); // Set up the render engine - render::CullFunctor cullFunctor = LODManager::shouldRender; - _renderEngine->addJob("RenderShadowTask", cullFunctor); + render::CullFunctor cullFunctor = LODManager::shouldRender; + static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; + bool isDeferred = true; + if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { + isDeferred = false; + } + + _renderEngine->addJob("MainFrame", cullFunctor, isDeferred); + _renderEngine->addJob("SelfieFrame", cullFunctor); + + +/* _renderEngine->addJob("RenderShadowTask", cullFunctor); const auto items = _renderEngine->addJob("FetchCullSort", cullFunctor); assert(items.canCast()); static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; @@ -1908,6 +1919,7 @@ void Application::initializeGL() { } else { _renderEngine->addJob("RenderDeferredTask", items); } + */ _renderEngine->load(); _renderEngine->registerScene(_main3DScene); diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp new file mode 100644 index 0000000000..9e1b1b92db --- /dev/null +++ b/interface/src/PrototypeSelfie.cpp @@ -0,0 +1,77 @@ + +#include "PrototypeSelfie.h" + + +void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { + + task.addJob("RenderShadowTask", cullFunctor); + const auto items = task.addJob("FetchCullSort", cullFunctor); + assert(items.canCast()); + if (!isDeferred) { + task.addJob("Forward", items); + } else { + task.addJob("RenderDeferredTask", items); + } +} + + +#include + +using RenderArgsPointer = std::shared_ptr; + +class BeginSelfieFrame { +public: + using JobModel = render::Job::ModelO; + + + void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { + auto args = renderContext->args; + + auto textureCache = DependencyManager::get(); + + auto destFramebuffer = textureCache->getSelfieFramebuffer(); + _cachedArgs._blitFramebuffer = args->_blitFramebuffer; + args->_blitFramebuffer = destFramebuffer; + args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); + + + auto srcViewFrustum = args->getViewFrustum(); + auto srcPos = srcViewFrustum.getPosition(); + srcPos.x += 2.0f; + srcViewFrustum.setPosition(srcPos); + args->pushViewFrustum(srcViewFrustum); + + // cachedArgs = _cachedArgs; + } + +protected: + RenderArgs _cachedArgs; +}; + +class EndSelfieFrame { +public: + using JobModel = render::Job::ModelI; + + + void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) { + auto args = renderContext->args; + args->popViewFrustum(); + + } + +protected: +}; + +void SelfieRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { + + + const auto cachedArg = task.addJob("BeginSelfie"); + + const auto items = task.addJob("FetchCullSort", cullFunctor); + assert(items.canCast()); + + task.addJob("RenderDeferredTask", items); + + task.addJob("EndSelfie", cachedArg); + +} \ No newline at end of file diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h new file mode 100644 index 0000000000..14b9f2d3f3 --- /dev/null +++ b/interface/src/PrototypeSelfie.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef hifi_PrototypeSelfie_h +#define hifi_PrototypeSelfie_h + +#include +#include +#include +#include + + + +class MainRenderTask { +public: + using JobModel = render::Task::Model; + + MainRenderTask() {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); +}; + +class SelfieRenderTaskConfig : public render::Task::Config { + Q_OBJECT +public: + SelfieRenderTaskConfig() : render::Task::Config(true) {} +signals: + void dirty(); + +protected: +}; + +class SelfieRenderTask { +public: + using Config = SelfieRenderTaskConfig; + + using JobModel = render::Task::Model; + + SelfieRenderTask() {} + + void configure(const Config& config) {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); +}; + +#endif \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 9653cde7d8..6e8695bfe8 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,6 +50,8 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; +const std::string TextureCache::SELFIE_FRAME_URL { "http://selfieFrame" }; + static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models @@ -180,6 +182,10 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum } NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) { + if (url == QUrl(SELFIE_FRAME_URL.c_str())) { + + return getSelfieNetworkTexture(); + } TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -265,6 +271,18 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh return QSharedPointer(texture, &Resource::deleter); } +NetworkTexture::NetworkTexture(const QUrl& url) : +Resource(url), +_type(), +_sourceIsKTX(false), +_maxNumPixels(100) +{ + _textureSource = std::make_shared(); + _lowestRequestedMipLevel = 0; + _loaded = true; +} + + NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) : Resource(url), _type(type), @@ -856,3 +874,27 @@ void ImageReader::read() { Q_ARG(int, texture->getWidth()), Q_ARG(int, texture->getHeight())); } + + +NetworkTexturePointer TextureCache::getSelfieNetworkTexture() { + if (!_selfieNetworkTexture) { + _selfieNetworkTexture.reset(new NetworkTexture(QUrl(SELFIE_FRAME_URL.c_str()))); + _selfieNetworkTexture->setImage(getSelfieTexture(), 2048, 1024); + } + return _selfieNetworkTexture; + } + +const gpu::TexturePointer& TextureCache::getSelfieTexture() { + if (!_selfieTexture) { + getSelfieFramebuffer(); + } + return _selfieTexture; +} +const gpu::FramebufferPointer& TextureCache::getSelfieFramebuffer() { + if (!_selfieFramebuffer) { + _selfieFramebuffer.reset(gpu::Framebuffer::create("selfie", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); + _selfieTexture = _selfieFramebuffer->getRenderBuffer(0); + } + + return _selfieFramebuffer; +} \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index aabc7fcb85..90c17a9ab1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -45,6 +45,7 @@ class NetworkTexture : public Resource, public Texture { Q_OBJECT public: + NetworkTexture(const QUrl& url); NetworkTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels); ~NetworkTexture() override; @@ -130,6 +131,8 @@ private: int _width { 0 }; int _height { 0 }; int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS }; + + friend class TextureCache; }; using NetworkTexturePointer = QSharedPointer; @@ -168,6 +171,12 @@ public: gpu::TexturePointer getTextureByHash(const std::string& hash); gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture); + + /// Selfie rendering targets. + NetworkTexturePointer getSelfieNetworkTexture(); + const gpu::TexturePointer& getSelfieTexture(); + const gpu::FramebufferPointer& getSelfieFramebuffer(); + protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); @@ -185,6 +194,8 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; + static const std::string SELFIE_FRAME_URL; + KTXCache _ktxCache; // Map from image hashes to texture weak pointers std::unordered_map> _texturesByHashes; @@ -195,6 +206,11 @@ private: gpu::TexturePointer _grayTexture; gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; + + + gpu::FramebufferPointer _selfieFramebuffer; + gpu::TexturePointer _selfieTexture; + NetworkTexturePointer _selfieNetworkTexture; }; #endif // hifi_TextureCache_h diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js new file mode 100644 index 0000000000..fea51ab278 --- /dev/null +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -0,0 +1,38 @@ + +function addOne() { + + var newOverlay = Overlays.addOverlay("image", { + x: 100, y: 100, width: 500, height: 250, + // imageURL: "http://selfieFrame", + imageURL: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", + alpha: 1.0 + }); + +} + +function addTwo() { + + var orientation = MyAvatar.orientation; + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + var root = Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(orientation))); + + + var newOverlay = Overlays.addOverlay("image3d", { + //url: kickOverlayURL(), + url: "http://selfieFrame", + //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", + position: root, + size: 1, + scale: 5.0, + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + solid: true, + isFacingAvatar: true, + drawInFront: false + }); +} + + +addTwo(); \ No newline at end of file From 2b2dd267e0f72ecdcd2ec53dd97bf6c912f95178 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 11 May 2017 16:05:57 -0700 Subject: [PATCH 02/79] attach the 3D overlay to the avatar because it s more fun --- scripts/developer/utilities/render/debugSelfie.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index fea51ab278..ef73c7e598 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -30,7 +30,8 @@ function addTwo() { alpha: 1, solid: true, isFacingAvatar: true, - drawInFront: false + drawInFront: false, + parentID: MyAvatar.sessionUUID }); } From b53a501ed2cf1e94b0e6c01466f96f5856d1a9bf Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 11 May 2017 16:15:14 -0700 Subject: [PATCH 03/79] attach the 3D overlay to the avatar because it s more fun --- scripts/developer/utilities/render/debugSelfie.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index ef73c7e598..31d5b51686 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -19,13 +19,13 @@ function addTwo() { var root = Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(orientation))); - var newOverlay = Overlays.addOverlay("image3d", { + return Overlays.addOverlay("image3d", { //url: kickOverlayURL(), url: "http://selfieFrame", //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", position: root, size: 1, - scale: 5.0, + scale: -5.0, color: { red: 255, green: 255, blue: 255}, alpha: 1, solid: true, @@ -36,4 +36,6 @@ function addTwo() { } -addTwo(); \ No newline at end of file +var newOverlay = addTwo(); + +Script.scriptEnding.connect(function () { Overlays.deleteOverlay(newOverlay); }) \ No newline at end of file From 29299976eea1f846e982864b2d255e3d0376ccbe Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 12 May 2017 17:03:23 -0700 Subject: [PATCH 04/79] render task should default off and be enabled by script --- interface/src/PrototypeSelfie.h | 2 +- scripts/developer/utilities/render/debugSelfie.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index 14b9f2d3f3..f35cd88b65 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -21,7 +21,7 @@ public: class SelfieRenderTaskConfig : public render::Task::Config { Q_OBJECT public: - SelfieRenderTaskConfig() : render::Task::Config(true) {} + SelfieRenderTaskConfig() : render::Task::Config(false) {} signals: void dirty(); diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index 31d5b51686..70903a52eb 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -37,5 +37,10 @@ function addTwo() { var newOverlay = addTwo(); +var config = Render.getConfig("SelfieFrame"); +config.enabled = true; -Script.scriptEnding.connect(function () { Overlays.deleteOverlay(newOverlay); }) \ No newline at end of file +Script.scriptEnding.connect(function () { + config.enabled = false; + Overlays.deleteOverlay(newOverlay); +}) From 142b4f4203ca72727b75ccd840ee93649ffc9291 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 12 May 2017 18:18:46 -0700 Subject: [PATCH 05/79] kill warnings --- interface/src/PrototypeSelfie.h | 6 +++--- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index f35cd88b65..18ab16939c 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -6,8 +6,8 @@ #include #include #include - - +#include "OctreeRenderer.h" + class MainRenderTask { public: @@ -41,4 +41,4 @@ public: void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; -#endif \ No newline at end of file +#endif diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index b759a06aee..80c8698bb6 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include From 9d1283e06715fcc080ddae64c8eda3d4f816c646 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Sun, 14 May 2017 15:24:35 -0700 Subject: [PATCH 06/79] resetSize of texture --- interface/src/PrototypeSelfie.cpp | 8 ++++++ interface/src/PrototypeSelfie.h | 4 +-- .../src/model-networking/TextureCache.cpp | 12 ++++++--- .../src/model-networking/TextureCache.h | 1 + .../developer/utilities/render/debugSelfie.js | 26 ++++++++++++------- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index 9e1b1b92db..fae29e03ca 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -19,6 +19,14 @@ void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render using RenderArgsPointer = std::shared_ptr; +void SelfieRenderTaskConfig::resetSize(int width, int height) { + bool wasEnabled = isEnabled(); + setEnabled(false); + auto textureCache = DependencyManager::get(); + textureCache->resetSelfieFramebuffer(width, height); + setEnabled(wasEnabled); +} + class BeginSelfieFrame { public: using JobModel = render::Job::ModelO; diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index 18ab16939c..209cd7322a 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -24,8 +24,8 @@ public: SelfieRenderTaskConfig() : render::Task::Config(false) {} signals: void dirty(); - -protected: +public slots: + void resetSize(int width, int height); }; class SelfieRenderTask { diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6e8695bfe8..2a9d196228 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -879,7 +879,8 @@ void ImageReader::read() { NetworkTexturePointer TextureCache::getSelfieNetworkTexture() { if (!_selfieNetworkTexture) { _selfieNetworkTexture.reset(new NetworkTexture(QUrl(SELFIE_FRAME_URL.c_str()))); - _selfieNetworkTexture->setImage(getSelfieTexture(), 2048, 1024); + auto texture = getSelfieTexture(); + _selfieNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); } return _selfieNetworkTexture; } @@ -892,9 +893,14 @@ const gpu::TexturePointer& TextureCache::getSelfieTexture() { } const gpu::FramebufferPointer& TextureCache::getSelfieFramebuffer() { if (!_selfieFramebuffer) { - _selfieFramebuffer.reset(gpu::Framebuffer::create("selfie", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); - _selfieTexture = _selfieFramebuffer->getRenderBuffer(0); + resetSelfieFramebuffer(2048, 1024); } return _selfieFramebuffer; +} + +void TextureCache::resetSelfieFramebuffer(int width, int height) { + _selfieFramebuffer.reset(gpu::Framebuffer::create("selfie", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); + _selfieTexture = _selfieFramebuffer->getRenderBuffer(0); + _selfieNetworkTexture.reset(); } \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index e97a2be814..698d37f38d 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -174,6 +174,7 @@ public: NetworkTexturePointer getSelfieNetworkTexture(); const gpu::TexturePointer& getSelfieTexture(); const gpu::FramebufferPointer& getSelfieFramebuffer(); + void resetSelfieFramebuffer(int width, int height); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index 70903a52eb..7c9f322c71 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -9,21 +9,19 @@ function addOne() { }); } - +function offset() { + var orientation = MyAvatar.orientation; + orientation = Quat.safeEulerAngles(orientation); + orientation.x = 0; + orientation = Quat.fromVec3Degrees(orientation); + return Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(orientation))); +} function addTwo() { - - var orientation = MyAvatar.orientation; - orientation = Quat.safeEulerAngles(orientation); - orientation.x = 0; - orientation = Quat.fromVec3Degrees(orientation); - var root = Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(orientation))); - - return Overlays.addOverlay("image3d", { //url: kickOverlayURL(), url: "http://selfieFrame", //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", - position: root, + position: offset(), size: 1, scale: -5.0, color: { red: 255, green: 255, blue: 255}, @@ -38,9 +36,17 @@ function addTwo() { var newOverlay = addTwo(); var config = Render.getConfig("SelfieFrame"); +function updateCamera() { + //config.position = offset(); + //config.orientation = MyAvatar.orientation; +} +var size = Controller.getViewportDimensions(); +config.resetSize(size.x, size.y); +Script.update.connect(updateCamera); config.enabled = true; Script.scriptEnding.connect(function () { config.enabled = false; + Script.update.disconnect(updateCamera); Overlays.deleteOverlay(newOverlay); }) From 3a0cc4e975cd45a30e0ef97c6d46264c9d8d8aaf Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Sun, 14 May 2017 15:48:40 -0700 Subject: [PATCH 07/79] begin/end are Model, not ModelI/O, and begin has config --- interface/src/PrototypeSelfie.cpp | 33 +++++++------------------------ interface/src/PrototypeSelfie.h | 15 ++++++++++---- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index fae29e03ca..d37fd550d5 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -29,57 +29,38 @@ void SelfieRenderTaskConfig::resetSize(int width, int height) { class BeginSelfieFrame { public: - using JobModel = render::Job::ModelO; + using Config = BeginSelfieFrameConfig; + using JobModel = render::Job::Model; - - void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { + void run(const render::RenderContextPointer& renderContext) { auto args = renderContext->args; - auto textureCache = DependencyManager::get(); - auto destFramebuffer = textureCache->getSelfieFramebuffer(); - _cachedArgs._blitFramebuffer = args->_blitFramebuffer; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - auto srcViewFrustum = args->getViewFrustum(); auto srcPos = srcViewFrustum.getPosition(); srcPos.x += 2.0f; srcViewFrustum.setPosition(srcPos); args->pushViewFrustum(srcViewFrustum); - - // cachedArgs = _cachedArgs; } - -protected: - RenderArgs _cachedArgs; }; class EndSelfieFrame { public: - using JobModel = render::Job::ModelI; + using JobModel = render::Job::Model; - - void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) { + void run(const render::RenderContextPointer& renderContext) { auto args = renderContext->args; args->popViewFrustum(); - } - -protected: }; void SelfieRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { - - - const auto cachedArg = task.addJob("BeginSelfie"); - + task.addJob("BeginSelfie"); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); - task.addJob("RenderDeferredTask", items); - - task.addJob("EndSelfie", cachedArg); - + task.addJob("EndSelfie"); } \ No newline at end of file diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index 209cd7322a..101fdf40ee 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -18,6 +18,17 @@ public: void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); }; +class BeginSelfieFrameConfig : public render::Task::Config { + Q_OBJECT + Q_PROPERTY(glm::vec3 position MEMBER position NOTIFY dirty) // of viewpoint to render from + Q_PROPERTY(glm::quat orientation MEMBER orientation NOTIFY dirty) // of viewpoint to render from +public: + glm::vec3 position{}; + glm::quat orientation{}; +signals: + void dirty(); +}; + class SelfieRenderTaskConfig : public render::Task::Config { Q_OBJECT public: @@ -31,13 +42,9 @@ public slots: class SelfieRenderTask { public: using Config = SelfieRenderTaskConfig; - using JobModel = render::Task::Model; - SelfieRenderTask() {} - void configure(const Config& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; From fa9d8663695c1143cf79368cd61b36e59bd484ff Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 15 May 2017 07:10:12 -0700 Subject: [PATCH 08/79] change camera pos/orientation through config --- interface/src/PrototypeSelfie.cpp | 16 ++++++++++++---- .../developer/utilities/render/debugSelfie.js | 10 +++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index d37fd550d5..94b86f051d 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -28,21 +28,29 @@ void SelfieRenderTaskConfig::resetSize(int width, int height) { } class BeginSelfieFrame { + glm::vec3 _position{}; + glm::quat _orientation{}; public: using Config = BeginSelfieFrameConfig; - using JobModel = render::Job::Model; + using JobModel = render::Job::Model; + + void configure(const Config& config) { + qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; + _position = config.position; + _orientation = config.orientation; + } void run(const render::RenderContextPointer& renderContext) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); auto destFramebuffer = textureCache->getSelfieFramebuffer(); + // Why don't we have to reset these values? Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); auto srcViewFrustum = args->getViewFrustum(); - auto srcPos = srcViewFrustum.getPosition(); - srcPos.x += 2.0f; - srcViewFrustum.setPosition(srcPos); + srcViewFrustum.setPosition(_position); + srcViewFrustum.setOrientation(_orientation); args->pushViewFrustum(srcViewFrustum); } }; diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index 7c9f322c71..195143eac3 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -23,7 +23,7 @@ function addTwo() { //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", position: offset(), size: 1, - scale: -5.0, + scale: 5.0, color: { red: 255, green: 255, blue: 255}, alpha: 1, solid: true, @@ -36,17 +36,21 @@ function addTwo() { var newOverlay = addTwo(); var config = Render.getConfig("SelfieFrame"); +var config2 = Render.getConfig("BeginSelfie"); function updateCamera() { - //config.position = offset(); - //config.orientation = MyAvatar.orientation; + config2.position = offset(); + config2.orientation = MyAvatar.orientation; + //print('fixme pos/orient', JSON.stringify(config.position), JSON.stringify(config.orientation)); } var size = Controller.getViewportDimensions(); config.resetSize(size.x, size.y); Script.update.connect(updateCamera); config.enabled = true; +config2.enabled = true; Script.scriptEnding.connect(function () { config.enabled = false; + config2.enabled = false; Script.update.disconnect(updateCamera); Overlays.deleteOverlay(newOverlay); }) From fed5397b38a5fc39643d7c452983e713f9ad2386 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 16 May 2017 16:46:52 -0700 Subject: [PATCH 09/79] a camera --- interface/src/PrototypeSelfie.cpp | 5 +- interface/src/PrototypeSelfie.h | 1 + .../developer/utilities/render/debugSelfie.js | 108 ++++++++++-------- 3 files changed, 66 insertions(+), 48 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index 94b86f051d..529226472b 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -35,7 +35,7 @@ public: using JobModel = render::Job::Model; void configure(const Config& config) { - qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; + //qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; _position = config.position; _orientation = config.orientation; } @@ -45,12 +45,15 @@ public: auto textureCache = DependencyManager::get(); auto destFramebuffer = textureCache->getSelfieFramebuffer(); // Why don't we have to reset these values? Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? + // Hmm, maybe we do have to! In hmd we're getting stereo on our texture! args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); srcViewFrustum.setOrientation(_orientation); + //srcViewFrustum.calculate(); // do we need this? I don't think so + //qDebug() << "FIXME pos" << _position << "orient" << _orientation << "frust pos" << srcViewFrustum.getPosition() << "orient" << srcViewFrustum.getOrientation() << "direct" << srcViewFrustum.getDirection(); args->pushViewFrustum(srcViewFrustum); } }; diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index 101fdf40ee..7ee1f121f3 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -25,6 +25,7 @@ class BeginSelfieFrameConfig : public render::Task::Config { public: glm::vec3 position{}; glm::quat orientation{}; + BeginSelfieFrameConfig() : render::Task::Config(false) {} signals: void dirty(); }; diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js index 195143eac3..0105700109 100644 --- a/scripts/developer/utilities/render/debugSelfie.js +++ b/scripts/developer/utilities/render/debugSelfie.js @@ -1,56 +1,70 @@ - -function addOne() { - - var newOverlay = Overlays.addOverlay("image", { - x: 100, y: 100, width: 500, height: 250, - // imageURL: "http://selfieFrame", - imageURL: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", - alpha: 1.0 - }); - -} -function offset() { - var orientation = MyAvatar.orientation; - orientation = Quat.safeEulerAngles(orientation); - orientation.x = 0; - orientation = Quat.fromVec3Degrees(orientation); - return Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(orientation))); -} -function addTwo() { - return Overlays.addOverlay("image3d", { - //url: kickOverlayURL(), - url: "http://selfieFrame", - //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", - position: offset(), - size: 1, - scale: 5.0, - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - solid: true, - isFacingAvatar: true, - drawInFront: false, - parentID: MyAvatar.sessionUUID - }); +function inFrontOf(distance, position, orientation) { + return Vec3.sum(position || MyAvatar.position, + Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); } +var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); +function flip(rotation) { return Quat.multiply(rotation, aroundY); } +// Specifying the following userData makes the camera near-grabbable in HMD. +// We really want it to also be far-grabbable and mouse-grabbable, +// but that requires dynamic:1, but alas that causes the camera to drift +// when let go. Maybe we'll restore the old "zero velocity on release" code +// to (handController)grab.js, and also make the camera collisionless? +var isDynamic = false; +var viewFinderOverlay, camera = Entities.addEntity({ + type: 'Box', + dimensions: {x: 0.4, y: 0.2, z: 0.4}, + userData: '{"grabbableKey":{"grabbable":true}}', + dynamic: isDynamic ? 1 : 0, + color: {red: 255, green: 0, blue: 0}, + name: 'SpectatorCamera' +}); // FIXME: avatar entity so that you don't need rez rights. -var newOverlay = addTwo(); var config = Render.getConfig("SelfieFrame"); var config2 = Render.getConfig("BeginSelfie"); -function updateCamera() { - config2.position = offset(); - config2.orientation = MyAvatar.orientation; - //print('fixme pos/orient', JSON.stringify(config.position), JSON.stringify(config.orientation)); +function updateRenderFromCamera() { + var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); + // FIXME: don't muck with config if properties haven't changed. + config2.position = cameraData.position; + config2.orientation = cameraData.rotation; + // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object + if (isDynamic) { + Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); + } } -var size = Controller.getViewportDimensions(); -config.resetSize(size.x, size.y); -Script.update.connect(updateCamera); -config.enabled = true; -config2.enabled = true; +Script.setTimeout(function () { // delay for a bit in case this script is running at startup + // Set the special texture size based on the window in which it will eventually be displayed. + var size = Controller.getViewportDimensions(); + config.resetSize(size.x, size.y); + Script.update.connect(updateRenderFromCamera); + config.enabled = config2.enabled = true; + Script.setTimeout(function () { // FIXME: do we need this delay? why? + var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); + // Put the camera in front of me so that I can find it. + Entities.editEntity(camera, { + position: cameraPosition, + rotation: cameraRotation + }); + // Put an image3d overlay on the near face, as a viewFinder. + viewFinderOverlay = Overlays.addOverlay("image3d", { + url: "http://selfieFrame", + //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", + parentID: camera, + alpha: 1, + position: inFrontOf(-0.25, cameraPosition, cameraRotation), + // FIXME: We shouldn't need the flip and the negative scale. + // e.g., This isn't necessary using an ordinary .jpg with lettering, above. + // Must be something about the view frustum projection matrix? + // But don't go changing that in (c++ code) without getting all the way to a desktop display! + orientation: flip(cameraRotation), + scale: -0.35, + }); + }, 500); +}, 1000); Script.scriptEnding.connect(function () { - config.enabled = false; - config2.enabled = false; - Script.update.disconnect(updateCamera); - Overlays.deleteOverlay(newOverlay); + config.enabled = config2.enabled = false; + Script.update.disconnect(updateRenderFromCamera); + Overlays.deleteOverlay(viewFinderOverlay); + Entities.deleteEntity(camera); }) From 469ffd41abb629a5b1556fc96978c249a95a3088 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 18 May 2017 17:07:41 -0700 Subject: [PATCH 10/79] bring back proper cached args --- interface/src/PrototypeSelfie.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index 529226472b..1cbd7dce20 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -32,7 +32,7 @@ class BeginSelfieFrame { glm::quat _orientation{}; public: using Config = BeginSelfieFrameConfig; - using JobModel = render::Job::Model; + using JobModel = render::Job::ModelO; void configure(const Config& config) { //qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; @@ -40,14 +40,16 @@ public: _orientation = config.orientation; } - void run(const render::RenderContextPointer& renderContext) { + void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); auto destFramebuffer = textureCache->getSelfieFramebuffer(); - // Why don't we have to reset these values? Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? - // Hmm, maybe we do have to! In hmd we're getting stereo on our texture! + // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? + _cachedArgs._blitFramebuffer = args->_blitFramebuffer; + _cachedArgs._viewport = args->_viewport; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); + // FIXME: We're also going to need to clear/restore the stereo setup! auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); @@ -55,23 +57,29 @@ public: //srcViewFrustum.calculate(); // do we need this? I don't think so //qDebug() << "FIXME pos" << _position << "orient" << _orientation << "frust pos" << srcViewFrustum.getPosition() << "orient" << srcViewFrustum.getOrientation() << "direct" << srcViewFrustum.getDirection(); args->pushViewFrustum(srcViewFrustum); + cachedArgs = std::make_shared(_cachedArgs); } + +protected: + RenderArgs _cachedArgs; }; class EndSelfieFrame { public: - using JobModel = render::Job::Model; + using JobModel = render::Job::ModelI; - void run(const render::RenderContextPointer& renderContext) { + void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) { auto args = renderContext->args; + args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + args->_viewport = cachedArgs->_viewport; args->popViewFrustum(); } }; void SelfieRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { - task.addJob("BeginSelfie"); + const auto cachedArg = task.addJob("BeginSelfie"); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); task.addJob("RenderDeferredTask", items); - task.addJob("EndSelfie"); + task.addJob("EndSelfie", cachedArg); } \ No newline at end of file From af98b3bd4c5aa8881419b1e9eebadd9838e7d4fb Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 19 May 2017 10:45:36 -0700 Subject: [PATCH 11/79] cleanup --- interface/src/PrototypeSelfie.cpp | 17 +++++++++++------ interface/src/PrototypeSelfie.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index 1cbd7dce20..809406ac23 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -19,7 +19,7 @@ void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render using RenderArgsPointer = std::shared_ptr; -void SelfieRenderTaskConfig::resetSize(int width, int height) { +void SelfieRenderTaskConfig::resetSize(int width, int height) { // Carefully adjust the framebuffer / texture. bool wasEnabled = isEnabled(); setEnabled(false); auto textureCache = DependencyManager::get(); @@ -27,14 +27,18 @@ void SelfieRenderTaskConfig::resetSize(int width, int height) { setEnabled(wasEnabled); } -class BeginSelfieFrame { +class BeginSelfieFrame { // Changes renderContext for our framebuffer and and view. glm::vec3 _position{}; glm::quat _orientation{}; public: using Config = BeginSelfieFrameConfig; using JobModel = render::Job::ModelO; + BeginSelfieFrame() { + _cachedArgsPointer = std::make_shared(_cachedArgs); + } void configure(const Config& config) { + // Why does this run all the time, even when not enabled? Should we check and bail? //qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; _position = config.position; _orientation = config.orientation; @@ -45,8 +49,8 @@ public: auto textureCache = DependencyManager::get(); auto destFramebuffer = textureCache->getSelfieFramebuffer(); // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? - _cachedArgs._blitFramebuffer = args->_blitFramebuffer; - _cachedArgs._viewport = args->_viewport; + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + _cachedArgsPointer->_viewport = args->_viewport; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); // FIXME: We're also going to need to clear/restore the stereo setup! @@ -57,14 +61,15 @@ public: //srcViewFrustum.calculate(); // do we need this? I don't think so //qDebug() << "FIXME pos" << _position << "orient" << _orientation << "frust pos" << srcViewFrustum.getPosition() << "orient" << srcViewFrustum.getOrientation() << "direct" << srcViewFrustum.getDirection(); args->pushViewFrustum(srcViewFrustum); - cachedArgs = std::make_shared(_cachedArgs); + cachedArgs = _cachedArgsPointer; } protected: RenderArgs _cachedArgs; + RenderArgsPointer _cachedArgsPointer; }; -class EndSelfieFrame { +class EndSelfieFrame { // Restores renderContext. public: using JobModel = render::Job::ModelI; diff --git a/interface/src/PrototypeSelfie.h b/interface/src/PrototypeSelfie.h index 7ee1f121f3..7bb9bbe861 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/PrototypeSelfie.h @@ -18,7 +18,7 @@ public: void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); }; -class BeginSelfieFrameConfig : public render::Task::Config { +class BeginSelfieFrameConfig : public render::Task::Config { // Exposes view frustum position/orientation to javascript. Q_OBJECT Q_PROPERTY(glm::vec3 position MEMBER position NOTIFY dirty) // of viewpoint to render from Q_PROPERTY(glm::quat orientation MEMBER orientation NOTIFY dirty) // of viewpoint to render from From e9bb982651f92f8039e2da58e530440b2d6230f6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 5 Jun 2017 15:07:35 -0700 Subject: [PATCH 12/79] First checkpoint! --- .../resources/qml/hifi/SpectatorCamera.qml | 41 ++++ scripts/defaultScripts.js | 1 + scripts/system/spectatorCamera.js | 183 ++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 interface/resources/qml/hifi/SpectatorCamera.qml create mode 100644 scripts/system/spectatorCamera.js diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml new file mode 100644 index 0000000000..1e8072c472 --- /dev/null +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -0,0 +1,41 @@ +// +// SpectatorCamera.qml +// qml/hifi +// +// Spectator Camera +// +// Created by Zach Fox on 2017-06-05 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../styles-uit" +import "../controls-uit" as HifiControlsUit +import "../controls" as HifiControls + +// references HMD, XXX from root context + +Rectangle { + id: spectatorCamera; + // Size + width: parent.width; + height: parent.height; + // Style + color: "#E3E3E3"; + // Properties + + HifiConstants { id: hifi; } + + function fromScript(message) { + switch (message.method) { + case 'XXX': + break; + default: + console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); + } + } +} diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 81ce72d901..aaa6d06c33 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -25,6 +25,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-goto.js", "system/marketplaces/marketplaces.js", "system/edit.js", + "system/spectatorCamera.js", "system/selectAudioDevice.js", "system/notifications.js", "system/dialTone.js", diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js new file mode 100644 index 0000000000..7316ead1be --- /dev/null +++ b/scripts/system/spectatorCamera.js @@ -0,0 +1,183 @@ +"use strict"; +/*jslint vars:true, plusplus:true, forin:true*/ +/*global Tablet, */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ +// +// spectatorCamera.js +// +// Created by Zach Fox on 2017-06-05 +// Copyright 2017 High Fidelity, Inc +// +// Distributed under the Apache License, Version 2.0 +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function () { // BEGIN LOCAL_SCOPE + + + // + // Function Name: sendToQml() + // + // Relevant Variables: + // None + // + // Arguments: + // message: The message to send to the SpectatorCamera QML. + // Messages are in format "{method, params}", like json-rpc. See also fromQml(). + // + // Description: + // Use this function to send a message to the QML (i.e. to change appearances). + // + function sendToQml(message) { + tablet.sendToQml(message); + } + + // + // Function Name: fromQml() + // + // Relevant Variables: + // None + // + // Arguments: + // message: The message sent from the SpectatorCamera QML. + // Messages are in format "{method, params}", like json-rpc. See also sendToQml(). + // + // Description: + // Called when a message is received from SpectatorCamera.qml. + // + function fromQml(message) { // + var data; + switch (message.method) { + case 'XXX': + break; + default: + print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); + } + } + + // + // Function Name: onTabletButtonClicked() + // + // Relevant Variables: + // onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app + // shouldActivateButton: true/false depending on whether we should show the button as white or gray the + // next time we edit the button's properties + // + // Arguments: + // None + // + // Description: + // Fired when the Spectator Camera app button is pressed. + // + var onSpectatorCameraScreen = false; + var shouldActivateButton = false; + function onTabletButtonClicked() { + if (onSpectatorCameraScreen) { + // for toolbar-mode: go back to home screen, this will close the window. + tablet.gotoHomeScreen(); + } else { + shouldActivateButton = true; + tablet.loadQMLSource("../SpectatorCamera.qml"); + onSpectatorCameraScreen = true; + } + } + + // + // Function Name: wireEventBridge() + // + // Relevant Variables: + // hasEventBridge: true/false depending on whether we've already connected the event bridge + // + // Arguments: + // on: Enable or disable the event bridge + // + // Description: + // Used to connect/disconnect the script's response to the tablet's "fromQml" signal. + // + var hasEventBridge = false; + function wireEventBridge(on) { + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } + } + } + + // + // Function Name: onTabletScreenChanged() + // + // Relevant Variables: + // None + // + // Arguments: + // type: "Home", "Web", "Menu", "QML", "Closed" + // url: Only valid for Web and QML. + // + // Description: + // Called when the TabletScriptingInterface::screenChanged() signal is emitted. + // + function onTabletScreenChanged(type, url) { + wireEventBridge(shouldActivateButton); + // for toolbar mode: change button to active when window is first openend, false otherwise. + button.editProperties({ isActive: shouldActivateButton }); + shouldActivateButton = false; + onSpectatorCameraScreen = false; + } + + // + // Function Name: shutdown() + // + // Relevant Variables: + // button: The tablet button. + // buttonName: The name of the button. + // tablet: The tablet instance to be modified. + // + // Arguments: + // None + // + // Description: + // startup() will be called when the script is loaded. + // + var button; + var buttonName = "Spectator"; + var tablet = null; + function startup() { + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + button = tablet.addButton({ + text: buttonName + }); + button.clicked.connect(onTabletButtonClicked); + tablet.screenChanged.connect(onTabletScreenChanged); + } + + // + // Function Name: shutdown() + // + // Relevant Variables: + // None + // + // Arguments: + // None + // + // Description: + // shutdown() will be called when the script ends (i.e. is stopped). + // + function shutdown() { + tablet.removeButton(button); + button.clicked.disconnect(onTabletButtonClicked); + tablet.screenChanged.disconnect(onTabletScreenChanged); + } + + // + // These functions will be called when the script is loaded. + // + startup(); + Script.scriptEnding.connect(shutdown); + +}()); // END LOCAL_SCOPE From 1fc7094b2c65ccc5bf98e23249f24d879bc5c582 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 5 Jun 2017 17:41:05 -0700 Subject: [PATCH 13/79] Checkpoint --- .../resources/qml/hifi/SpectatorCamera.qml | 206 +++++++++++++++++- scripts/system/spectatorCamera.js | 131 +++++------ 2 files changed, 270 insertions(+), 67 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 1e8072c472..8dfea22e2e 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -22,14 +22,209 @@ import "../controls" as HifiControls Rectangle { id: spectatorCamera; // Size - width: parent.width; - height: parent.height; // Style - color: "#E3E3E3"; + color: "#FFFFFF"; // Properties HifiConstants { id: hifi; } + + // + // TITLE BAR START + // + Item { + id: titleBarContainer; + // Size + width: spectatorCamera.width; + height: 50; + // Anchors + anchors.left: parent.left; + anchors.top: parent.top; + // "Spectator" text + RalewayRegular { + id: titleBarText; + text: "Spectator"; + // Text size + size: hifi.fontSizes.overlayTitle; + // Anchors + anchors.fill: parent; + anchors.leftMargin: 16; + // Style + color: hifi.colors.darkGray; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // Separator + Rectangle { + // Size + width: parent.width; + height: 1; + // Anchors + anchors.left: parent.left; + anchors.bottom: parent.bottom; + // Style + color: hifi.colors.faintGray; + } + } + // + // TITLE BAR END + // + + // + // SPECTATOR APP DESCRIPTION START + // + Item { + id: spectatorDescriptionContainer; + // Size + width: spectatorCamera.width; + height: childrenRect.height; + // Anchors + anchors.left: parent.left; + anchors.top: titleBarContainer.bottom; + + // (i) Glyph + HiFiGlyphs { + id: spectatorDescriptionGlyph; + text: hifi.glyphs.info; + // Size + width: 20; + height: parent.height; + size: 48; + // Anchors + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.top: parent.top; + anchors.topMargin: 0; + // Style + color: hifi.colors.blueAccent; + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // "Spectator" app description text + RalewaySemiBold { + id: spectatorDescriptionText; + text: "Spectator lets you switch what your monitor displays while you're using an HMD."; + // Text size + size: 14; + // Size + width: parent.width - 40 - 60; + height: paintedHeight; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 10; + anchors.left: spectatorDescriptionGlyph.right; + anchors.leftMargin: 30; + // Style + color: hifi.colors.darkGray; + wrapMode: Text.WordWrap; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + } + + // "Learn More" text + RalewayRegular { + id: spectatorLearnMoreText; + text: "Learn More About Spectator"; + // Text size + size: 14; + // Size + width: paintedWidth; + height: paintedHeight; + // Anchors + anchors.top: spectatorDescriptionText.bottom; + anchors.topMargin: 10; + anchors.left: spectatorDescriptionText.anchors.left; + anchors.leftMargin: spectatorDescriptionText.anchors.leftMargin; + // Style + color: hifi.colors.blueAccent; + wrapMode: Text.WordWrap; + font.underline: true; + // Alignment + horizontalAlignment: Text.AlignHLeft; + verticalAlignment: Text.AlignVCenter; + + MouseArea { + anchors.fill: parent; + hoverEnabled: enabled; + onClicked: { + console.log("FIXME! Add popup pointing to 'Learn More' page"); + } + onEntered: parent.color = hifi.colors.blueHighlight; + onExited: parent.color = hifi.colors.blueAccent; + } + } + + // Separator + Rectangle { + // Size + width: parent.width; + height: 1; + // Anchors + anchors.left: parent.left; + anchors.top: spectatorLearnMoreText.bottom; + anchors.topMargin: spectatorDescriptionText.anchors.topMargin; + // Style + color: hifi.colors.faintGray; + } + } + // + // SPECTATOR APP DESCRIPTION END + // + + + // + // SPECTATOR CONTROLS START + // + Item { + id: spectatorControlsContainer; + // Size + width: spectatorCamera.width; + height: spectatorCamera.height - spectatorDescriptionContainer.height - titleBarContainer.height; + // Anchors + anchors.top: spectatorDescriptionContainer.bottom; + anchors.topMargin: 12; + anchors.left: parent.left; + anchors.leftMargin: 20; + + // "Camera On" Checkbox + HifiControlsUit.CheckBox { + id: cameraToggleCheckBox; + anchors.left: parent.left; + anchors.top: parent.top; + //checked: true; // FIXME + text: "Camera On"; + boxSize: 32; + onCheckedChanged: { + console.log("CAMERA ON: " + checked); + } + } + + // Preview + } + // + // SPECTATOR CONTROLS END + // + + // + // FUNCTION DEFINITIONS START + // + // + // Function Name: fromScript() + // + // Relevant Variables: + // None + // + // Arguments: + // message: The message sent from the SpectatorCamera JavaScript. + // Messages are in format "{method, params}", like json-rpc. + // + // Description: + // Called when a message is received from spectatorCamera.js. + // function fromScript(message) { switch (message.method) { case 'XXX': @@ -38,4 +233,9 @@ Rectangle { console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); } } + signal sendToScript(var message); + + // + // FUNCTION DEFINITIONS END + // } diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 7316ead1be..5a226d4eeb 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -1,6 +1,6 @@ "use strict"; /*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablet, */ +/*global Tablet, Script, */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ // // spectatorCamera.js @@ -14,44 +14,61 @@ (function () { // BEGIN LOCAL_SCOPE + // + // FUNCTION VAR DECLARATIONS + // + var sendToQml, onTabletScreenChanged, fromQml, onTabletButtonClicked, wireEventBridge, startup, shutdown; // - // Function Name: sendToQml() + // Function Name: startup() // // Relevant Variables: - // None + // button: The tablet button. + // buttonName: The name of the button. + // tablet: The tablet instance to be modified. // // Arguments: - // message: The message to send to the SpectatorCamera QML. - // Messages are in format "{method, params}", like json-rpc. See also fromQml(). + // None // // Description: - // Use this function to send a message to the QML (i.e. to change appearances). + // startup() will be called when the script is loaded. // - function sendToQml(message) { - tablet.sendToQml(message); + var button; + var buttonName = "SPECTATOR"; + var tablet = null; + function startup() { + tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + button = tablet.addButton({ + text: buttonName + }); + button.clicked.connect(onTabletButtonClicked); + tablet.screenChanged.connect(onTabletScreenChanged); } // - // Function Name: fromQml() + // Function Name: wireEventBridge() // // Relevant Variables: - // None + // hasEventBridge: true/false depending on whether we've already connected the event bridge // // Arguments: - // message: The message sent from the SpectatorCamera QML. - // Messages are in format "{method, params}", like json-rpc. See also sendToQml(). + // on: Enable or disable the event bridge // // Description: - // Called when a message is received from SpectatorCamera.qml. + // Used to connect/disconnect the script's response to the tablet's "fromQml" signal. // - function fromQml(message) { // - var data; - switch (message.method) { - case 'XXX': - break; - default: - print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); + var hasEventBridge = false; + function wireEventBridge(on) { + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } } } @@ -82,33 +99,6 @@ } } - // - // Function Name: wireEventBridge() - // - // Relevant Variables: - // hasEventBridge: true/false depending on whether we've already connected the event bridge - // - // Arguments: - // on: Enable or disable the event bridge - // - // Description: - // Used to connect/disconnect the script's response to the tablet's "fromQml" signal. - // - var hasEventBridge = false; - function wireEventBridge(on) { - if (on) { - if (!hasEventBridge) { - tablet.fromQml.connect(fromQml); - hasEventBridge = true; - } - } else { - if (hasEventBridge) { - tablet.fromQml.disconnect(fromQml); - hasEventBridge = false; - } - } - } - // // Function Name: onTabletScreenChanged() // @@ -131,29 +121,42 @@ } // - // Function Name: shutdown() + // Function Name: sendToQml() // // Relevant Variables: - // button: The tablet button. - // buttonName: The name of the button. - // tablet: The tablet instance to be modified. - // - // Arguments: // None // + // Arguments: + // message: The message to send to the SpectatorCamera QML. + // Messages are in format "{method, params}", like json-rpc. See also fromQml(). + // // Description: - // startup() will be called when the script is loaded. + // Use this function to send a message to the QML (i.e. to change appearances). // - var button; - var buttonName = "Spectator"; - var tablet = null; - function startup() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - text: buttonName - }); - button.clicked.connect(onTabletButtonClicked); - tablet.screenChanged.connect(onTabletScreenChanged); + function sendToQml(message) { + tablet.sendToQml(message); + } + + // + // Function Name: fromQml() + // + // Relevant Variables: + // None + // + // Arguments: + // message: The message sent from the SpectatorCamera QML. + // Messages are in format "{method, params}", like json-rpc. See also sendToQml(). + // + // Description: + // Called when a message is received from SpectatorCamera.qml. + // + function fromQml(message) { + switch (message.method) { + case 'XXX': + break; + default: + print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); + } } // From 9970802142354daceb44b2d03de679eb8793bd47 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 10:55:25 -0700 Subject: [PATCH 14/79] Another checkpoint --- .../resources/qml/hifi/SpectatorCamera.qml | 32 +++-- scripts/system/spectatorCamera.js | 134 +++++++++++++++++- 2 files changed, 156 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 8dfea22e2e..f677efa347 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -94,7 +94,7 @@ Rectangle { size: 48; // Anchors anchors.left: parent.left; - anchors.leftMargin: 20; + anchors.leftMargin: 45; anchors.top: parent.top; anchors.topMargin: 0; // Style @@ -110,7 +110,7 @@ Rectangle { // Text size size: 14; // Size - width: parent.width - 40 - 60; + width: parent.width - 90 - 60; height: paintedHeight; // Anchors anchors.top: parent.top; @@ -182,13 +182,14 @@ Rectangle { Item { id: spectatorControlsContainer; // Size - width: spectatorCamera.width; height: spectatorCamera.height - spectatorDescriptionContainer.height - titleBarContainer.height; // Anchors anchors.top: spectatorDescriptionContainer.bottom; - anchors.topMargin: 12; + anchors.topMargin: 20; anchors.left: parent.left; - anchors.leftMargin: 20; + anchors.leftMargin: 40; + anchors.right: parent.right; + anchors.rightMargin: 40; // "Camera On" Checkbox HifiControlsUit.CheckBox { @@ -197,13 +198,25 @@ Rectangle { anchors.top: parent.top; //checked: true; // FIXME text: "Camera On"; - boxSize: 32; - onCheckedChanged: { - console.log("CAMERA ON: " + checked); + boxSize: 30; + onClicked: { + sendToScript({method: (checked ? 'enableSpectatorCamera' : 'disableSpectatorCamera')}); } } // Preview + Image { + id: spectatorCameraPreview; + height: 300; + anchors.left: parent.left; + anchors.top: cameraToggleCheckBox.bottom; + anchors.topMargin: 20; + anchors.right: parent.right; + fillMode: Image.PreserveAspectFit; + horizontalAlignment: Image.AlignHCenter; + verticalAlignment: Image.AlignVCenter; + source: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; + } } // // SPECTATOR CONTROLS END @@ -227,7 +240,8 @@ Rectangle { // function fromScript(message) { switch (message.method) { - case 'XXX': + case 'updateSpectatorCameraCheckbox': + cameraToggleCheckBox.checked = message.params; break; default: console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 5a226d4eeb..88d2a9ebc1 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -19,6 +19,130 @@ // var sendToQml, onTabletScreenChanged, fromQml, onTabletButtonClicked, wireEventBridge, startup, shutdown; + + + // + // Function Name: inFrontOf(), flip() + // + // Description: + // Spectator camera utility functions and variables. + // + function inFrontOf(distance, position, orientation) { + return Vec3.sum(position || MyAvatar.position, + Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); + } + var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); + function flip(rotation) { return Quat.multiply(rotation, aroundY); } + + // + // Function Name: updateRenderFromCamera() + // + // Relevant Variables: + // spectatorFrameRenderConfig: The render configuration of the spectator camera + // render job. Controls size. + // beginSpectatorFrameRenderConfig: The render configuration of the spectator camera + // render job. Controls position and orientation. + // viewFinderOverlay: The in-world overlay that displays the spectator camera's view. + // camera: The in-world entity that corresponds to the spectator camera. + // + // Arguments: + // None + // + // Description: + // The update function for the spectator camera. Modifies the camera's position + // and orientation. + // + var spectatorFrameRenderConfig = Render.getConfig("SelfieFrame"); + var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSelfie"); + var viewFinderOverlay = false; + var camera = false; + function updateRenderFromCamera() { + var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); + // FIXME: don't muck with config if properties haven't changed. + beginSpectatorFrameRenderConfig.position = cameraData.position; + beginSpectatorFrameRenderConfig.orientation = cameraData.rotation; + // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object + Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); + } + + // + // Function Name: enableSpectatorCamera() + // + // Relevant Variables: + // isUpdateRenderWired: Bool storing whether or not the camera's update + // function is wired. + // + // Arguments: + // None + // + // Description: + // Call this function to set up the spectator camera and + // spawn the camera entity. + // + var isUpdateRenderWired = false; + function enableSpectatorCamera() { + // Set the special texture size based on the window in which it will eventually be displayed. + var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. + spectatorFrameRenderConfig.resetSize(size.x, size.y); + spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; + var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); + Script.update.connect(updateRenderFromCamera); + isUpdateRenderWired = true; + camera = Entities.addEntity({ + type: 'Box', + dimensions: { x: 0.4, y: 0.2, z: 0.4 }, + userData: '{"grabbableKey":{"grabbable":true}}', + dynamic: true, + color: { red: 255, green: 0, blue: 0 }, + name: 'SpectatorCamera', + position: cameraPosition, // Put the camera in front of me so that I can find it. + rotation: cameraRotation + }); // FIXME: avatar entity so that you don't need rez rights.; + // Put an image3d overlay on the near face, as a viewFinder. + viewFinderOverlay = Overlays.addOverlay("image3d", { + url: "http://selfieFrame", + //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", + parentID: camera, + alpha: 1, + position: inFrontOf(-0.25, cameraPosition, cameraRotation), + // FIXME: We shouldn't need the flip and the negative scale. + // e.g., This isn't necessary using an ordinary .jpg with lettering, above. + // Must be something about the view frustum projection matrix? + // But don't go changing that in (c++ code) without getting all the way to a desktop display! + orientation: flip(cameraRotation), + scale: -0.35, + }); + } + + // + // Function Name: disableSpectatorCamera() + // + // Relevant Variables: + // None + // + // Arguments: + // None + // + // Description: + // Call this function to shut down the spectator camera and + // destroy the camera entity. + // + function disableSpectatorCamera() { + spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = false; + if (isUpdateRenderWired) { + Script.update.disconnect(updateRenderFromCamera); + isUpdateRenderWired = false; + } + if (viewFinderOverlay) { + Overlays.deleteOverlay(viewFinderOverlay); + viewFinderOverlay = false; + } + if (camera) { + Entities.deleteEntity(camera); + camera = false; + } + } + // // Function Name: startup() // @@ -43,6 +167,8 @@ }); button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); + viewFinderOverlay = false; + camera = false; } // @@ -96,6 +222,7 @@ shouldActivateButton = true; tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; + sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); } } @@ -152,7 +279,11 @@ // function fromQml(message) { switch (message.method) { - case 'XXX': + case 'enableSpectatorCamera': + enableSpectatorCamera(); + break; + case 'disableSpectatorCamera': + disableSpectatorCamera(); break; default: print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); @@ -172,6 +303,7 @@ // shutdown() will be called when the script ends (i.e. is stopped). // function shutdown() { + disableSpectatorCamera(); tablet.removeButton(button); button.clicked.disconnect(onTabletButtonClicked); tablet.screenChanged.disconnect(onTabletScreenChanged); From 557d1c65a3a017aec6ed7388fbdc3409f2f64cba Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 11:58:25 -0700 Subject: [PATCH 15/79] Another checkpoint; added Switch.qml --- .../resources/qml/controls-uit/Switch.qml | 60 +++++++++++++++ .../resources/qml/hifi/SpectatorCamera.qml | 74 ++++++++++++++----- scripts/system/spectatorCamera.js | 9 +++ 3 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 interface/resources/qml/controls-uit/Switch.qml diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml new file mode 100644 index 0000000000..6db38b054d --- /dev/null +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -0,0 +1,60 @@ +// +// Switch.qml +// +// Created by Zach Fox on 2017-06-06 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 + +import "../styles-uit" + +Item { + id: rootSwitch; + + property int colorScheme: hifi.colorSchemes.light; + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light; + property int switchWidth: 100; + readonly property int switchRadius: 3; + property string offLabelText: ""; + property string onLabelText: ""; + property string switchLabelText: ""; + + Original.Switch { + id: originalSwitch; + activeFocusOnPress: true; + anchors.top: rootSwitch.top; + anchors.left: switchLabel.right; + anchors.leftMargin: 4; + + style: SwitchStyle { + groove: Rectangle { + implicitWidth: rootSwitch.switchWidth; + implicitHeight: rootSwitch.height; + radius: rootSwitch.switchRadius; + border.color: control.activeFocus ? "darkblue" : "gray"; + border.width: 1; + } + + handle: Rectangle { + opacity: rootSwitch.enabled ? 1.0 : 0.5 + implicitWidth: rootSwitch.height - 5; + implicitHeight: implicitWidth; + radius: implicitWidth/2; + border.color: hifi.colors.primaryHighlight; + } + } + } + + MouseArea { + anchors.fill: parent; + onClicked: { + originalSwitch.checked = !originalSwitch.checked; + } + } +} diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index f677efa347..d57315424a 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -20,13 +20,12 @@ import "../controls" as HifiControls // references HMD, XXX from root context Rectangle { + HifiConstants { id: hifi; } + id: spectatorCamera; // Size // Style - color: "#FFFFFF"; - // Properties - - HifiConstants { id: hifi; } + color: hifi.colors.baseGray; // // TITLE BAR START @@ -50,7 +49,7 @@ Rectangle { anchors.fill: parent; anchors.leftMargin: 16; // Style - color: hifi.colors.darkGray; + color: hifi.colors.lightGrayText; // Alignment horizontalAlignment: Text.AlignHLeft; verticalAlignment: Text.AlignVCenter; @@ -91,34 +90,34 @@ Rectangle { // Size width: 20; height: parent.height; - size: 48; + size: 60; // Anchors anchors.left: parent.left; - anchors.leftMargin: 45; + anchors.leftMargin: 20; anchors.top: parent.top; anchors.topMargin: 0; // Style - color: hifi.colors.blueAccent; + color: hifi.colors.lightGrayText; horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; + verticalAlignment: Text.AlignTop; } // "Spectator" app description text - RalewaySemiBold { + RalewayLight { id: spectatorDescriptionText; - text: "Spectator lets you switch what your monitor displays while you're using an HMD."; + text: "Spectator lets you switch what your monitor displays while you're using an HMD. Use Spectator to stream and record video."; // Text size size: 14; // Size - width: parent.width - 90 - 60; + width: 350; height: paintedHeight; // Anchors anchors.top: parent.top; anchors.topMargin: 10; anchors.left: spectatorDescriptionGlyph.right; - anchors.leftMargin: 30; + anchors.leftMargin: 40; // Style - color: hifi.colors.darkGray; + color: hifi.colors.lightGrayText; wrapMode: Text.WordWrap; // Alignment horizontalAlignment: Text.AlignHLeft; @@ -187,16 +186,15 @@ Rectangle { anchors.top: spectatorDescriptionContainer.bottom; anchors.topMargin: 20; anchors.left: parent.left; - anchors.leftMargin: 40; + anchors.leftMargin: 25; anchors.right: parent.right; - anchors.rightMargin: 40; + anchors.rightMargin: anchors.leftMargin; // "Camera On" Checkbox HifiControlsUit.CheckBox { id: cameraToggleCheckBox; anchors.left: parent.left; anchors.top: parent.top; - //checked: true; // FIXME text: "Camera On"; boxSize: 30; onClicked: { @@ -204,7 +202,7 @@ Rectangle { } } - // Preview + // Spectator Camera Preview Image { id: spectatorCameraPreview; height: 300; @@ -217,6 +215,46 @@ Rectangle { verticalAlignment: Image.AlignVCenter; source: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; } + + // "Monitor Shows" Switch Label + RalewayLight { + id: monitorShowsSwitchLabel; + text: "MONITOR SHOWS"; + anchors.top: spectatorCameraPreview.bottom; + anchors.topMargin: 20; + anchors.left: parent.left; + size: 16; + width: paintedWidth; + height: paintedHeight; + color: hifi.colors.lightGrayText; + verticalAlignment: Text.AlignVCenter; + } + // "Monitor Shows" Switch + HifiControlsUit.Switch { + id: monitorShowsSwitch; + height: 34; + anchors.left: parent.left; + anchors.right: parent.right; + anchors.top: monitorShowsSwitchLabel.bottom; + anchors.topMargin: 10; + switchLabelText: "Monitor Shows:"; + //onClicked: { + // sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showMyViewOnMonitor')}); + //} + } + + // "Switch View From Controller" Checkbox + HifiControlsUit.CheckBox { + id: switchViewFromControllerCheckBox; + anchors.left: parent.left; + anchors.top: monitorShowsSwitch.bottom; + anchors.topMargin: 20; + text: "Pressing Vive's Left Thumbpad Switches Monitor View"; + boxSize: 30; + onClicked: { + sendToScript({method: 'changeSwitchViewFromControllerPreference', params: checked}); + } + } } // // SPECTATOR CONTROLS END diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 88d2a9ebc1..3f855906e5 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -285,6 +285,15 @@ case 'disableSpectatorCamera': disableSpectatorCamera(); break; + case 'showCameraViewOnMonitor': + print('FIXME: showCameraViewOnMonitor'); + break; + case 'showMyViewOnMonitor': + print('FIXME: showMyViewOnMonitor'); + break; + case 'changeSwitchViewFromControllerPreference': + print('FIXME: Preference is now: ' + message.params); + break; default: print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); } From afb7e72b25cc152fcfcadaa5e432bf8a6f21aed0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 13:51:07 -0700 Subject: [PATCH 16/79] Separator; Switch.qml updates; etc --- .../resources/qml/controls-uit/Separator.qml | 38 ++++++ .../resources/qml/controls-uit/Switch.qml | 128 +++++++++++++++--- .../resources/qml/hifi/SpectatorCamera.qml | 62 +++++---- 3 files changed, 184 insertions(+), 44 deletions(-) create mode 100644 interface/resources/qml/controls-uit/Separator.qml diff --git a/interface/resources/qml/controls-uit/Separator.qml b/interface/resources/qml/controls-uit/Separator.qml new file mode 100644 index 0000000000..5a775221f6 --- /dev/null +++ b/interface/resources/qml/controls-uit/Separator.qml @@ -0,0 +1,38 @@ +// +// Separator.qml +// +// Created by Zach Fox on 2017-06-06 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import "../styles-uit" + +Item { + // Size + height: 2; + Rectangle { + // Size + width: parent.width; + height: 1; + // Anchors + anchors.left: parent.left; + anchors.bottom: parent.bottom; + anchors.bottomMargin: height; + // Style + color: hifi.colors.baseGrayShadow; + } + Rectangle { + // Size + width: parent.width; + height: 1; + // Anchors + anchors.left: parent.left; + anchors.bottom: parent.bottom; + // Style + color: hifi.colors.baseGrayHighlight; + } +} diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml index 6db38b054d..4659224391 100644 --- a/interface/resources/qml/controls-uit/Switch.qml +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -19,42 +19,138 @@ Item { property int colorScheme: hifi.colorSchemes.light; readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light; - property int switchWidth: 100; - readonly property int switchRadius: 3; - property string offLabelText: ""; - property string onLabelText: ""; - property string switchLabelText: ""; + property int switchWidth: 70; + readonly property int switchRadius: height/2; + property string labelTextOff: ""; + property string labelGlyphOffText: ""; + property int labelGlyphOffSize: 32; + property string labelTextOn: ""; + property string labelGlyphOnText: ""; + property int labelGlyphOnSize: 32; + property alias checked: originalSwitch.checked; + signal onCheckedChanged; + signal clicked; Original.Switch { id: originalSwitch; activeFocusOnPress: true; anchors.top: rootSwitch.top; - anchors.left: switchLabel.right; - anchors.leftMargin: 4; + anchors.left: rootSwitch.left; + anchors.leftMargin: rootSwitch.width/2 - rootSwitch.switchWidth/2; + onCheckedChanged: rootSwitch.onCheckedChanged(); + onClicked: rootSwitch.clicked(); style: SwitchStyle { + + padding { + top: 3; + left: 3; + right: 3; + bottom: 3; + } + groove: Rectangle { + color: hifi.colors.darkGray; implicitWidth: rootSwitch.switchWidth; implicitHeight: rootSwitch.height; radius: rootSwitch.switchRadius; - border.color: control.activeFocus ? "darkblue" : "gray"; - border.width: 1; } handle: Rectangle { - opacity: rootSwitch.enabled ? 1.0 : 0.5 - implicitWidth: rootSwitch.height - 5; + id: switchHandle; + implicitWidth: rootSwitch.height - padding.top - padding.bottom; implicitHeight: implicitWidth; radius: implicitWidth/2; - border.color: hifi.colors.primaryHighlight; + border.color: hifi.colors.lightGrayText; + color: hifi.colors.lightGray; + + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: parent.color = hifi.colors.blueHighlight; + onExited: parent.color = hifi.colors.lightGray; + } } } } - MouseArea { - anchors.fill: parent; - onClicked: { - originalSwitch.checked = !originalSwitch.checked; + // OFF Label + Item { + anchors.right: originalSwitch.left; + anchors.rightMargin: 10; + anchors.top: rootSwitch.top; + height: rootSwitch.height; + + RalewaySemiBold { + id: labelOff; + text: labelTextOff; + size: hifi.fontSizes.inputLabel; + color: hifi.colors.lightGrayText; + anchors.top: parent.top; + anchors.right: parent.right; + width: paintedWidth; + height: parent.height; + verticalAlignment: Text.AlignVCenter; + } + + HiFiGlyphs { + id: labelGlyphOff; + text: labelGlyphOffText; + size: labelGlyphOffSize; + color: hifi.colors.lightGrayText; + anchors.top: parent.top; + anchors.topMargin: 2; + anchors.right: labelOff.left; + anchors.rightMargin: 4; + } + + MouseArea { + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.left: labelGlyphOff.left; + anchors.right: labelOff.right; + onClicked: { + originalSwitch.checked = false; + } + } + } + + // ON Label + Item { + anchors.left: originalSwitch.right; + anchors.leftMargin: 10; + anchors.top: rootSwitch.top; + height: rootSwitch.height; + + RalewaySemiBold { + id: labelOn; + text: labelTextOn; + size: hifi.fontSizes.inputLabel; + color: hifi.colors.lightGrayText; + anchors.top: parent.top; + anchors.left: parent.left; + width: paintedWidth; + height: parent.height; + verticalAlignment: Text.AlignVCenter; + } + + HiFiGlyphs { + id: labelGlyphOn; + text: labelGlyphOnText; + size: labelGlyphOnSize; + color: hifi.colors.lightGrayText; + anchors.top: parent.top; + anchors.left: labelOn.right; + } + + MouseArea { + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.left: labelOn.left; + anchors.right: labelGlyphOn.right; + onClicked: { + originalSwitch.checked = true; + } } } } diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index d57315424a..0d3642d8c7 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -23,7 +23,6 @@ Rectangle { HifiConstants { id: hifi; } id: spectatorCamera; - // Size // Style color: hifi.colors.baseGray; @@ -40,7 +39,7 @@ Rectangle { anchors.top: parent.top; // "Spectator" text - RalewayRegular { + RalewaySemiBold { id: titleBarText; text: "Spectator"; // Text size @@ -56,15 +55,10 @@ Rectangle { } // Separator - Rectangle { - // Size - width: parent.width; - height: 1; - // Anchors + HifiControlsUit.Separator { anchors.left: parent.left; + anchors.right: parent.right; anchors.bottom: parent.bottom; - // Style - color: hifi.colors.faintGray; } } // @@ -113,7 +107,7 @@ Rectangle { height: paintedHeight; // Anchors anchors.top: parent.top; - anchors.topMargin: 10; + anchors.topMargin: 15; anchors.left: spectatorDescriptionGlyph.right; anchors.leftMargin: 40; // Style @@ -158,16 +152,11 @@ Rectangle { } // Separator - Rectangle { - // Size - width: parent.width; - height: 1; - // Anchors + HifiControlsUit.Separator { anchors.left: parent.left; + anchors.right: parent.right; anchors.top: spectatorLearnMoreText.bottom; anchors.topMargin: spectatorDescriptionText.anchors.topMargin; - // Style - color: hifi.colors.faintGray; } } // @@ -193,10 +182,11 @@ Rectangle { // "Camera On" Checkbox HifiControlsUit.CheckBox { id: cameraToggleCheckBox; + colorScheme: hifi.colorSchemes.dark; anchors.left: parent.left; anchors.top: parent.top; text: "Camera On"; - boxSize: 30; + boxSize: 24; onClicked: { sendToScript({method: (checked ? 'enableSpectatorCamera' : 'disableSpectatorCamera')}); } @@ -205,7 +195,7 @@ Rectangle { // Spectator Camera Preview Image { id: spectatorCameraPreview; - height: 300; + height: 250; anchors.left: parent.left; anchors.top: cameraToggleCheckBox.bottom; anchors.topMargin: 20; @@ -216,13 +206,24 @@ Rectangle { source: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; } + // "Monitor Shows" Switch Label Glyph + HiFiGlyphs { + id: monitorShowsSwitchLabelGlyph; + text: hifi.glyphs.screen; + size: 32; + color: hifi.colors.blueHighlight; + anchors.top: spectatorCameraPreview.bottom; + anchors.topMargin: 12; + anchors.left: parent.left; + } // "Monitor Shows" Switch Label RalewayLight { id: monitorShowsSwitchLabel; - text: "MONITOR SHOWS"; + text: "MONITOR SHOWS:"; anchors.top: spectatorCameraPreview.bottom; anchors.topMargin: 20; - anchors.left: parent.left; + anchors.left: monitorShowsSwitchLabelGlyph.right; + anchors.leftMargin: 6; size: 16; width: paintedWidth; height: paintedHeight; @@ -232,25 +233,30 @@ Rectangle { // "Monitor Shows" Switch HifiControlsUit.Switch { id: monitorShowsSwitch; - height: 34; + height: 30; anchors.left: parent.left; anchors.right: parent.right; anchors.top: monitorShowsSwitchLabel.bottom; anchors.topMargin: 10; - switchLabelText: "Monitor Shows:"; - //onClicked: { - // sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showMyViewOnMonitor')}); - //} + labelTextOff: "HMD Preview"; + labelGlyphOffText: hifi.glyphs.hmd; + labelGlyphOffSize: 26; + labelTextOn: "Camera View"; + labelGlyphOnText: hifi.glyphs.alert; + onCheckedChanged: { + sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showMyViewOnMonitor')}); + } } // "Switch View From Controller" Checkbox HifiControlsUit.CheckBox { id: switchViewFromControllerCheckBox; + colorScheme: hifi.colorSchemes.dark; anchors.left: parent.left; anchors.top: monitorShowsSwitch.bottom; - anchors.topMargin: 20; + anchors.topMargin: 25; text: "Pressing Vive's Left Thumbpad Switches Monitor View"; - boxSize: 30; + boxSize: 24; onClicked: { sendToScript({method: 'changeSwitchViewFromControllerPreference', params: checked}); } From ca05e3d0b61e56216c907452a83c3a94da705ab0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 14:17:38 -0700 Subject: [PATCH 17/79] Improvements to switch; switch settings persist --- interface/resources/qml/controls-uit/Switch.qml | 8 ++++---- interface/resources/qml/hifi/SpectatorCamera.qml | 7 +++++-- scripts/system/spectatorCamera.js | 9 ++++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml index 4659224391..c8a566de4b 100644 --- a/interface/resources/qml/controls-uit/Switch.qml +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -85,7 +85,7 @@ Item { id: labelOff; text: labelTextOff; size: hifi.fontSizes.inputLabel; - color: hifi.colors.lightGrayText; + color: originalSwitch.checked ? hifi.colors.lightGrayText : hifi.colors.faintGray; anchors.top: parent.top; anchors.right: parent.right; width: paintedWidth; @@ -97,7 +97,7 @@ Item { id: labelGlyphOff; text: labelGlyphOffText; size: labelGlyphOffSize; - color: hifi.colors.lightGrayText; + color: labelOff.color; anchors.top: parent.top; anchors.topMargin: 2; anchors.right: labelOff.left; @@ -126,7 +126,7 @@ Item { id: labelOn; text: labelTextOn; size: hifi.fontSizes.inputLabel; - color: hifi.colors.lightGrayText; + color: originalSwitch.checked ? hifi.colors.faintGray : hifi.colors.lightGrayText; anchors.top: parent.top; anchors.left: parent.left; width: paintedWidth; @@ -138,7 +138,7 @@ Item { id: labelGlyphOn; text: labelGlyphOnText; size: labelGlyphOnSize; - color: hifi.colors.lightGrayText; + color: labelOn.color; anchors.top: parent.top; anchors.left: labelOn.right; } diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 0d3642d8c7..d23897a415 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -99,7 +99,7 @@ Rectangle { // "Spectator" app description text RalewayLight { id: spectatorDescriptionText; - text: "Spectator lets you switch what your monitor displays while you're using an HMD. Use Spectator to stream and record video."; + text: "Spectator lets you change what your monitor displays while you're using an HMD. Use Spectator when streaming and recording video."; // Text size size: 14; // Size @@ -244,7 +244,7 @@ Rectangle { labelTextOn: "Camera View"; labelGlyphOnText: hifi.glyphs.alert; onCheckedChanged: { - sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showMyViewOnMonitor')}); + sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showHmdPreviewOnMonitor')}); } } @@ -287,6 +287,9 @@ Rectangle { case 'updateSpectatorCameraCheckbox': cameraToggleCheckBox.checked = message.params; break; + case 'updateMonitorShowsSwitch': + monitorShowsSwitch.checked = message.params; + break; default: console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); } diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 3f855906e5..1d07f8f03e 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -223,6 +223,7 @@ tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); + sendToQml({ method: 'updateMonitorShowsSwitch', params: !!Settings.getValue('spectatorCamera/monitorShowsCameraView', false) }); } } @@ -285,11 +286,13 @@ case 'disableSpectatorCamera': disableSpectatorCamera(); break; + case 'showHmdPreviewOnMonitor': + print('FIXME: showHmdPreviewOnMonitor'); + Settings.setValue('spectatorCamera/monitorShowsCameraView', false); + break; case 'showCameraViewOnMonitor': print('FIXME: showCameraViewOnMonitor'); - break; - case 'showMyViewOnMonitor': - print('FIXME: showMyViewOnMonitor'); + Settings.setValue('spectatorCamera/monitorShowsCameraView', true); break; case 'changeSwitchViewFromControllerPreference': print('FIXME: Preference is now: ' + message.params); From b50cf6cee6fe10a573cbc3de989a6f3e0dccab43 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 14:50:01 -0700 Subject: [PATCH 18/79] Quick feedback from Alan --- interface/resources/qml/controls-uit/Switch.qml | 6 +++--- interface/resources/qml/hifi/SpectatorCamera.qml | 2 -- interface/resources/qml/styles-uit/HifiConstants.qml | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml index c8a566de4b..d54f986717 100644 --- a/interface/resources/qml/controls-uit/Switch.qml +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -50,7 +50,7 @@ Item { } groove: Rectangle { - color: hifi.colors.darkGray; + color: "#252525"; implicitWidth: rootSwitch.switchWidth; implicitHeight: rootSwitch.height; radius: rootSwitch.switchRadius; @@ -85,7 +85,7 @@ Item { id: labelOff; text: labelTextOff; size: hifi.fontSizes.inputLabel; - color: originalSwitch.checked ? hifi.colors.lightGrayText : hifi.colors.faintGray; + color: originalSwitch.checked ? hifi.colors.lightGrayText : "#FFFFFF"; anchors.top: parent.top; anchors.right: parent.right; width: paintedWidth; @@ -126,7 +126,7 @@ Item { id: labelOn; text: labelTextOn; size: hifi.fontSizes.inputLabel; - color: originalSwitch.checked ? hifi.colors.faintGray : hifi.colors.lightGrayText; + color: originalSwitch.checked ? "#FFFFFF" : hifi.colors.lightGrayText; anchors.top: parent.top; anchors.left: parent.left; width: paintedWidth; diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index d23897a415..66b0718d19 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -239,8 +239,6 @@ Rectangle { anchors.top: monitorShowsSwitchLabel.bottom; anchors.topMargin: 10; labelTextOff: "HMD Preview"; - labelGlyphOffText: hifi.glyphs.hmd; - labelGlyphOffSize: 26; labelTextOn: "Camera View"; labelGlyphOnText: hifi.glyphs.alert; onCheckedChanged: { diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 7b6efbd573..1bd3891001 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -50,7 +50,7 @@ Item { id: colors // Base colors - readonly property color baseGray: "#404040" + readonly property color baseGray: "#393939" readonly property color darkGray: "#121212" readonly property color baseGrayShadow: "#252525" readonly property color baseGrayHighlight: "#575757" From 383ef542a1db28c9ffd3c2c4b987d45c7174261e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 14:59:26 -0700 Subject: [PATCH 19/79] Remove 'debugSelfie.js'; Change 'HMD' to 'VR headset' --- .../resources/qml/hifi/SpectatorCamera.qml | 2 +- .../developer/utilities/render/debugSelfie.js | 70 ------------------- 2 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 scripts/developer/utilities/render/debugSelfie.js diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 66b0718d19..94d9f59d40 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -99,7 +99,7 @@ Rectangle { // "Spectator" app description text RalewayLight { id: spectatorDescriptionText; - text: "Spectator lets you change what your monitor displays while you're using an HMD. Use Spectator when streaming and recording video."; + text: "Spectator lets you change what your monitor displays while you're using a VR headset. Use Spectator when streaming and recording video."; // Text size size: 14; // Size diff --git a/scripts/developer/utilities/render/debugSelfie.js b/scripts/developer/utilities/render/debugSelfie.js deleted file mode 100644 index 0105700109..0000000000 --- a/scripts/developer/utilities/render/debugSelfie.js +++ /dev/null @@ -1,70 +0,0 @@ -function inFrontOf(distance, position, orientation) { - return Vec3.sum(position || MyAvatar.position, - Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); -} -var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); -function flip(rotation) { return Quat.multiply(rotation, aroundY); } -// Specifying the following userData makes the camera near-grabbable in HMD. -// We really want it to also be far-grabbable and mouse-grabbable, -// but that requires dynamic:1, but alas that causes the camera to drift -// when let go. Maybe we'll restore the old "zero velocity on release" code -// to (handController)grab.js, and also make the camera collisionless? -var isDynamic = false; - -var viewFinderOverlay, camera = Entities.addEntity({ - type: 'Box', - dimensions: {x: 0.4, y: 0.2, z: 0.4}, - userData: '{"grabbableKey":{"grabbable":true}}', - dynamic: isDynamic ? 1 : 0, - color: {red: 255, green: 0, blue: 0}, - name: 'SpectatorCamera' -}); // FIXME: avatar entity so that you don't need rez rights. - -var config = Render.getConfig("SelfieFrame"); -var config2 = Render.getConfig("BeginSelfie"); -function updateRenderFromCamera() { - var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); - // FIXME: don't muck with config if properties haven't changed. - config2.position = cameraData.position; - config2.orientation = cameraData.rotation; - // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object - if (isDynamic) { - Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); - } -} -Script.setTimeout(function () { // delay for a bit in case this script is running at startup - // Set the special texture size based on the window in which it will eventually be displayed. - var size = Controller.getViewportDimensions(); - config.resetSize(size.x, size.y); - Script.update.connect(updateRenderFromCamera); - config.enabled = config2.enabled = true; - Script.setTimeout(function () { // FIXME: do we need this delay? why? - var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); - // Put the camera in front of me so that I can find it. - Entities.editEntity(camera, { - position: cameraPosition, - rotation: cameraRotation - }); - // Put an image3d overlay on the near face, as a viewFinder. - viewFinderOverlay = Overlays.addOverlay("image3d", { - url: "http://selfieFrame", - //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", - parentID: camera, - alpha: 1, - position: inFrontOf(-0.25, cameraPosition, cameraRotation), - // FIXME: We shouldn't need the flip and the negative scale. - // e.g., This isn't necessary using an ordinary .jpg with lettering, above. - // Must be something about the view frustum projection matrix? - // But don't go changing that in (c++ code) without getting all the way to a desktop display! - orientation: flip(cameraRotation), - scale: -0.35, - }); - }, 500); -}, 1000); - -Script.scriptEnding.connect(function () { - config.enabled = config2.enabled = false; - Script.update.disconnect(updateRenderFromCamera); - Overlays.deleteOverlay(viewFinderOverlay); - Entities.deleteEntity(camera); -}) From 6e9b083be111ef5aeb49930a63c06298ce6877e4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 15:49:15 -0700 Subject: [PATCH 20/79] Function renaming; turn cam off when changing domains --- .../resources/qml/hifi/SpectatorCamera.qml | 2 +- scripts/system/spectatorCamera.js | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 94d9f59d40..fa19a4b371 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -188,7 +188,7 @@ Rectangle { text: "Camera On"; boxSize: 24; onClicked: { - sendToScript({method: (checked ? 'enableSpectatorCamera' : 'disableSpectatorCamera')}); + sendToScript({method: (checked ? 'spectatorCameraOn' : 'spectatorCameraOff')}); } } diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 1d07f8f03e..ec3bc3c46c 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -66,7 +66,7 @@ } // - // Function Name: enableSpectatorCamera() + // Function Name: spectatorCameraOn() // // Relevant Variables: // isUpdateRenderWired: Bool storing whether or not the camera's update @@ -80,7 +80,7 @@ // spawn the camera entity. // var isUpdateRenderWired = false; - function enableSpectatorCamera() { + function spectatorCameraOn() { // Set the special texture size based on the window in which it will eventually be displayed. var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. spectatorFrameRenderConfig.resetSize(size.x, size.y); @@ -115,7 +115,7 @@ } // - // Function Name: disableSpectatorCamera() + // Function Name: spectatorCameraOff() // // Relevant Variables: // None @@ -127,20 +127,21 @@ // Call this function to shut down the spectator camera and // destroy the camera entity. // - function disableSpectatorCamera() { + function spectatorCameraOff() { spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = false; if (isUpdateRenderWired) { Script.update.disconnect(updateRenderFromCamera); isUpdateRenderWired = false; } - if (viewFinderOverlay) { - Overlays.deleteOverlay(viewFinderOverlay); - viewFinderOverlay = false; - } if (camera) { Entities.deleteEntity(camera); - camera = false; + print("ZACH FOX GOODBYE"); } + if (viewFinderOverlay) { + Overlays.deleteOverlay(viewFinderOverlay); + } + camera = false; + viewFinderOverlay = false; } // @@ -167,6 +168,7 @@ }); button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); + Window.domainChanged.connect(spectatorCameraOff); viewFinderOverlay = false; camera = false; } @@ -280,11 +282,11 @@ // function fromQml(message) { switch (message.method) { - case 'enableSpectatorCamera': - enableSpectatorCamera(); + case 'spectatorCameraOn': + spectatorCameraOn(); break; - case 'disableSpectatorCamera': - disableSpectatorCamera(); + case 'spectatorCameraOff': + spectatorCameraOff(); break; case 'showHmdPreviewOnMonitor': print('FIXME: showHmdPreviewOnMonitor'); @@ -315,7 +317,8 @@ // shutdown() will be called when the script ends (i.e. is stopped). // function shutdown() { - disableSpectatorCamera(); + spectatorCameraOff(); + Window.domainChanged.disconnect(spectatorCameraOff); tablet.removeButton(button); button.clicked.disconnect(onTabletButtonClicked); tablet.screenChanged.disconnect(onTabletScreenChanged); From a30b678ecbe18e7533c3e50b4531422b14859cab Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 16:27:58 -0700 Subject: [PATCH 21/79] No more dynamic camera...for now. --- scripts/system/spectatorCamera.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index ec3bc3c46c..b39b203817 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -44,6 +44,8 @@ // render job. Controls position and orientation. // viewFinderOverlay: The in-world overlay that displays the spectator camera's view. // camera: The in-world entity that corresponds to the spectator camera. + // cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays + // drift with respect to their parent // // Arguments: // None @@ -56,13 +58,16 @@ var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSelfie"); var viewFinderOverlay = false; var camera = false; + var cameraIsDynamic = false; function updateRenderFromCamera() { var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); // FIXME: don't muck with config if properties haven't changed. beginSpectatorFrameRenderConfig.position = cameraData.position; beginSpectatorFrameRenderConfig.orientation = cameraData.rotation; - // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object - Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); + if (cameraIsDynamic) { + // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object + Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); + } } // @@ -92,7 +97,7 @@ type: 'Box', dimensions: { x: 0.4, y: 0.2, z: 0.4 }, userData: '{"grabbableKey":{"grabbable":true}}', - dynamic: true, + dynamic: cameraIsDynamic, color: { red: 255, green: 0, blue: 0 }, name: 'SpectatorCamera', position: cameraPosition, // Put the camera in front of me so that I can find it. From cbeea7abc430cd8a818810e3fe93146d453f1e35 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 6 Jun 2017 16:37:25 -0700 Subject: [PATCH 22/79] Make the camera an avatar entity --- scripts/system/spectatorCamera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index b39b203817..6f676ef632 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -102,7 +102,7 @@ name: 'SpectatorCamera', position: cameraPosition, // Put the camera in front of me so that I can find it. rotation: cameraRotation - }); // FIXME: avatar entity so that you don't need rez rights.; + }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { url: "http://selfieFrame", From 51982b12948bc7fcbdcd52e801f3d1d9bb9ba36e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 7 Jun 2017 14:39:18 -0700 Subject: [PATCH 23/79] display textures in plugins --- .../scripting/WindowScriptingInterface.cpp | 5 +++ .../src/scripting/WindowScriptingInterface.h | 1 + .../display-plugins/OpenGLDisplayPlugin.cpp | 36 ++++++++++++++----- .../src/display-plugins/OpenGLDisplayPlugin.h | 3 ++ .../display-plugins/hmd/HmdDisplayPlugin.cpp | 30 ++++++---------- libraries/plugins/src/plugins/DisplayPlugin.h | 3 ++ 6 files changed, 50 insertions(+), 28 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 1e14c24da3..38f467f22b 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -284,6 +284,11 @@ void WindowScriptingInterface::copyToClipboard(const QString& text) { QApplication::clipboard()->setText(text); } + +bool WindowScriptingInterface::setDisplayTexture(const QString& name) { + return qApp->getActiveDisplayPlugin()->setDisplayTexture(name); // Plugins that don't know how, answer false. +} + void WindowScriptingInterface::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) { qApp->takeSnapshot(notify, includeAnimated, aspectRatio); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 2b1e48d918..4fb4829636 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -62,6 +62,7 @@ public slots: void displayAnnouncement(const QString& message); void shareSnapshot(const QString& path, const QUrl& href = QUrl("")); bool isPhysicsEnabled(); + bool setDisplayTexture(const QString& name); int openMessageBox(QString title, QString text, int buttons, int defaultButton); void updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index bfd158ffb5..25c238be6d 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -496,6 +496,17 @@ void OpenGLDisplayPlugin::submitFrame(const gpu::FramePointer& newFrame) { _newFrameQueue.push(newFrame); }); } +void OpenGLDisplayPlugin::renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor) { + batch.enableStereo(false); + batch.resetViewTransform(); + batch.setFramebuffer(gpu::FramebufferPointer()); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0)); + batch.setStateScissorRect(scissor); + batch.setViewportTransform(viewport); + batch.setResourceTexture(0, texture); + batch.setPipeline(_presentPipeline); + batch.draw(gpu::TRIANGLE_STRIP, 4); +} void OpenGLDisplayPlugin::updateFrameData() { PROFILE_RANGE(render, __FUNCTION__) @@ -605,14 +616,9 @@ void OpenGLDisplayPlugin::compositeLayers() { void OpenGLDisplayPlugin::internalPresent() { render([&](gpu::Batch& batch) { - batch.enableStereo(false); - batch.resetViewTransform(); - batch.setFramebuffer(gpu::FramebufferPointer()); - batch.setViewportTransform(ivec4(uvec2(0), getSurfacePixels())); - batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0)); - batch.setPipeline(_presentPipeline); - batch.draw(gpu::TRIANGLE_STRIP, 4); - }); + auto viewport = ivec4(uvec2(0), getSurfacePixels()); + renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport, viewport); + }); swapBuffers(); _presentRate.increment(); } @@ -694,6 +700,20 @@ void OpenGLDisplayPlugin::withMainThreadContext(std::function f) const { _container->makeRenderingContextCurrent(); } +bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { + if (name.isEmpty()) { + _displayTexture.reset(); + return true; + } + auto textureCache = DependencyManager::get(); + auto networkTexture = textureCache->getTexture(name); + if (!networkTexture) { + return false; + } + _displayTexture = networkTexture->getGPUTexture(); + return !!_displayTexture; +} + QImage OpenGLDisplayPlugin::getScreenshot(float aspectRatio) const { auto size = _compositeFramebuffer->getSize(); if (isHmd()) { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 10a7558398..cf874fb721 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -57,6 +57,7 @@ public: return getSurfaceSize(); } + virtual bool setDisplayTexture(const QString& name) override; QImage getScreenshot(float aspectRatio = 0.0f) const override; float presentRate() const override; @@ -109,6 +110,7 @@ protected: // Plugin specific functionality to send the composed scene to the output window or device virtual void internalPresent(); + void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor); virtual void updateFrameData(); void withMainThreadContext(std::function f) const; @@ -134,6 +136,7 @@ protected: gpu::PipelinePointer _simplePipeline; gpu::PipelinePointer _presentPipeline; gpu::PipelinePointer _cursorPipeline; + gpu::TexturePointer _displayTexture{}; float _compositeOverlayAlpha { 1.0f }; struct CursorData { diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index cab96c258b..3cceb632fc 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include "../Logging.h" @@ -211,7 +212,13 @@ void HmdDisplayPlugin::internalPresent() { // Composite together the scene, overlay and mouse cursor hmdPresent(); - if (!_disablePreview) { + if (_displayTexture) { + auto viewport = getViewportForSourceSize(uvec2(_displayTexture->getDimensions())); + render([&](gpu::Batch& batch) { + renderFromTexture(batch, _displayTexture, viewport, viewport); + }); + swapBuffers(); + } else if (!_disablePreview) { // screen preview mirroring auto sourceSize = _renderTargetSize; if (_monoPreview) { @@ -272,16 +279,7 @@ void HmdDisplayPlugin::internalPresent() { viewport.z *= 2; } - - batch.enableStereo(false); - batch.resetViewTransform(); - batch.setFramebuffer(gpu::FramebufferPointer()); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0)); - batch.setStateScissorRect(scissor); // was viewport - batch.setViewportTransform(viewport); - batch.setResourceTexture(0, _compositeFramebuffer->getRenderBuffer(0)); - batch.setPipeline(_presentPipeline); - batch.draw(gpu::TRIANGLE_STRIP, 4); + renderFromTexture(batch, _compositeFramebuffer->getRenderBuffer(0), viewport, scissor); }); swapBuffers(); } else if (_clearPreviewFlag) { @@ -310,15 +308,7 @@ void HmdDisplayPlugin::internalPresent() { auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions())); render([&](gpu::Batch& batch) { - batch.enableStereo(false); - batch.resetViewTransform(); - batch.setFramebuffer(gpu::FramebufferPointer()); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(0)); - batch.setStateScissorRect(viewport); - batch.setViewportTransform(viewport); - batch.setResourceTexture(0, _previewTexture); - batch.setPipeline(_presentPipeline); - batch.draw(gpu::TRIANGLE_STRIP, 4); + renderFromTexture(batch, _previewTexture, viewport, viewport); }); _clearPreviewFlag = false; swapBuffers(); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 297bdb2cca..7bfdbddbc5 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -184,6 +184,9 @@ public: // will query the underlying hmd api to compute the most recent head pose virtual bool beginFrameRender(uint32_t frameIndex) { return true; } + // Set the texture to display on the monitor and return true, if allowed. Empty string resets. + virtual bool setDisplayTexture(const QString& name) { return false; } + virtual float devicePixelRatio() { return 1.0f; } // Rate at which we render frames virtual float renderRate() const { return -1.0f; } From bc1eb5c4a3f4a241845977b25c472b594e6b7c80 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 7 Jun 2017 16:18:04 -0700 Subject: [PATCH 24/79] sizing --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 3 ++- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 25c238be6d..84724a22d8 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -616,7 +616,8 @@ void OpenGLDisplayPlugin::compositeLayers() { void OpenGLDisplayPlugin::internalPresent() { render([&](gpu::Batch& batch) { - auto viewport = ivec4(uvec2(0), getSurfacePixels()); + uvec2 dims = _displayTexture ? uvec2(_displayTexture->getDimensions()) : getSurfacePixels(); + auto viewport = ivec4(uvec2(0), dims); renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport, viewport); }); swapBuffers(); diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 3cceb632fc..96d12a7f70 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -213,7 +213,8 @@ void HmdDisplayPlugin::internalPresent() { hmdPresent(); if (_displayTexture) { - auto viewport = getViewportForSourceSize(uvec2(_displayTexture->getDimensions())); + uvec2 dims = uvec2(_displayTexture->getDimensions()); + auto viewport = ivec4(uvec2(0), dims); render([&](gpu::Batch& batch) { renderFromTexture(batch, _displayTexture, viewport, viewport); }); From 8db81ee5c9233307d88c9509034569c15a1aeb11 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 7 Jun 2017 16:19:36 -0700 Subject: [PATCH 25/79] wire up preview vs camera display in scripts --- .../resources/qml/hifi/SpectatorCamera.qml | 2 +- scripts/system/spectatorCamera.js | 28 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index fa19a4b371..544fc72927 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -242,7 +242,7 @@ Rectangle { labelTextOn: "Camera View"; labelGlyphOnText: hifi.glyphs.alert; onCheckedChanged: { - sendToScript({method: (checked ? 'showCameraViewOnMonitor' : 'showHmdPreviewOnMonitor')}); + sendToScript({method: 'setMonitorShowsCameraView', params: checked}); } } diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 6f676ef632..7224932130 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -205,6 +205,20 @@ } } + const CAMERA_PREVIEW_WHEN_OFF = "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; // FIXME instructions? + const MONITOR_SHOWS_CAMERA_VIEW_DEFAULT = false; + var monitorShowsCameraView = !!Settings.getValue('spectatorCamera/monitorShowsCameraView', MONITOR_SHOWS_CAMERA_VIEW_DEFAULT); + function setMonitorShowsCameraView(showCameraView) { + if (showCameraView === monitorShowsCameraView) { + return; + } + monitorShowsCameraView = showCameraView; + var url = showCameraView ? (isUpdateRenderWired ? "http://selfieFrame" : CAMERA_PREVIEW_WHEN_OFF) : ""; + print('setDisplayTexture', url, + Window.setDisplayTexture(url)); + Settings.setValue('spectatorCamera/monitorShowsCameraView', showCameraView); + } + // // Function Name: onTabletButtonClicked() // @@ -229,8 +243,9 @@ shouldActivateButton = true; tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; - sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); - sendToQml({ method: 'updateMonitorShowsSwitch', params: !!Settings.getValue('spectatorCamera/monitorShowsCameraView', false) }); + sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera });; + setMonitorShowsCameraView(monitorShowsCameraView); + sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView }); } } @@ -293,13 +308,8 @@ case 'spectatorCameraOff': spectatorCameraOff(); break; - case 'showHmdPreviewOnMonitor': - print('FIXME: showHmdPreviewOnMonitor'); - Settings.setValue('spectatorCamera/monitorShowsCameraView', false); - break; - case 'showCameraViewOnMonitor': - print('FIXME: showCameraViewOnMonitor'); - Settings.setValue('spectatorCamera/monitorShowsCameraView', true); + case 'setMonitorShowsCameraView': + setMonitorShowsCameraView(message.params); break; case 'changeSwitchViewFromControllerPreference': print('FIXME: Preference is now: ' + message.params); From d15657616a7b3dbb80a4ee2e7f1c4adeda09a627 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 8 Jun 2017 10:40:20 -0700 Subject: [PATCH 26/79] comments --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 8 +++++--- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 84724a22d8..ba8842c2ec 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -616,6 +616,7 @@ void OpenGLDisplayPlugin::compositeLayers() { void OpenGLDisplayPlugin::internalPresent() { render([&](gpu::Batch& batch) { + // Note: _displayTexture must currently be the same size as the display. uvec2 dims = _displayTexture ? uvec2(_displayTexture->getDimensions()) : getSurfacePixels(); auto viewport = ivec4(uvec2(0), dims); renderFromTexture(batch, _displayTexture ? _displayTexture : _compositeFramebuffer->getRenderBuffer(0), viewport, viewport); @@ -702,16 +703,17 @@ void OpenGLDisplayPlugin::withMainThreadContext(std::function f) const { } bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { + // Note: it is the caller's responsibility to keep the network texture in cache. if (name.isEmpty()) { _displayTexture.reset(); return true; } auto textureCache = DependencyManager::get(); - auto networkTexture = textureCache->getTexture(name); - if (!networkTexture) { + auto displayNetworkTexture = textureCache->getTexture(name); + if (!displayNetworkTexture) { return false; } - _displayTexture = networkTexture->getGPUTexture(); + _displayTexture = displayNetworkTexture->getGPUTexture(); return !!_displayTexture; } diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 96d12a7f70..b3797853f0 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -213,6 +213,7 @@ void HmdDisplayPlugin::internalPresent() { hmdPresent(); if (_displayTexture) { + // Note: _displayTexture must currently be the same size as the display. uvec2 dims = uvec2(_displayTexture->getDimensions()); auto viewport = ivec4(uvec2(0), dims); render([&](gpu::Batch& batch) { From ce2053e3b889c194bd867ccb6e1bec4d29d68f1f Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 8 Jun 2017 10:41:09 -0700 Subject: [PATCH 27/79] control-0 toggles display, and display itself only toggles when camera is on --- scripts/system/spectatorCamera.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 7224932130..2e27d5f364 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -174,6 +174,7 @@ button.clicked.connect(onTabletButtonClicked); tablet.screenChanged.connect(onTabletScreenChanged); Window.domainChanged.connect(spectatorCameraOff); + Controller.keyPressEvent.connect(keyPressEvent); viewFinderOverlay = false; camera = false; } @@ -213,11 +214,19 @@ return; } monitorShowsCameraView = showCameraView; - var url = showCameraView ? (isUpdateRenderWired ? "http://selfieFrame" : CAMERA_PREVIEW_WHEN_OFF) : ""; - print('setDisplayTexture', url, - Window.setDisplayTexture(url)); + var url = (showCameraView && isUpdateRenderWired) ? "http://selfieFrame" : ""; + Window.setDisplayTexture(url); Settings.setValue('spectatorCamera/monitorShowsCameraView', showCameraView); } + function setMonitorShowsCameraViewAndSendToQml(showCameraView) { + setMonitorShowsCameraView(showCameraView); + sendToQml({ method: 'updateMonitorShowsSwitch', params: showCameraView }); + } + function keyPressEvent(event) { + if ((event.text === "0") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && event.isControl && !event.isAlt) { + setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); + } + } // // Function Name: onTabletButtonClicked() @@ -243,9 +252,8 @@ shouldActivateButton = true; tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; - sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera });; - setMonitorShowsCameraView(monitorShowsCameraView); - sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView }); + sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); + setMonitorShowsCameraViewAndSendToQml(monitorShowsCameraView); } } @@ -337,6 +345,7 @@ tablet.removeButton(button); button.clicked.disconnect(onTabletButtonClicked); tablet.screenChanged.disconnect(onTabletScreenChanged); + Controller.keyPressEvent.disconnect(keyPressEvent); } // From df8287d6eee05182883b4b0f89b9e984e8a64104 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 8 Jun 2017 11:35:55 -0700 Subject: [PATCH 28/79] reset display texture as needed when switching camera or hmd --- scripts/system/spectatorCamera.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 2e27d5f364..44419d73ff 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -117,6 +117,7 @@ orientation: flip(cameraRotation), scale: -0.35, }); + setDisplay(monitorShowsCameraView); } // @@ -147,6 +148,12 @@ } camera = false; viewFinderOverlay = false; + setDisplay(monitorShowsCameraView); + } + + function onHMDChanged(isHMDMode) { + // Will also eventually enable disable app, camera, etc. + setDisplay(monitorShowsCameraView); } // @@ -175,6 +182,7 @@ tablet.screenChanged.connect(onTabletScreenChanged); Window.domainChanged.connect(spectatorCameraOff); Controller.keyPressEvent.connect(keyPressEvent); + HMD.displayModeChanged.connect(onHMDChanged); viewFinderOverlay = false; camera = false; } @@ -206,7 +214,11 @@ } } - const CAMERA_PREVIEW_WHEN_OFF = "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; // FIXME instructions? + function setDisplay(showCameraView) { + // It would be fancy if (showCameraView && !isUpdateRenderWired) would show instructions, but that's out of scope for now. + var url = (showCameraView && isUpdateRenderWired) ? "http://selfieFrame" : ""; + Window.setDisplayTexture(url); + } const MONITOR_SHOWS_CAMERA_VIEW_DEFAULT = false; var monitorShowsCameraView = !!Settings.getValue('spectatorCamera/monitorShowsCameraView', MONITOR_SHOWS_CAMERA_VIEW_DEFAULT); function setMonitorShowsCameraView(showCameraView) { @@ -214,8 +226,7 @@ return; } monitorShowsCameraView = showCameraView; - var url = (showCameraView && isUpdateRenderWired) ? "http://selfieFrame" : ""; - Window.setDisplayTexture(url); + setDisplay(showCameraView); Settings.setValue('spectatorCamera/monitorShowsCameraView', showCameraView); } function setMonitorShowsCameraViewAndSendToQml(showCameraView) { @@ -345,6 +356,7 @@ tablet.removeButton(button); button.clicked.disconnect(onTabletButtonClicked); tablet.screenChanged.disconnect(onTabletScreenChanged); + HMD.displayModeChanged.disconnect(onHMDChanged); Controller.keyPressEvent.disconnect(keyPressEvent); } From 32d83e375cf030adc000104142439cb264ea5440 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 8 Jun 2017 13:48:01 -0700 Subject: [PATCH 29/79] fix for avatar entities disappearing after grabbing and releasing --- .../src/avatars-renderer/Avatar.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index d78287a0e7..a0a348388e 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -288,6 +288,13 @@ void Avatar::updateAvatarEntities() { properties.setScript(noScript); } + // When grabbing avatar entities, they are parented to the joint moving them, then when un-grabbed + // they go back to the default parent (null uuid). When un-gripped, others saw the entity disappear. + // The thinking here is the local position was noticed as changing, but not the parentID (since it is now + // back to the default), and the entity flew off somewhere. Marking all changed definitely fixes this, + // and seems safe (per Seth). + properties.markAllChanged(); + // try to build the entity EntityItemPointer entity = entityTree->findEntityByEntityItemID(EntityItemID(entityID)); bool success = true; @@ -1067,15 +1074,15 @@ void Avatar::setModelURLFinished(bool success) { const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts if (_skeletonModel->getResourceDownloadAttemptsRemaining() <= 0 || _skeletonModel->getResourceDownloadAttempts() > MAX_SKELETON_DOWNLOAD_ATTEMPTS) { - qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL + qCWarning(avatars_renderer) << "Using default after failing to load Avatar model: " << _skeletonModelURL << "after" << _skeletonModel->getResourceDownloadAttempts() << "attempts."; // call _skeletonModel.setURL, but leave our copy of _skeletonModelURL alone. This is so that // we don't redo this every time we receive an identity packet from the avatar with the bad url. QMetaObject::invokeMethod(_skeletonModel.get(), "setURL", Qt::QueuedConnection, Q_ARG(QUrl, AvatarData::defaultFullAvatarModelUrl())); } else { - qCWarning(avatars_renderer) << "Avatar model: " << _skeletonModelURL - << "failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts() + qCWarning(avatars_renderer) << "Avatar model: " << _skeletonModelURL + << "failed to load... attempts:" << _skeletonModel->getResourceDownloadAttempts() << "out of:" << MAX_SKELETON_DOWNLOAD_ATTEMPTS; } } From 4c8eec4e16387e0b9a0c8de87324a204852e9e40 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 8 Jun 2017 17:38:26 -0700 Subject: [PATCH 30/79] Introducing a way to prevent a frame to render in stereo accross batches --- interface/src/PrototypeSelfie.cpp | 14 +++++++++- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 26 ++++++++++++++++--- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 3 +++ .../gpu-gl/src/gpu/gl/GLBackendOutput.cpp | 2 +- .../gpu-gl/src/gpu/gl/GLBackendState.cpp | 2 +- .../gpu-gl/src/gpu/gl/GLBackendTransform.cpp | 2 +- libraries/gpu/src/gpu/Batch.cpp | 9 +++++++ libraries/gpu/src/gpu/Batch.h | 8 +++++- libraries/gpu/src/gpu/Context.cpp | 2 +- libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/Forward.h | 4 +++ scripts/system/spectatorCamera.js | 2 +- 12 files changed, 65 insertions(+), 11 deletions(-) diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/PrototypeSelfie.cpp index 809406ac23..6b719a12de 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/PrototypeSelfie.cpp @@ -1,6 +1,7 @@ #include "PrototypeSelfie.h" +#include void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { @@ -51,9 +52,15 @@ public: // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; + _cachedArgsPointer->_displayMode = args->_displayMode; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - // FIXME: We're also going to need to clear/restore the stereo setup! + args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); + args->_displayMode = RenderArgs::MONO; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.disableContextStereo(); + }); auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); @@ -78,6 +85,11 @@ public: args->_blitFramebuffer = cachedArgs->_blitFramebuffer; args->_viewport = cachedArgs->_viewport; args->popViewFrustum(); + args->_displayMode = cachedArgs->_displayMode; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.restoreContextStereo(); + }); } }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index ed81b502fc..791130ef6e 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -115,6 +115,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_resetStages), + (&::gpu::gl::GLBackend::do_disableContextStereo), + (&::gpu::gl::GLBackend::do_restoreContextStereo), + (&::gpu::gl::GLBackend::do_runLambda), (&::gpu::gl::GLBackend::do_startNamedCall), @@ -224,6 +227,14 @@ void GLBackend::renderPassTransfer(const Batch& batch) { _transform.preUpdate(_commandIndex, _stereo); break; + case Batch::COMMAND_disableContextStereo: + _stereo._contextDisable = true; + break; + + case Batch::COMMAND_restoreContextStereo: + _stereo._contextDisable = false; + break; + case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: { @@ -308,16 +319,16 @@ void GLBackend::render(const Batch& batch) { } #ifdef GPU_STEREO_DRAWCALL_INSTANCED - if (_stereo._enable) { + if (_stereo.isStereo()) { glEnable(GL_CLIP_DISTANCE0); } #endif { - PROFILE_RANGE(render_gpu_gl_detail, _stereo._enable ? "Render Stereo" : "Render"); + PROFILE_RANGE(render_gpu_gl_detail, _stereo.isStereo() ? "Render Stereo" : "Render"); renderPassDraw(batch); } #ifdef GPU_STEREO_DRAWCALL_INSTANCED - if (_stereo._enable) { + if (_stereo.isStereo()) { glDisable(GL_CLIP_DISTANCE0); } #endif @@ -358,6 +369,15 @@ void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) { resetStages(); } + +void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { + +} + +void GLBackend::do_restoreContextStereo(const Batch& batch, size_t paramOffset) { + +} + void GLBackend::do_runLambda(const Batch& batch, size_t paramOffset) { std::function f = batch._lambdas.get(batch._params[paramOffset]._uint); f(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 1c6cffb575..96217555e1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -143,6 +143,9 @@ public: // Reset stages virtual void do_resetStages(const Batch& batch, size_t paramOffset) final; + virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; + virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; + virtual void do_runLambda(const Batch& batch, size_t paramOffset) final; virtual void do_startNamedCall(const Batch& batch, size_t paramOffset) final; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp index 1e6691538b..a89bc69948 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp @@ -48,7 +48,7 @@ void GLBackend::do_setFramebuffer(const Batch& batch, size_t paramOffset) { } void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { - if (_stereo._enable && !_pipeline._stateCache.scissorEnable) { + if (_stereo.isStereo() && !_pipeline._stateCache.scissorEnable) { qWarning("Clear without scissor in stereo mode"); } diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp index a7d4a7ff7c..24f90395d7 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp @@ -322,7 +322,7 @@ void GLBackend::do_setStateScissorRect(const Batch& batch, size_t paramOffset) { Vec4i rect; memcpy(&rect, batch.readData(batch._params[paramOffset]._uint), sizeof(Vec4i)); - if (_stereo._enable) { + if (_stereo.isStereo()) { rect.z /= 2; if (_stereo._pass) { rect.x += rect.z; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp index f3da18ba1d..974aee2620 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp @@ -37,7 +37,7 @@ void GLBackend::do_setViewportTransform(const Batch& batch, size_t paramOffset) glViewport(vp.x, vp.y, vp.z, vp.w); // Where we assign the GL viewport - if (_stereo._enable) { + if (_stereo.isStereo()) { vp.z /= 2; if (_stereo._pass) { vp.x += vp.z; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 0d5036c202..15c0dfce49 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -390,6 +390,15 @@ void Batch::resetStages() { ADD_COMMAND(resetStages); } + +void Batch::disableContextStereo() { + ADD_COMMAND(disableContextStereo); +} + +void Batch::restoreContextStereo() { + ADD_COMMAND(restoreContextStereo); +} + void Batch::runLambda(std::function f) { ADD_COMMAND(runLambda); _params.emplace_back(_lambdas.cache(f)); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 85e99951cb..27c9402131 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -217,6 +217,9 @@ public: // Reset the stage caches and states void resetStages(); + void disableContextStereo(); + void restoreContextStereo(); + // Debugging void pushProfileRange(const char* name); void popProfileRange(); @@ -301,6 +304,9 @@ public: COMMAND_resetStages, + COMMAND_disableContextStereo, + COMMAND_restoreContextStereo, + COMMAND_runLambda, COMMAND_startNamedCall, @@ -467,7 +473,7 @@ public: NamedBatchDataMap _namedData; bool _enableStereo{ true }; - bool _enableSkybox{ false }; + bool _enableSkybox { false }; protected: friend class Context; diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 2116ffd6fe..24128524da 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -145,7 +145,7 @@ void Context::enableStereo(bool enable) { } bool Context::isStereo() { - return _stereo._enable; + return _stereo.isStereo(); } void Context::setStereoProjections(const mat4 eyeProjections[2]) { diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index de818ddcb0..7b7575e9ed 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -118,7 +118,7 @@ public: protected: virtual bool isStereo() { - return _stereo._enable; + return _stereo.isStereo(); } void getStereoProjections(mat4* eyeProjections) const { diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index ce95e8657e..88800652a5 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -93,7 +93,11 @@ namespace gpu { using TextureViews = std::vector; struct StereoState { + bool isStereo() const { + return _enable && !_contextDisable; + } bool _enable{ false }; + bool _contextDisable { false }; bool _skybox{ false }; // 0 for left eye, 1 for right eye uint8 _pass{ 0 }; diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 6f676ef632..34424c3451 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -115,7 +115,7 @@ // Must be something about the view frustum projection matrix? // But don't go changing that in (c++ code) without getting all the way to a desktop display! orientation: flip(cameraRotation), - scale: -0.35, + scale: -1.0, }); } From b694256559216821b07af963c33e3cc0fdbfed20 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 8 Jun 2017 17:40:43 -0700 Subject: [PATCH 31/79] Restore the value in the script --- scripts/system/spectatorCamera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 34424c3451..6f676ef632 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -115,7 +115,7 @@ // Must be something about the view frustum projection matrix? // But don't go changing that in (c++ code) without getting all the way to a desktop display! orientation: flip(cameraRotation), - scale: -1.0, + scale: -0.35, }); } From 7aef4dab4c26f4d8f6c76f9bffaad20958a52f27 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Jun 2017 11:02:23 -0700 Subject: [PATCH 32/79] Variable renaming pass --- interface/src/Application.cpp | 4 +- ...rototypeSelfie.cpp => SecondaryCamera.cpp} | 26 +++++------ .../{PrototypeSelfie.h => SecondaryCamera.h} | 20 ++++----- .../src/model-networking/TextureCache.cpp | 44 +++++++++---------- .../src/model-networking/TextureCache.h | 18 ++++---- scripts/system/spectatorCamera.js | 8 ++-- 6 files changed, 59 insertions(+), 61 deletions(-) rename interface/src/{PrototypeSelfie.cpp => SecondaryCamera.cpp} (77%) rename interface/src/{PrototypeSelfie.h => SecondaryCamera.h} (63%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1e831d39a6..f116b5fd6d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -114,7 +114,7 @@ #include #include #include -#include +#include #include #include #include @@ -1874,7 +1874,7 @@ void Application::initializeGL() { } _renderEngine->addJob("MainFrame", cullFunctor, isDeferred); - _renderEngine->addJob("SelfieFrame", cullFunctor); + _renderEngine->addJob("SecondaryCameraFrame", cullFunctor); /* _renderEngine->addJob("RenderShadowTask", cullFunctor); diff --git a/interface/src/PrototypeSelfie.cpp b/interface/src/SecondaryCamera.cpp similarity index 77% rename from interface/src/PrototypeSelfie.cpp rename to interface/src/SecondaryCamera.cpp index 6b719a12de..c6f7526256 100644 --- a/interface/src/PrototypeSelfie.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -1,5 +1,5 @@ -#include "PrototypeSelfie.h" +#include "SecondaryCamera.h" #include @@ -20,21 +20,21 @@ void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render using RenderArgsPointer = std::shared_ptr; -void SelfieRenderTaskConfig::resetSize(int width, int height) { // Carefully adjust the framebuffer / texture. +void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // Carefully adjust the framebuffer / texture. bool wasEnabled = isEnabled(); setEnabled(false); auto textureCache = DependencyManager::get(); - textureCache->resetSelfieFramebuffer(width, height); + textureCache->resetSecondaryCameraFramebuffer(width, height); setEnabled(wasEnabled); } -class BeginSelfieFrame { // Changes renderContext for our framebuffer and and view. +class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view. glm::vec3 _position{}; glm::quat _orientation{}; public: - using Config = BeginSelfieFrameConfig; - using JobModel = render::Job::ModelO; - BeginSelfieFrame() { + using Config = BeginSecondaryCameraFrameConfig; + using JobModel = render::Job::ModelO; + BeginSecondaryCameraFrame() { _cachedArgsPointer = std::make_shared(_cachedArgs); } @@ -48,7 +48,7 @@ public: void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); - auto destFramebuffer = textureCache->getSelfieFramebuffer(); + auto destFramebuffer = textureCache->getSecondaryCameraFramebuffer(); // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; @@ -76,9 +76,9 @@ protected: RenderArgsPointer _cachedArgsPointer; }; -class EndSelfieFrame { // Restores renderContext. +class EndSecondaryCameraFrame { // Restores renderContext. public: - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelI; void run(const render::RenderContextPointer& renderContext, const RenderArgsPointer& cachedArgs) { auto args = renderContext->args; @@ -93,10 +93,10 @@ public: } }; -void SelfieRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { - const auto cachedArg = task.addJob("BeginSelfie"); +void SecondaryCameraRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor) { + const auto cachedArg = task.addJob("BeginSecondaryCamera"); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); task.addJob("RenderDeferredTask", items); - task.addJob("EndSelfie", cachedArg); + task.addJob("EndSecondaryCamera", cachedArg); } \ No newline at end of file diff --git a/interface/src/PrototypeSelfie.h b/interface/src/SecondaryCamera.h similarity index 63% rename from interface/src/PrototypeSelfie.h rename to interface/src/SecondaryCamera.h index 7bb9bbe861..f68a65dd12 100644 --- a/interface/src/PrototypeSelfie.h +++ b/interface/src/SecondaryCamera.h @@ -1,6 +1,6 @@ #pragma once -#ifndef hifi_PrototypeSelfie_h -#define hifi_PrototypeSelfie_h +#ifndef hifi_SecondaryCamera_h +#define hifi_SecondaryCamera_h #include #include @@ -18,33 +18,33 @@ public: void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); }; -class BeginSelfieFrameConfig : public render::Task::Config { // Exposes view frustum position/orientation to javascript. +class BeginSecondaryCameraFrameConfig : public render::Task::Config { // Exposes view frustum position/orientation to javascript. Q_OBJECT Q_PROPERTY(glm::vec3 position MEMBER position NOTIFY dirty) // of viewpoint to render from Q_PROPERTY(glm::quat orientation MEMBER orientation NOTIFY dirty) // of viewpoint to render from public: glm::vec3 position{}; glm::quat orientation{}; - BeginSelfieFrameConfig() : render::Task::Config(false) {} + BeginSecondaryCameraFrameConfig() : render::Task::Config(false) {} signals: void dirty(); }; -class SelfieRenderTaskConfig : public render::Task::Config { +class SecondaryCameraRenderTaskConfig : public render::Task::Config { Q_OBJECT public: - SelfieRenderTaskConfig() : render::Task::Config(false) {} + SecondaryCameraRenderTaskConfig() : render::Task::Config(false) {} signals: void dirty(); public slots: void resetSize(int width, int height); }; -class SelfieRenderTask { +class SecondaryCameraRenderTask { public: - using Config = SelfieRenderTaskConfig; - using JobModel = render::Task::Model; - SelfieRenderTask() {} + using Config = SecondaryCameraRenderTaskConfig; + using JobModel = render::Task::Model; + SecondaryCameraRenderTask() {} void configure(const Config& config) {} void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 0a291a79ec..f64b917520 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,7 +50,7 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; -const std::string TextureCache::SELFIE_FRAME_URL { "http://selfieFrame" }; +const std::string TextureCache::SECONDARY_CAMERA_FRAME_URL { "http://secondaryCameraFrame" }; static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models @@ -182,9 +182,9 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum } NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) { - if (url == QUrl(SELFIE_FRAME_URL.c_str())) { + if (url == QUrl(SECONDARY_CAMERA_FRAME_URL.c_str())) { - return getSelfieNetworkTexture(); + return getSecondaryCameraNetworkTexture(); } TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); @@ -885,31 +885,31 @@ void ImageReader::read() { } -NetworkTexturePointer TextureCache::getSelfieNetworkTexture() { - if (!_selfieNetworkTexture) { - _selfieNetworkTexture.reset(new NetworkTexture(QUrl(SELFIE_FRAME_URL.c_str()))); - auto texture = getSelfieTexture(); - _selfieNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); +NetworkTexturePointer TextureCache::getSecondaryCameraNetworkTexture() { + if (!_secondaryCameraNetworkTexture) { + _secondaryCameraNetworkTexture.reset(new NetworkTexture(QUrl(SECONDARY_CAMERA_FRAME_URL.c_str()))); + auto texture = getSecondaryCameraTexture(); + _secondaryCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); } - return _selfieNetworkTexture; + return _secondaryCameraNetworkTexture; } -const gpu::TexturePointer& TextureCache::getSelfieTexture() { - if (!_selfieTexture) { - getSelfieFramebuffer(); +const gpu::TexturePointer& TextureCache::getSecondaryCameraTexture() { + if (!_secondaryCameraTexture) { + getSecondaryCameraFramebuffer(); } - return _selfieTexture; + return _secondaryCameraTexture; } -const gpu::FramebufferPointer& TextureCache::getSelfieFramebuffer() { - if (!_selfieFramebuffer) { - resetSelfieFramebuffer(2048, 1024); +const gpu::FramebufferPointer& TextureCache::getSecondaryCameraFramebuffer() { + if (!_secondaryCameraFramebuffer) { + resetSecondaryCameraFramebuffer(2048, 1024); } - return _selfieFramebuffer; + return _secondaryCameraFramebuffer; } -void TextureCache::resetSelfieFramebuffer(int width, int height) { - _selfieFramebuffer.reset(gpu::Framebuffer::create("selfie", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); - _selfieTexture = _selfieFramebuffer->getRenderBuffer(0); - _selfieNetworkTexture.reset(); -} \ No newline at end of file +void TextureCache::resetSecondaryCameraFramebuffer(int width, int height) { + _secondaryCameraFramebuffer.reset(gpu::Framebuffer::create("secondaryCamera", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); + _secondaryCameraTexture = _secondaryCameraFramebuffer->getRenderBuffer(0); + _secondaryCameraNetworkTexture.reset(); +} diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 698d37f38d..498a5ffb8f 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -170,11 +170,11 @@ public: gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture); - /// Selfie rendering targets. - NetworkTexturePointer getSelfieNetworkTexture(); - const gpu::TexturePointer& getSelfieTexture(); - const gpu::FramebufferPointer& getSelfieFramebuffer(); - void resetSelfieFramebuffer(int width, int height); + /// SecondaryCamera rendering targets. + NetworkTexturePointer getSecondaryCameraNetworkTexture(); + const gpu::TexturePointer& getSecondaryCameraTexture(); + const gpu::FramebufferPointer& getSecondaryCameraFramebuffer(); + void resetSecondaryCameraFramebuffer(int width, int height); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads @@ -193,7 +193,7 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; - static const std::string SELFIE_FRAME_URL; + static const std::string SECONDARY_CAMERA_FRAME_URL; KTXCache _ktxCache; // Map from image hashes to texture weak pointers @@ -207,9 +207,9 @@ private: gpu::TexturePointer _blackTexture; - gpu::FramebufferPointer _selfieFramebuffer; - gpu::TexturePointer _selfieTexture; - NetworkTexturePointer _selfieNetworkTexture; + gpu::FramebufferPointer _secondaryCameraFramebuffer; + gpu::TexturePointer _secondaryCameraTexture; + NetworkTexturePointer _secondaryCameraNetworkTexture; }; #endif // hifi_TextureCache_h diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 44419d73ff..04aa2b8186 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -54,8 +54,8 @@ // The update function for the spectator camera. Modifies the camera's position // and orientation. // - var spectatorFrameRenderConfig = Render.getConfig("SelfieFrame"); - var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSelfie"); + var spectatorFrameRenderConfig = Render.getConfig("SecondaryCameraFrame"); + var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSecondaryCamera"); var viewFinderOverlay = false; var camera = false; var cameraIsDynamic = false; @@ -105,8 +105,7 @@ }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { - url: "http://selfieFrame", - //url: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg", + url: "http://secondaryCameraFrame", parentID: camera, alpha: 1, position: inFrontOf(-0.25, cameraPosition, cameraRotation), @@ -141,7 +140,6 @@ } if (camera) { Entities.deleteEntity(camera); - print("ZACH FOX GOODBYE"); } if (viewFinderOverlay) { Overlays.deleteOverlay(viewFinderOverlay); From 5114fd8e1f46a52b1d31f5a6f35ab6926cd561f6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Jun 2017 14:46:59 -0700 Subject: [PATCH 33/79] Rename correctly? --- interface/src/SecondaryCamera.cpp | 4 +- .../src/model-networking/TextureCache.cpp | 42 +++++++++---------- .../src/model-networking/TextureCache.h | 18 ++++---- scripts/system/spectatorCamera.js | 2 +- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index c6f7526256..4603a4be79 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -24,7 +24,7 @@ void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // Care bool wasEnabled = isEnabled(); setEnabled(false); auto textureCache = DependencyManager::get(); - textureCache->resetSecondaryCameraFramebuffer(width, height); + textureCache->resetSpectatorCameraFramebuffer(width, height); setEnabled(wasEnabled); } @@ -48,7 +48,7 @@ public: void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); - auto destFramebuffer = textureCache->getSecondaryCameraFramebuffer(); + auto destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index f64b917520..f8b48833f7 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,7 +50,7 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; -const std::string TextureCache::SECONDARY_CAMERA_FRAME_URL { "http://secondaryCameraFrame" }; +const std::string TextureCache::SPECTATOR_CAMERA_FRAME_URL { "http://spectatorCameraFrame" }; static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models @@ -182,9 +182,9 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum } NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) { - if (url == QUrl(SECONDARY_CAMERA_FRAME_URL.c_str())) { + if (url == QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str())) { - return getSecondaryCameraNetworkTexture(); + return getSpectatorCameraNetworkTexture(); } TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); @@ -885,31 +885,31 @@ void ImageReader::read() { } -NetworkTexturePointer TextureCache::getSecondaryCameraNetworkTexture() { - if (!_secondaryCameraNetworkTexture) { - _secondaryCameraNetworkTexture.reset(new NetworkTexture(QUrl(SECONDARY_CAMERA_FRAME_URL.c_str()))); - auto texture = getSecondaryCameraTexture(); - _secondaryCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); +NetworkTexturePointer TextureCache::getSpectatorCameraNetworkTexture() { + if (!_spectatorCameraNetworkTexture) { + _spectatorCameraNetworkTexture.reset(new NetworkTexture(QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str()))); + auto texture = getSpectatorCameraTexture(); + _spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); } - return _secondaryCameraNetworkTexture; + return _spectatorCameraNetworkTexture; } -const gpu::TexturePointer& TextureCache::getSecondaryCameraTexture() { - if (!_secondaryCameraTexture) { - getSecondaryCameraFramebuffer(); +const gpu::TexturePointer& TextureCache::getSpectatorCameraTexture() { + if (!_spectatorCameraTexture) { + getSpectatorCameraFramebuffer(); } - return _secondaryCameraTexture; + return _spectatorCameraTexture; } -const gpu::FramebufferPointer& TextureCache::getSecondaryCameraFramebuffer() { - if (!_secondaryCameraFramebuffer) { - resetSecondaryCameraFramebuffer(2048, 1024); +const gpu::FramebufferPointer& TextureCache::getSpectatorCameraFramebuffer() { + if (!_spectatorCameraFramebuffer) { + resetSpectatorCameraFramebuffer(2048, 1024); } - return _secondaryCameraFramebuffer; + return _spectatorCameraFramebuffer; } -void TextureCache::resetSecondaryCameraFramebuffer(int width, int height) { - _secondaryCameraFramebuffer.reset(gpu::Framebuffer::create("secondaryCamera", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); - _secondaryCameraTexture = _secondaryCameraFramebuffer->getRenderBuffer(0); - _secondaryCameraNetworkTexture.reset(); +void TextureCache::resetSpectatorCameraFramebuffer(int width, int height) { + _spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); + _spectatorCameraTexture = _spectatorCameraFramebuffer->getRenderBuffer(0); + _spectatorCameraNetworkTexture.reset(); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 498a5ffb8f..38cb8e1982 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -170,11 +170,11 @@ public: gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture); - /// SecondaryCamera rendering targets. - NetworkTexturePointer getSecondaryCameraNetworkTexture(); - const gpu::TexturePointer& getSecondaryCameraTexture(); - const gpu::FramebufferPointer& getSecondaryCameraFramebuffer(); - void resetSecondaryCameraFramebuffer(int width, int height); + /// SpectatorCamera rendering targets. + NetworkTexturePointer getSpectatorCameraNetworkTexture(); + const gpu::TexturePointer& getSpectatorCameraTexture(); + const gpu::FramebufferPointer& getSpectatorCameraFramebuffer(); + void resetSpectatorCameraFramebuffer(int width, int height); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads @@ -193,7 +193,7 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; - static const std::string SECONDARY_CAMERA_FRAME_URL; + static const std::string SPECTATOR_CAMERA_FRAME_URL; KTXCache _ktxCache; // Map from image hashes to texture weak pointers @@ -207,9 +207,9 @@ private: gpu::TexturePointer _blackTexture; - gpu::FramebufferPointer _secondaryCameraFramebuffer; - gpu::TexturePointer _secondaryCameraTexture; - NetworkTexturePointer _secondaryCameraNetworkTexture; + gpu::FramebufferPointer _spectatorCameraFramebuffer; + gpu::TexturePointer _spectatorCameraTexture; + NetworkTexturePointer _spectatorCameraNetworkTexture; }; #endif // hifi_TextureCache_h diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 04aa2b8186..9df7dade53 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -105,7 +105,7 @@ }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { - url: "http://secondaryCameraFrame", + url: "http://spectatorCameraFrame", parentID: camera, alpha: 1, position: inFrontOf(-0.25, cameraPosition, cameraRotation), From 3884287c416d9f8e5c62af2b40e1e96d2bc589ad Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 7 Jun 2017 15:11:53 -0700 Subject: [PATCH 34/79] Use 'resource' protocol instead of 'http' --- .../model-networking/src/model-networking/TextureCache.cpp | 2 +- scripts/system/spectatorCamera.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index f8b48833f7..69eede0cc2 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,7 +50,7 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; -const std::string TextureCache::SPECTATOR_CAMERA_FRAME_URL { "http://spectatorCameraFrame" }; +const std::string TextureCache::SPECTATOR_CAMERA_FRAME_URL { "resource://spectatorCameraFrame" }; static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 9df7dade53..051741d55f 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -105,7 +105,7 @@ }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { - url: "http://spectatorCameraFrame", + url: "resource://spectatorCameraFrame", parentID: camera, alpha: 1, position: inFrontOf(-0.25, cameraPosition, cameraRotation), From fd50434d869d1103a47dc10b3f04a1c76461f507 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Jun 2017 14:36:38 -0700 Subject: [PATCH 35/79] New camera model; Cleanup; Bashing head :against desk --- interface/src/SecondaryCamera.cpp | 73 +++++++++++-------- interface/src/SecondaryCamera.h | 15 +++- .../src/model-networking/TextureCache.cpp | 37 +++++----- .../src/model-networking/TextureCache.h | 8 +- scripts/system/spectatorCamera.js | 52 +++++++++---- 5 files changed, 113 insertions(+), 72 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 4603a4be79..0af51bb2c4 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -1,8 +1,20 @@ +// +// SecondaryCamera.cpp +// interface/src +// +// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// #include "SecondaryCamera.h" - +#include #include +using RenderArgsPointer = std::shared_ptr; + void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { task.addJob("RenderShadowTask", cullFunctor); @@ -15,19 +27,18 @@ void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render } } - -#include - -using RenderArgsPointer = std::shared_ptr; - -void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // Carefully adjust the framebuffer / texture. +void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // FIXME: Add an arg here for "destinationFramebuffer" bool wasEnabled = isEnabled(); setEnabled(false); auto textureCache = DependencyManager::get(); - textureCache->resetSpectatorCameraFramebuffer(width, height); + textureCache->resetSpectatorCameraFramebuffer(width, height); // FIXME: Call the correct reset function based on the "destinationFramebuffer" arg setEnabled(wasEnabled); } +void SecondaryCameraRenderTaskConfig::resetSizeSpectatorCamera(int width, int height) { // Carefully adjust the framebuffer / texture. + resetSize(width, height); +} + class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view. glm::vec3 _position{}; glm::quat _orientation{}; @@ -39,36 +50,36 @@ public: } void configure(const Config& config) { - // Why does this run all the time, even when not enabled? Should we check and bail? - //qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; - _position = config.position; - _orientation = config.orientation; + if (config.enabled || config.alwaysEnabled) { + _position = config.position; + _orientation = config.orientation; + } } void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); - auto destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); - // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? - _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; - _cachedArgsPointer->_viewport = args->_viewport; - _cachedArgsPointer->_displayMode = args->_displayMode; - args->_blitFramebuffer = destFramebuffer; - args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - args->_displayMode = RenderArgs::MONO; + gpu::FramebufferPointer destFramebuffer; + destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); // FIXME: Change the destination based on some unimplemented config var + if (destFramebuffer) { + // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + _cachedArgsPointer->_viewport = args->_viewport; + _cachedArgsPointer->_displayMode = args->_displayMode; + args->_blitFramebuffer = destFramebuffer; + args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); + args->_displayMode = RenderArgs::MONO; - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - batch.disableContextStereo(); - }); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.disableContextStereo(); + }); - auto srcViewFrustum = args->getViewFrustum(); - srcViewFrustum.setPosition(_position); - srcViewFrustum.setOrientation(_orientation); - //srcViewFrustum.calculate(); // do we need this? I don't think so - //qDebug() << "FIXME pos" << _position << "orient" << _orientation << "frust pos" << srcViewFrustum.getPosition() << "orient" << srcViewFrustum.getOrientation() << "direct" << srcViewFrustum.getDirection(); - args->pushViewFrustum(srcViewFrustum); - cachedArgs = _cachedArgsPointer; + auto srcViewFrustum = args->getViewFrustum(); + srcViewFrustum.setPosition(_position); + srcViewFrustum.setOrientation(_orientation); + args->pushViewFrustum(srcViewFrustum); + cachedArgs = _cachedArgsPointer; + } } protected: diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index f68a65dd12..1abb2952aa 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -1,3 +1,14 @@ +// +// SecondaryCamera.h +// interface/src +// +// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + #pragma once #ifndef hifi_SecondaryCamera_h #define hifi_SecondaryCamera_h @@ -34,10 +45,12 @@ class SecondaryCameraRenderTaskConfig : public render::Task::Config { Q_OBJECT public: SecondaryCameraRenderTaskConfig() : render::Task::Config(false) {} +private: + void resetSize(int width, int height); signals: void dirty(); public slots: - void resetSize(int width, int height); + void resetSizeSpectatorCamera(int width, int height); }; class SecondaryCameraRenderTask { diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 69eede0cc2..0ecd8e8aab 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,7 +50,8 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; -const std::string TextureCache::SPECTATOR_CAMERA_FRAME_URL { "resource://spectatorCameraFrame" }; +static const QString RESOURCE_SCHEME = "resource"; +static const QUrl SPECTATOR_CAMERA_FRAME_URL("resource://spectatorCameraFrame"); static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models @@ -182,9 +183,8 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum } NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) { - if (url == QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str())) { - - return getSpectatorCameraNetworkTexture(); + if (url.scheme() == RESOURCE_SCHEME) { + return getResourceTexture(url); } TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); @@ -885,31 +885,30 @@ void ImageReader::read() { } -NetworkTexturePointer TextureCache::getSpectatorCameraNetworkTexture() { - if (!_spectatorCameraNetworkTexture) { - _spectatorCameraNetworkTexture.reset(new NetworkTexture(QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str()))); - auto texture = getSpectatorCameraTexture(); - _spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); +NetworkTexturePointer TextureCache::getResourceTexture(QUrl resourceTextureUrl) { + gpu::TexturePointer texture; + if (resourceTextureUrl == SPECTATOR_CAMERA_FRAME_URL) { + if (!_spectatorCameraNetworkTexture) { + _spectatorCameraNetworkTexture.reset(new NetworkTexture(resourceTextureUrl)); + } + texture = _spectatorCameraFramebuffer->getRenderBuffer(0); + if (texture) { + _spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); + return _spectatorCameraNetworkTexture; + } } - return _spectatorCameraNetworkTexture; - } -const gpu::TexturePointer& TextureCache::getSpectatorCameraTexture() { - if (!_spectatorCameraTexture) { - getSpectatorCameraFramebuffer(); - } - return _spectatorCameraTexture; + return NetworkTexturePointer(); } + const gpu::FramebufferPointer& TextureCache::getSpectatorCameraFramebuffer() { if (!_spectatorCameraFramebuffer) { resetSpectatorCameraFramebuffer(2048, 1024); } - return _spectatorCameraFramebuffer; } void TextureCache::resetSpectatorCameraFramebuffer(int width, int height) { - _spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); - _spectatorCameraTexture = _spectatorCameraFramebuffer->getRenderBuffer(0); + _spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, width, height)); _spectatorCameraNetworkTexture.reset(); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 38cb8e1982..c7bb34068d 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -171,8 +171,7 @@ public: /// SpectatorCamera rendering targets. - NetworkTexturePointer getSpectatorCameraNetworkTexture(); - const gpu::TexturePointer& getSpectatorCameraTexture(); + NetworkTexturePointer getResourceTexture(QUrl resourceTextureUrl); const gpu::FramebufferPointer& getSpectatorCameraFramebuffer(); void resetSpectatorCameraFramebuffer(int width, int height); @@ -193,7 +192,6 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; - static const std::string SPECTATOR_CAMERA_FRAME_URL; KTXCache _ktxCache; // Map from image hashes to texture weak pointers @@ -206,10 +204,8 @@ private: gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; - - gpu::FramebufferPointer _spectatorCameraFramebuffer; - gpu::TexturePointer _spectatorCameraTexture; NetworkTexturePointer _spectatorCameraNetworkTexture; + gpu::FramebufferPointer _spectatorCameraFramebuffer; }; #endif // hifi_TextureCache_h diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 051741d55f..6e3d032e31 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -28,7 +28,7 @@ // Spectator camera utility functions and variables. // function inFrontOf(distance, position, orientation) { - return Vec3.sum(position || MyAvatar.position, + return Vec3.sum(position || Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 }), Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); } var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); @@ -46,6 +46,8 @@ // camera: The in-world entity that corresponds to the spectator camera. // cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays // drift with respect to their parent + // lastCameraPosition: Holds the last known camera position + // lastCameraRotation: Holds the last known camera rotation // // Arguments: // None @@ -59,11 +61,18 @@ var viewFinderOverlay = false; var camera = false; var cameraIsDynamic = false; + var lastCameraPosition = false; + var lastCameraRotation = false; function updateRenderFromCamera() { var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); - // FIXME: don't muck with config if properties haven't changed. - beginSpectatorFrameRenderConfig.position = cameraData.position; - beginSpectatorFrameRenderConfig.orientation = cameraData.rotation; + if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) { + lastCameraPosition = cameraData.position; + beginSpectatorFrameRenderConfig.position = lastCameraPosition; + } + if (JSON.stringify(lastCameraRotation) !== JSON.stringify(cameraData.rotation)) { + lastCameraRotation = cameraData.rotation; + beginSpectatorFrameRenderConfig.orientation = lastCameraRotation; + } if (cameraIsDynamic) { // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); @@ -88,33 +97,46 @@ function spectatorCameraOn() { // Set the special texture size based on the window in which it will eventually be displayed. var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. - spectatorFrameRenderConfig.resetSize(size.x, size.y); + spectatorFrameRenderConfig.resetSizeSpectatorCamera(size.x, size.y); spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); Script.update.connect(updateRenderFromCamera); isUpdateRenderWired = true; camera = Entities.addEntity({ - type: 'Box', - dimensions: { x: 0.4, y: 0.2, z: 0.4 }, - userData: '{"grabbableKey":{"grabbable":true}}', - dynamic: cameraIsDynamic, - color: { red: 255, green: 0, blue: 0 }, - name: 'SpectatorCamera', - position: cameraPosition, // Put the camera in front of me so that I can find it. - rotation: cameraRotation + "angularDamping": 0.98000001907348633, + "collisionsWillMove": 1, + "damping": 0.98000001907348633, + "dimensions": { + "x": 0.2338641881942749, + "y": 0.407032310962677, + "z": 0.38702544569969177 + }, + "dynamic": cameraIsDynamic, + "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/spectator-camera.fbx", + "queryAACube": { + "scale": 0.60840487480163574, + "x": -0.30420243740081787, + "y": -0.30420243740081787, + "z": -0.30420243740081787 + }, + "rotation": cameraRotation, + "position": cameraPosition, + "shapeType": "simple-compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"grabbable\":true}}" }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { url: "resource://spectatorCameraFrame", parentID: camera, alpha: 1, - position: inFrontOf(-0.25, cameraPosition, cameraRotation), + position: inFrontOf(0, Vec3.sum(cameraPosition, { x: 0, y: 0.15, z: 0 }), cameraRotation), // FIXME: We shouldn't need the flip and the negative scale. // e.g., This isn't necessary using an ordinary .jpg with lettering, above. // Must be something about the view frustum projection matrix? // But don't go changing that in (c++ code) without getting all the way to a desktop display! orientation: flip(cameraRotation), - scale: -0.35, + scale: -0.16, }); setDisplay(monitorShowsCameraView); } From 3d9904cde1579f4a737a98fb6acff00315fa08d9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Jun 2017 15:41:51 -0700 Subject: [PATCH 36/79] Correctly position actual camera and preview overlay --- scripts/system/spectatorCamera.js | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 6e3d032e31..af0fd92b64 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -28,7 +28,7 @@ // Spectator camera utility functions and variables. // function inFrontOf(distance, position, orientation) { - return Vec3.sum(position || Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 }), + return Vec3.sum(position || MyAvatar.position, Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); } var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); @@ -65,14 +65,14 @@ var lastCameraRotation = false; function updateRenderFromCamera() { var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); - if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) { - lastCameraPosition = cameraData.position; - beginSpectatorFrameRenderConfig.position = lastCameraPosition; - } if (JSON.stringify(lastCameraRotation) !== JSON.stringify(cameraData.rotation)) { lastCameraRotation = cameraData.rotation; beginSpectatorFrameRenderConfig.orientation = lastCameraRotation; } + if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) { + lastCameraPosition = cameraData.position; + beginSpectatorFrameRenderConfig.position = Vec3.sum(inFrontOf(0.17, lastCameraPosition, lastCameraRotation), {x: 0, y: 0.02, z: 0}); + } if (cameraIsDynamic) { // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); @@ -99,12 +99,12 @@ var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. spectatorFrameRenderConfig.resetSizeSpectatorCamera(size.x, size.y); spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; - var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); + var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(1, Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 })); Script.update.connect(updateRenderFromCamera); isUpdateRenderWired = true; camera = Entities.addEntity({ "angularDamping": 0.98000001907348633, - "collisionsWillMove": 1, + "collisionsWillMove": 0, "damping": 0.98000001907348633, "dimensions": { "x": 0.2338641881942749, @@ -119,25 +119,26 @@ "y": -0.30420243740081787, "z": -0.30420243740081787 }, - "rotation": cameraRotation, - "position": cameraPosition, + "rotation": { x: 0, y: 0, z: 0 }, + "position": { x: 0, y: 0, z: 0 }, "shapeType": "simple-compound", "type": "Model", "userData": "{\"grabbableKey\":{\"grabbable\":true}}" }, true); - // Put an image3d overlay on the near face, as a viewFinder. + // This image3d overlay acts as the camera's preview screen. viewFinderOverlay = Overlays.addOverlay("image3d", { url: "resource://spectatorCameraFrame", parentID: camera, alpha: 1, - position: inFrontOf(0, Vec3.sum(cameraPosition, { x: 0, y: 0.15, z: 0 }), cameraRotation), - // FIXME: We shouldn't need the flip and the negative scale. - // e.g., This isn't necessary using an ordinary .jpg with lettering, above. - // Must be something about the view frustum projection matrix? - // But don't go changing that in (c++ code) without getting all the way to a desktop display! - orientation: flip(cameraRotation), + position: { x: 0.007, y: 0.15, z: -0.005 }, scale: -0.16, }); + Entities.editEntity(camera, { position: cameraPosition, rotation: cameraRotation }); + // FIXME: We shouldn't need the flip and the negative scale. + // e.g., This isn't necessary using an ordinary .jpg with lettering, above. + // Must be something about the view frustum projection matrix? + // But don't go changing that in (c++ code) without getting all the way to a desktop display! + Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraRotation) }); setDisplay(monitorShowsCameraView); } @@ -284,6 +285,7 @@ tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); + sendToQml({ method: 'updateMonitorShowsSwitch', params: !!Settings.getValue('spectatorCamera/monitorShowsCameraView', false) }); setMonitorShowsCameraViewAndSendToQml(monitorShowsCameraView); } } From 3f169e50fe776734cd991103069b5ae66f20e1e6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Jun 2017 16:18:25 -0700 Subject: [PATCH 37/79] selfie to spectatorCamera --- scripts/system/spectatorCamera.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index af0fd92b64..ed67c97f4a 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -237,7 +237,7 @@ function setDisplay(showCameraView) { // It would be fancy if (showCameraView && !isUpdateRenderWired) would show instructions, but that's out of scope for now. - var url = (showCameraView && isUpdateRenderWired) ? "http://selfieFrame" : ""; + var url = (showCameraView && isUpdateRenderWired) ? "resource://spectatorCameraFrame" : ""; Window.setDisplayTexture(url); } const MONITOR_SHOWS_CAMERA_VIEW_DEFAULT = false; From 8825e9177536d6844b88152b4ae37fdecb140a34 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 9 Jun 2017 11:36:32 -0700 Subject: [PATCH 38/79] emissive is true --- scripts/system/spectatorCamera.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index ed67c97f4a..ea934bd83c 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -128,6 +128,7 @@ // This image3d overlay acts as the camera's preview screen. viewFinderOverlay = Overlays.addOverlay("image3d", { url: "resource://spectatorCameraFrame", + emissive: true, parentID: camera, alpha: 1, position: { x: 0.007, y: 0.15, z: -0.005 }, From f973f7b5e34c4e77f994ee225078e0f238e265aa Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 12 Jun 2017 21:25:27 -0700 Subject: [PATCH 39/79] Fix the background not rendering on the second frame, this was imply due to a bug in the GLBackend --- interface/src/Application.cpp | 2 +- libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f116b5fd6d..cd8b42af1a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1873,8 +1873,8 @@ void Application::initializeGL() { isDeferred = false; } - _renderEngine->addJob("MainFrame", cullFunctor, isDeferred); _renderEngine->addJob("SecondaryCameraFrame", cullFunctor); + _renderEngine->addJob("MainFrame", cullFunctor, isDeferred); /* _renderEngine->addJob("RenderShadowTask", cullFunctor); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp index a89bc69948..358b90ed8b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendOutput.cpp @@ -63,11 +63,17 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { int useScissor = batch._params[paramOffset + 0]._int; GLuint glmask = 0; + bool restoreStencilMask = false; + uint8_t cacheStencilMask = 0xFF; if (masks & Framebuffer::BUFFER_STENCIL) { glClearStencil(stencil); glmask |= GL_STENCIL_BUFFER_BIT; - // TODO: we will probably need to also check the write mask of stencil like we do - // for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it" + + cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront(); + if (cacheStencilMask != 0xFF) { + restoreStencilMask = true; + glStencilMask( 0xFF); + } } bool restoreDepthMask = false; @@ -121,6 +127,11 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) { glDisable(GL_SCISSOR_TEST); } + // Restore Stencil write mask + if (restoreStencilMask) { + glStencilMask(cacheStencilMask); + } + // Restore write mask meaning turn back off if (restoreDepthMask) { glDepthMask(GL_FALSE); From 4acbb81413d1da763d967697b371d5df72103eae Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 12 Jun 2017 15:38:49 -0700 Subject: [PATCH 40/79] Checkpoint --- interface/src/SecondaryCamera.cpp | 7 ++++++- libraries/shared/src/RenderArgs.h | 2 +- scripts/system/spectatorCamera.js | 29 +++++++++++++++-------------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 0af51bb2c4..3f3d02af42 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -62,13 +62,14 @@ public: gpu::FramebufferPointer destFramebuffer; destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); // FIXME: Change the destination based on some unimplemented config var if (destFramebuffer) { - // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; _cachedArgsPointer->_displayMode = args->_displayMode; + _cachedArgsPointer->_renderMode = args->_renderMode; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); args->_displayMode = RenderArgs::MONO; + args->_renderMode = RenderArgs::SECONDARY_CAMERA_RENDER_MODE; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.disableContextStereo(); @@ -77,6 +78,9 @@ public: auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); srcViewFrustum.setOrientation(_orientation); + // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, + // which is not what we want here. + srcViewFrustum.calculate(); args->pushViewFrustum(srcViewFrustum); cachedArgs = _cachedArgsPointer; } @@ -97,6 +101,7 @@ public: args->_viewport = cachedArgs->_viewport; args->popViewFrustum(); args->_displayMode = cachedArgs->_displayMode; + args->_renderMode = cachedArgs->_renderMode; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.restoreContextStereo(); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index d4d88c26a8..f869a93e1f 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -75,7 +75,7 @@ public: class RenderArgs { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; enum DebugFlags { RENDER_DEBUG_NONE = 0, diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index ea934bd83c..9e83be1a0e 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -22,7 +22,7 @@ // - // Function Name: inFrontOf(), flip() + // Function Name: inFrontOf() // // Description: // Spectator camera utility functions and variables. @@ -31,8 +31,6 @@ return Vec3.sum(position || MyAvatar.position, Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); } - var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); - function flip(rotation) { return Quat.multiply(rotation, aroundY); } // // Function Name: updateRenderFromCamera() @@ -73,10 +71,6 @@ lastCameraPosition = cameraData.position; beginSpectatorFrameRenderConfig.position = Vec3.sum(inFrontOf(0.17, lastCameraPosition, lastCameraRotation), {x: 0, y: 0.02, z: 0}); } - if (cameraIsDynamic) { - // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object - Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); - } } // @@ -85,6 +79,8 @@ // Relevant Variables: // isUpdateRenderWired: Bool storing whether or not the camera's update // function is wired. + // windowAspectRatio: The ratio of the Interface windows's sizeX/sizeY + // previewAspectRatio: The ratio of the camera preview's sizeX/sizeY // // Arguments: // None @@ -94,10 +90,15 @@ // spawn the camera entity. // var isUpdateRenderWired = false; + var windowAspectRatio; + var previewAspectRatio = 16/9; function spectatorCameraOn() { // Set the special texture size based on the window in which it will eventually be displayed. var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. - spectatorFrameRenderConfig.resetSizeSpectatorCamera(size.x, size.y); + var sizeX = Window.innerWidth; + var sizeY = Window.innerHeight; + windowAspectRatio = sizeX/sizeY; + spectatorFrameRenderConfig.resetSizeSpectatorCamera(sizeX, sizeY); spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(1, Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 })); Script.update.connect(updateRenderFromCamera); @@ -132,14 +133,14 @@ parentID: camera, alpha: 1, position: { x: 0.007, y: 0.15, z: -0.005 }, - scale: -0.16, + dimensions: { x: 0.16, y: -0.16 * windowAspectRatio / previewAspectRatio, z: 0 } + // FIXME: This stretches the preview. + // FIXME: We shouldn't need the negative dimension. + // e.g., This isn't necessary using an ordinary .jpg with lettering, above. + // Must be something about the view frustum projection matrix? + // But don't go changing that in (c++ code) without getting all the way to a desktop display! }); Entities.editEntity(camera, { position: cameraPosition, rotation: cameraRotation }); - // FIXME: We shouldn't need the flip and the negative scale. - // e.g., This isn't necessary using an ordinary .jpg with lettering, above. - // Must be something about the view frustum projection matrix? - // But don't go changing that in (c++ code) without getting all the way to a desktop display! - Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraRotation) }); setDisplay(monitorShowsCameraView); } From 7b6033f7bc5f141b28cfbce713653cd1f3b3c1df Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 13 Jun 2017 11:37:27 -0700 Subject: [PATCH 41/79] Getting closer to a solution --- interface/src/SecondaryCamera.cpp | 1 + libraries/render-utils/src/DeferredLightingEffect.cpp | 3 +-- scripts/system/spectatorCamera.js | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 3f3d02af42..479c97c7f8 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -78,6 +78,7 @@ public: auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); srcViewFrustum.setOrientation(_orientation); + srcViewFrustum.setProjection(glm::perspective(45.0f, ((float)args->_viewport.z / (float)args->_viewport.w), 0.1f, 100.0f)); // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, // which is not what we want here. srcViewFrustum.calculate(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4b3ee9fec7..2ab13aecd6 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -420,8 +420,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) { auto framebufferCache = DependencyManager::get(); - auto framebufferSize = framebufferCache->getFrameBufferSize(); - glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height()); + glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); // Resizing framebuffers instead of re-building them seems to cause issues with threaded // rendering diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 9e83be1a0e..88f9e86ae5 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -133,12 +133,8 @@ parentID: camera, alpha: 1, position: { x: 0.007, y: 0.15, z: -0.005 }, - dimensions: { x: 0.16, y: -0.16 * windowAspectRatio / previewAspectRatio, z: 0 } + dimensions: { x: 0.16, y: 0.16 * windowAspectRatio / previewAspectRatio, z: 0 } // FIXME: This stretches the preview. - // FIXME: We shouldn't need the negative dimension. - // e.g., This isn't necessary using an ordinary .jpg with lettering, above. - // Must be something about the view frustum projection matrix? - // But don't go changing that in (c++ code) without getting all the way to a desktop display! }); Entities.editEntity(camera, { position: cameraPosition, rotation: cameraRotation }); setDisplay(monitorShowsCameraView); From 8962c7bf6af03a7fe3852f976cc9b3a62c7cd912 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 13 Jun 2017 13:06:03 -0700 Subject: [PATCH 42/79] Viewfinder re-flip, add comments regarding why it's necessary --- scripts/system/spectatorCamera.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 88f9e86ae5..f77eaab3e4 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -133,8 +133,15 @@ parentID: camera, alpha: 1, position: { x: 0.007, y: 0.15, z: -0.005 }, - dimensions: { x: 0.16, y: 0.16 * windowAspectRatio / previewAspectRatio, z: 0 } - // FIXME: This stretches the preview. + dimensions: { x: 0.16, y: -0.16 * windowAspectRatio / previewAspectRatio, z: 0 } + // Negative dimension for viewfinder is necessary for now due to the way Image3DOverlay + // draws textures. + // See Image3DOverlay.cpp:91. If you change the two lines there to: + // glm::vec2 topLeft(-x, -y); + // glm::vec2 bottomRight(x, y); + // the viewfinder will appear rightside up without this negative y-dimension. + // However, other Image3DOverlay textures (like the PAUSED one) will appear upside-down. *Why?* + // FIXME: This code will stretch the preview as the window aspect ratio changes. Fix that! }); Entities.editEntity(camera, { position: cameraPosition, rotation: cameraRotation }); setDisplay(monitorShowsCameraView); From 0d86d4f0cb3917acd52a447d0490ad28b4dddf64 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 13 Jun 2017 14:30:32 -0700 Subject: [PATCH 43/79] It's working! --- .../gpu-gl/src/gpu/gl/GLBackendTransform.cpp | 4 ++-- .../render-utils/src/AntialiasingEffect.cpp | 16 +++++++--------- libraries/render-utils/src/AntialiasingEffect.h | 2 +- .../render-utils/src/DebugDeferredBuffer.cpp | 2 -- .../render-utils/src/DeferredLightingEffect.cpp | 2 -- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp index 974aee2620..01f055e0d9 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendTransform.cpp @@ -119,7 +119,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo size_t offset = _cameraUboSize * _cameras.size(); _cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset)); - if (stereo._enable) { + if (stereo.isStereo()) { #ifdef GPU_STEREO_CAMERA_BUFFER _cameras.push_back(CameraBufferElement(_camera.getEyeCamera(0, stereo, _view), _camera.getEyeCamera(1, stereo, _view))); #else @@ -151,7 +151,7 @@ void GLBackend::TransformStageState::update(size_t commandIndex, const StereoSta #ifdef GPU_STEREO_CAMERA_BUFFER bindCurrentCamera(0); #else - if (!stereo._enable) { + if (!stereo.isStereo()) { bindCurrentCamera(0); } #endif diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index f7881b0333..ce3bf69588 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -40,9 +40,9 @@ Antialiasing::~Antialiasing() { } } -const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { - int width = DependencyManager::get()->getFrameBufferSize().width(); - int height = DependencyManager::get()->getFrameBufferSize().height(); +const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* args) { + int width = args->_viewport.z; + int height = args->_viewport.w; if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) { _antialiasingBuffer.reset(); @@ -115,10 +115,8 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setViewportTransform(args->_viewport); // FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation - auto framebufferCache = DependencyManager::get(); - QSize framebufferSize = framebufferCache->getFrameBufferSize(); - float fbWidth = framebufferSize.width(); - float fbHeight = framebufferSize.height(); + float fbWidth = renderContext->args->_viewport.z; + float fbHeight = renderContext->args->_viewport.w; // float sMin = args->_viewport.x / fbWidth; // float sWidth = args->_viewport.z / fbWidth; // float tMin = args->_viewport.y / fbHeight; @@ -133,10 +131,10 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setModelTransform(Transform()); // FXAA step - getAntialiasingPipeline(); + auto pipeline = getAntialiasingPipeline(renderContext->args); batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0)); batch.setFramebuffer(_antialiasingBuffer); - batch.setPipeline(getAntialiasingPipeline()); + batch.setPipeline(pipeline); // initialize the view-space unpacking uniforms using frustum data float left, right, bottom, top, nearVal, farVal; diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index e403032b4e..cec2554a3b 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -33,7 +33,7 @@ public: void configure(const Config& config) {} void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer); - const gpu::PipelinePointer& getAntialiasingPipeline(); + const gpu::PipelinePointer& getAntialiasingPipeline(RenderArgs* args); const gpu::PipelinePointer& getBlendPipeline(); private: diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index a67d20c6b0..3359b3a12d 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -19,7 +19,6 @@ #include #include "GeometryCache.h" -#include "FramebufferCache.h" #include "TextureCache.h" #include "DeferredLightingEffect.h" @@ -410,7 +409,6 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I batch.setViewportTransform(args->_viewport); const auto geometryBuffer = DependencyManager::get(); - const auto framebufferCache = DependencyManager::get(); const auto textureCache = DependencyManager::get(); glm::mat4 projMat; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 2ab13aecd6..0b4eee125b 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -418,8 +418,6 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() { } void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) { - - auto framebufferCache = DependencyManager::get(); glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w); // Resizing framebuffers instead of re-building them seems to cause issues with threaded From ec3b488897cd25bc3d251ee5038093d18ae1b34e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 10:27:08 -0700 Subject: [PATCH 44/79] Remove SECONDARY_CAMERA_RENDER_MODE for now --- interface/src/SecondaryCamera.cpp | 3 --- libraries/shared/src/RenderArgs.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 479c97c7f8..ae4c67507a 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -65,11 +65,9 @@ public: _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; _cachedArgsPointer->_displayMode = args->_displayMode; - _cachedArgsPointer->_renderMode = args->_renderMode; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); args->_displayMode = RenderArgs::MONO; - args->_renderMode = RenderArgs::SECONDARY_CAMERA_RENDER_MODE; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.disableContextStereo(); @@ -102,7 +100,6 @@ public: args->_viewport = cachedArgs->_viewport; args->popViewFrustum(); args->_displayMode = cachedArgs->_displayMode; - args->_renderMode = cachedArgs->_renderMode; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.restoreContextStereo(); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index f869a93e1f..d4d88c26a8 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -75,7 +75,7 @@ public: class RenderArgs { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; enum DebugFlags { RENDER_DEBUG_NONE = 0, From 03c61e21914dcd6be8e75a90784a101af022cce7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 11:53:05 -0700 Subject: [PATCH 45/79] vFoV and clipping plane distances now come from config --- interface/src/SecondaryCamera.cpp | 8 +++++++- interface/src/SecondaryCamera.h | 8 +++++++- scripts/system/spectatorCamera.js | 11 ++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index ae4c67507a..257c8454c5 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -42,6 +42,9 @@ void SecondaryCameraRenderTaskConfig::resetSizeSpectatorCamera(int width, int he class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view. glm::vec3 _position{}; glm::quat _orientation{}; + float _vFoV{}; + float _nearClipPlaneDistance{}; + float _farClipPlaneDistance{}; public: using Config = BeginSecondaryCameraFrameConfig; using JobModel = render::Job::ModelO; @@ -53,6 +56,9 @@ public: if (config.enabled || config.alwaysEnabled) { _position = config.position; _orientation = config.orientation; + _vFoV = config.vFoV; + _nearClipPlaneDistance = config.nearClipPlaneDistance; + _farClipPlaneDistance = config.farClipPlaneDistance; } } @@ -76,7 +82,7 @@ public: auto srcViewFrustum = args->getViewFrustum(); srcViewFrustum.setPosition(_position); srcViewFrustum.setOrientation(_orientation); - srcViewFrustum.setProjection(glm::perspective(45.0f, ((float)args->_viewport.z / (float)args->_viewport.w), 0.1f, 100.0f)); + srcViewFrustum.setProjection(glm::perspective(glm::radians(_vFoV), ((float)args->_viewport.z / (float)args->_viewport.w), _nearClipPlaneDistance, _farClipPlaneDistance)); // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, // which is not what we want here. srcViewFrustum.calculate(); diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 1abb2952aa..f689c042c0 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -29,13 +29,19 @@ public: void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred = true); }; -class BeginSecondaryCameraFrameConfig : public render::Task::Config { // Exposes view frustum position/orientation to javascript. +class BeginSecondaryCameraFrameConfig : public render::Task::Config { // Exposes secondary camera parameters to JavaScript. Q_OBJECT Q_PROPERTY(glm::vec3 position MEMBER position NOTIFY dirty) // of viewpoint to render from Q_PROPERTY(glm::quat orientation MEMBER orientation NOTIFY dirty) // of viewpoint to render from + Q_PROPERTY(float vFoV MEMBER vFoV NOTIFY dirty) // Secondary camera's vertical field of view. In degrees. + Q_PROPERTY(float nearClipPlaneDistance MEMBER nearClipPlaneDistance NOTIFY dirty) // Secondary camera's near clip plane distance. In meters. + Q_PROPERTY(float farClipPlaneDistance MEMBER farClipPlaneDistance NOTIFY dirty) // Secondary camera's far clip plane distance. In meters. public: glm::vec3 position{}; glm::quat orientation{}; + float vFoV{}; + float nearClipPlaneDistance{}; + float farClipPlaneDistance{}; BeginSecondaryCameraFrameConfig() : render::Task::Config(false) {} signals: void dirty(); diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index f77eaab3e4..a3cdea7bd5 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -81,6 +81,9 @@ // function is wired. // windowAspectRatio: The ratio of the Interface windows's sizeX/sizeY // previewAspectRatio: The ratio of the camera preview's sizeX/sizeY + // vFoV: The vertical field of view of the spectator camera + // nearClipPlaneDistance: The near clip plane distance of the spectator camera + // farClipPlaneDistance: The far clip plane distance of the spectator camera // // Arguments: // None @@ -91,7 +94,10 @@ // var isUpdateRenderWired = false; var windowAspectRatio; - var previewAspectRatio = 16/9; + var previewAspectRatio = 16 / 9; + var vFoV = 45.0; + var nearClipPlaneDistance = 0.1; + var farClipPlaneDistance = 100.0; function spectatorCameraOn() { // Set the special texture size based on the window in which it will eventually be displayed. var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. @@ -100,6 +106,9 @@ windowAspectRatio = sizeX/sizeY; spectatorFrameRenderConfig.resetSizeSpectatorCamera(sizeX, sizeY); spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; + beginSpectatorFrameRenderConfig.vFoV = vFoV; + beginSpectatorFrameRenderConfig.nearClipPlaneDistance = nearClipPlaneDistance; + beginSpectatorFrameRenderConfig.farClipPlaneDistance = farClipPlaneDistance; var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(1, Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 })); Script.update.connect(updateRenderFromCamera); isUpdateRenderWired = true; From 8a217acd2bef505696dae04ba2a19076c3a364ee Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 12:19:38 -0700 Subject: [PATCH 46/79] Defaults for camera projection parameters --- interface/src/SecondaryCamera.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index f689c042c0..0f74ff8be0 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -39,9 +39,9 @@ class BeginSecondaryCameraFrameConfig : public render::Task::Config { // Exposes public: glm::vec3 position{}; glm::quat orientation{}; - float vFoV{}; - float nearClipPlaneDistance{}; - float farClipPlaneDistance{}; + float vFoV{ 45.0f }; + float nearClipPlaneDistance{ 0.1f }; + float farClipPlaneDistance{ 100.0f }; BeginSecondaryCameraFrameConfig() : render::Task::Config(false) {} signals: void dirty(); From 0114962e7554ee77afba06d05ac47fa94caa7cbc Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 15:25:07 -0700 Subject: [PATCH 47/79] Make the Spectator button only appear in HMD (with debug mode) --- scripts/system/spectatorCamera.js | 60 +++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index a3cdea7bd5..e308e252b3 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -17,7 +17,8 @@ // // FUNCTION VAR DECLARATIONS // - var sendToQml, onTabletScreenChanged, fromQml, onTabletButtonClicked, wireEventBridge, startup, shutdown; + var sendToQml, addOrRemoveButton, onTabletScreenChanged, fromQml, + onTabletButtonClicked, wireEventBridge, startup, shutdown; @@ -189,15 +190,51 @@ function onHMDChanged(isHMDMode) { // Will also eventually enable disable app, camera, etc. setDisplay(monitorShowsCameraView); + addOrRemoveButton(false, isHMDMode); + } + + // + // Function Names: addOrRemoveButton() + // + // Relevant Variables: + // button: The tablet button. + // buttonName: The name of the button. + // tablet: The tablet instance to be modified. + // showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode + // + // Arguments: + // forceRemove: Set to "true" to force removal of the button, i.e. upon shutdown + // isHMDMode: "true" if user is in HMD; false otherwise + // + // Description: + // Used to add or remove the "SPECTATOR" app button from the HUD/tablet + // + var button = false; + var buttonName = "SPECTATOR"; + var tablet = null; + var showSpectatorInDesktop = false; + function addOrRemoveButton(forceRemove, isHMDMode) { + if (!button) { + if ((isHMDMode || showSpectatorInDesktop) && !forceRemove) { + button = tablet.addButton({ + text: buttonName + }); + button.clicked.connect(onTabletButtonClicked); + } + } else if (button) { + button.clicked.disconnect(onTabletButtonClicked); + tablet.removeButton(button); + button = false; + } else { + print("ERROR adding/removing Spectator button!") + } } // // Function Name: startup() // // Relevant Variables: - // button: The tablet button. - // buttonName: The name of the button. - // tablet: The tablet instance to be modified. + // None // // Arguments: // None @@ -205,15 +242,9 @@ // Description: // startup() will be called when the script is loaded. // - var button; - var buttonName = "SPECTATOR"; - var tablet = null; function startup() { tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - button = tablet.addButton({ - text: buttonName - }); - button.clicked.connect(onTabletButtonClicked); + addOrRemoveButton(false, HMD.active); tablet.screenChanged.connect(onTabletScreenChanged); Window.domainChanged.connect(spectatorCameraOff); Controller.keyPressEvent.connect(keyPressEvent); @@ -320,7 +351,9 @@ function onTabletScreenChanged(type, url) { wireEventBridge(shouldActivateButton); // for toolbar mode: change button to active when window is first openend, false otherwise. - button.editProperties({ isActive: shouldActivateButton }); + if (button) { + button.editProperties({ isActive: shouldActivateButton }); + } shouldActivateButton = false; onSpectatorCameraScreen = false; } @@ -389,8 +422,7 @@ function shutdown() { spectatorCameraOff(); Window.domainChanged.disconnect(spectatorCameraOff); - tablet.removeButton(button); - button.clicked.disconnect(onTabletButtonClicked); + addOrRemoveButton(true, HMD.active); tablet.screenChanged.disconnect(onTabletScreenChanged); HMD.displayModeChanged.disconnect(onHMDChanged); Controller.keyPressEvent.disconnect(keyPressEvent); From 498ed4cbe8ea9286993466222be4ee0d75dd3379 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 17:00:33 -0700 Subject: [PATCH 48/79] showSpectatorInDesktop true for now --- scripts/system/spectatorCamera.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index e308e252b3..a7f5dbcc79 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -194,7 +194,7 @@ } // - // Function Names: addOrRemoveButton() + // Function Name: addOrRemoveButton() // // Relevant Variables: // button: The tablet button. @@ -203,7 +203,7 @@ // showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode // // Arguments: - // forceRemove: Set to "true" to force removal of the button, i.e. upon shutdown + // shouldntAdd: Set to "true" if you don't want to add the button, i.e. upon shutdown // isHMDMode: "true" if user is in HMD; false otherwise // // Description: @@ -212,10 +212,10 @@ var button = false; var buttonName = "SPECTATOR"; var tablet = null; - var showSpectatorInDesktop = false; - function addOrRemoveButton(forceRemove, isHMDMode) { + var showSpectatorInDesktop = true; + function addOrRemoveButton(shouldntAdd, isHMDMode) { if (!button) { - if ((isHMDMode || showSpectatorInDesktop) && !forceRemove) { + if ((isHMDMode || showSpectatorInDesktop) && !shouldntAdd) { button = tablet.addButton({ text: buttonName }); @@ -226,7 +226,7 @@ tablet.removeButton(button); button = false; } else { - print("ERROR adding/removing Spectator button!") + print("ERROR adding/removing Spectator button!"); } } From a795822919e9d11662ed76b5e16a8daefb726e9e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Jun 2017 17:12:37 -0700 Subject: [PATCH 49/79] Comments and disable camera when switching --- scripts/system/spectatorCamera.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index a7f5dbcc79..f8186f26fe 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -187,12 +187,6 @@ setDisplay(monitorShowsCameraView); } - function onHMDChanged(isHMDMode) { - // Will also eventually enable disable app, camera, etc. - setDisplay(monitorShowsCameraView); - addOrRemoveButton(false, isHMDMode); - } - // // Function Name: addOrRemoveButton() // @@ -407,6 +401,26 @@ } } + // + // Function Name: onHMDChanged() + // + // Relevant Variables: + // None + // + // Arguments: + // isHMDMode: "true" if HMD is on; "false" otherwise + // + // Description: + // Called from C++ when HMD mode is changed + // + function onHMDChanged(isHMDMode) { + setDisplay(monitorShowsCameraView); + addOrRemoveButton(false, isHMDMode); + if (!isHMDMode && !showSpectatorInDesktop) { + spectatorCameraOff(); + } + } + // // Function Name: shutdown() // From 68662bb209f1cc92da2616676883d4a0d9545da8 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 10:20:17 -0700 Subject: [PATCH 50/79] Bugfixes --- scripts/system/spectatorCamera.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index f8186f26fe..6095a960cd 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -197,7 +197,7 @@ // showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode // // Arguments: - // shouldntAdd: Set to "true" if you don't want to add the button, i.e. upon shutdown + // isShuttingDown: Set to "true" if you're calling this function upon script shutdown // isHMDMode: "true" if user is in HMD; false otherwise // // Description: @@ -207,18 +207,20 @@ var buttonName = "SPECTATOR"; var tablet = null; var showSpectatorInDesktop = true; - function addOrRemoveButton(shouldntAdd, isHMDMode) { + function addOrRemoveButton(isShuttingDown, isHMDMode) { if (!button) { - if ((isHMDMode || showSpectatorInDesktop) && !shouldntAdd) { + if ((isHMDMode || showSpectatorInDesktop) && !isShuttingDown) { button = tablet.addButton({ text: buttonName }); button.clicked.connect(onTabletButtonClicked); } } else if (button) { - button.clicked.disconnect(onTabletButtonClicked); - tablet.removeButton(button); - button = false; + if ((!showSpectatorInDesktop || isShuttingDown) && !isHMDMode) { + button.clicked.disconnect(onTabletButtonClicked); + tablet.removeButton(button); + button = false; + } } else { print("ERROR adding/removing Spectator button!"); } From 47e5fb56d3639956105489f1c18c43bdd6fdf807 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 11:31:20 -0700 Subject: [PATCH 51/79] Show MyAvatar's head in the SpectatorCamera view! --- interface/src/SecondaryCamera.cpp | 3 +++ interface/src/avatar/MyAvatar.cpp | 5 ++--- interface/src/avatar/MyAvatar.h | 2 +- libraries/render-utils/src/CauterizedMeshPartPayload.cpp | 2 +- libraries/shared/src/RenderArgs.h | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 257c8454c5..f6ee8caa61 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -71,9 +71,11 @@ public: _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; _cachedArgsPointer->_viewport = args->_viewport; _cachedArgsPointer->_displayMode = args->_displayMode; + _cachedArgsPointer->_renderMode = args->_renderMode; args->_blitFramebuffer = destFramebuffer; args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); args->_displayMode = RenderArgs::MONO; + args->_renderMode = RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.disableContextStereo(); @@ -106,6 +108,7 @@ public: args->_viewport = cachedArgs->_viewport; args->popViewFrustum(); args->_displayMode = cachedArgs->_displayMode; + args->_renderMode = cachedArgs->_renderMode; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.restoreContextStereo(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1adcfbd345..18bee773b0 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1881,15 +1881,14 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f; -bool MyAvatar::cameraInsideHead() const { - const glm::vec3 cameraPosition = qApp->getCamera().getPosition(); +bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const { return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE; bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; - bool insideHead = cameraInsideHead(); + bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); return !defaultMode || !firstPerson || !insideHead; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f61f24fb11..752b89bef6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -615,7 +615,7 @@ private: float scale = 1.0f, bool isSoft = false, bool allowDuplicates = false, bool useSaved = true) override; - bool cameraInsideHead() const; + bool cameraInsideHead(const glm::vec3& cameraPosition) const; void updateEyeContactTarget(float deltaTime); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index f3ee846d39..07628904f1 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -29,7 +29,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh( void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { // Still relying on the raw data from the model - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE); + bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE); if (useCauterizedMesh) { ModelPointer model = _model.lock(); if (model) { diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index d4d88c26a8..f869a93e1f 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -75,7 +75,7 @@ public: class RenderArgs { public: - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; enum DebugFlags { RENDER_DEBUG_NONE = 0, From 834a2a5c3b2f2241a379175bfcab80db721b1639 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 12:49:09 -0700 Subject: [PATCH 52/79] Ensure monitor never shows frozen SpectatorCamera preview --- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 16 ++++++++++++++++ .../src/display-plugins/hmd/HmdDisplayPlugin.h | 2 ++ 2 files changed, 18 insertions(+) diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index ea91890f33..260ac5fa4c 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -743,3 +743,19 @@ HmdDisplayPlugin::~HmdDisplayPlugin() { float HmdDisplayPlugin::stutterRate() const { return _stutterRate.rate(); } + +bool HmdDisplayPlugin::setDisplayTexture(const QString& name) { + // Note: it is the caller's responsibility to keep the network texture in cache. + if (name.isEmpty()) { + _displayTexture.reset(); + _clearPreviewFlag = true; + return true; + } + auto textureCache = DependencyManager::get(); + auto displayNetworkTexture = textureCache->getTexture(name); + if (!displayNetworkTexture) { + return false; + } + _displayTexture = displayNetworkTexture->getGPUTexture(); + return !!_displayTexture; +} diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index aaa6e347e0..78b3889179 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -46,6 +46,8 @@ public: float stutterRate() const override; + virtual bool setDisplayTexture(const QString& name) override; + protected: virtual void hmdPresent() = 0; virtual bool isHmdMounted() const = 0; From 1088d248e3bc0e21c7c8278110183954e16dcada Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 13:13:58 -0700 Subject: [PATCH 53/79] Howard's CR comments --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 1 + .../src/display-plugins/OpenGLDisplayPlugin.h | 1 + .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 16 ---------------- .../src/display-plugins/hmd/HmdDisplayPlugin.h | 2 +- libraries/plugins/src/plugins/DisplayPlugin.h | 1 + 5 files changed, 4 insertions(+), 17 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index ba8842c2ec..92afa8ef22 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -706,6 +706,7 @@ bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { // Note: it is the caller's responsibility to keep the network texture in cache. if (name.isEmpty()) { _displayTexture.reset(); + clearPreviewFlag(); return true; } auto textureCache = DependencyManager::get(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index cf874fb721..aa047b4538 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -58,6 +58,7 @@ public: } virtual bool setDisplayTexture(const QString& name) override; + virtual bool clearPreviewFlag() override { return false; }; QImage getScreenshot(float aspectRatio = 0.0f) const override; float presentRate() const override; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 260ac5fa4c..ea91890f33 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -743,19 +743,3 @@ HmdDisplayPlugin::~HmdDisplayPlugin() { float HmdDisplayPlugin::stutterRate() const { return _stutterRate.rate(); } - -bool HmdDisplayPlugin::setDisplayTexture(const QString& name) { - // Note: it is the caller's responsibility to keep the network texture in cache. - if (name.isEmpty()) { - _displayTexture.reset(); - _clearPreviewFlag = true; - return true; - } - auto textureCache = DependencyManager::get(); - auto displayNetworkTexture = textureCache->getTexture(name); - if (!displayNetworkTexture) { - return false; - } - _displayTexture = displayNetworkTexture->getGPUTexture(); - return !!_displayTexture; -} diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 78b3889179..58ef109525 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -46,7 +46,7 @@ public: float stutterRate() const override; - virtual bool setDisplayTexture(const QString& name) override; + virtual bool clearPreviewFlag() override { _clearPreviewFlag = true; return true; }; protected: virtual void hmdPresent() = 0; diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 7bfdbddbc5..bce6c0c33a 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -186,6 +186,7 @@ public: // Set the texture to display on the monitor and return true, if allowed. Empty string resets. virtual bool setDisplayTexture(const QString& name) { return false; } + virtual bool clearPreviewFlag() { return false; }; virtual float devicePixelRatio() { return 1.0f; } // Rate at which we render frames From d7a9354b370098d8032d339be2a7e86fd47b07e1 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 13:25:16 -0700 Subject: [PATCH 54/79] More CR comments; rename function --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp | 2 +- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.h | 2 +- .../display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h | 2 +- libraries/plugins/src/plugins/DisplayPlugin.h | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 92afa8ef22..67bbb452ca 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -706,7 +706,7 @@ bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { // Note: it is the caller's responsibility to keep the network texture in cache. if (name.isEmpty()) { _displayTexture.reset(); - clearPreviewFlag(); + onDisplayTextureReset(); return true; } auto textureCache = DependencyManager::get(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index aa047b4538..7e7889ff47 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -58,7 +58,7 @@ public: } virtual bool setDisplayTexture(const QString& name) override; - virtual bool clearPreviewFlag() override { return false; }; + virtual bool onDisplayTextureReset() { return false; }; QImage getScreenshot(float aspectRatio = 0.0f) const override; float presentRate() const override; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index 58ef109525..055328ee21 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -46,7 +46,7 @@ public: float stutterRate() const override; - virtual bool clearPreviewFlag() override { _clearPreviewFlag = true; return true; }; + virtual bool onDisplayTextureReset() override { _clearPreviewFlag = true; return true; }; protected: virtual void hmdPresent() = 0; diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index bce6c0c33a..7bfdbddbc5 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -186,7 +186,6 @@ public: // Set the texture to display on the monitor and return true, if allowed. Empty string resets. virtual bool setDisplayTexture(const QString& name) { return false; } - virtual bool clearPreviewFlag() { return false; }; virtual float devicePixelRatio() { return 1.0f; } // Rate at which we render frames From 8cf9c8708df108fcda953af9fb8dd771a08d139c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 14:50:34 -0700 Subject: [PATCH 55/79] Allow user to click left thumbstick to switch 'MONITOR SHOWS' --- .../resources/qml/hifi/SpectatorCamera.qml | 3 ++ scripts/system/spectatorCamera.js | 54 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 544fc72927..fcbac5e60d 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -288,6 +288,9 @@ Rectangle { case 'updateMonitorShowsSwitch': monitorShowsSwitch.checked = message.params; break; + case 'updateControllerMappingCheckbox': + switchViewFromControllerCheckBox.checked = message.params; + break; default: console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); } diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 6095a960cd..26fca11305 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -18,9 +18,7 @@ // FUNCTION VAR DECLARATIONS // var sendToQml, addOrRemoveButton, onTabletScreenChanged, fromQml, - onTabletButtonClicked, wireEventBridge, startup, shutdown; - - + onTabletButtonClicked, wireEventBridge, startup, shutdown, registerButtonMappings; // // Function Name: inFrontOf() @@ -247,6 +245,7 @@ HMD.displayModeChanged.connect(onHMDChanged); viewFinderOverlay = false; camera = false; + registerButtonMappings(); } // @@ -301,6 +300,52 @@ } } + const SWITCH_VIEW_FROM_CONTROLLER_DEFAULT = false; + var switchViewFromController = !!Settings.getValue('spectatorCamera/switchViewFromController', SWITCH_VIEW_FROM_CONTROLLER_DEFAULT); + function setControllerMappingStatus(status) { + if (status === true) { + controllerMapping.enable(); + } else { + controllerMapping.disable(); + } + } + function setSwitchViewFromController(setting) { + if (setting === switchViewFromController) { + return; + } + switchViewFromController = setting; + setControllerMappingStatus(switchViewFromController); + Settings.setValue('spectatorCamera/switchViewFromController', setting); + } + + // + // Function Name: registerButtonMappings() + // + // Relevant Variables: + // controllerMappingName: The name of the controller mapping + // controllerMapping: The controller mapping itself + // + // Arguments: + // None + // + // Description: + // Updates controller button mappings for Spectator Camera. + // + var controllerMappingName; + var controllerMapping; + function registerButtonMappings() { + controllerMappingName = 'Hifi-SpectatorCamera-Mapping-' + Math.random(); + controllerMapping = Controller.newMapping(controllerMappingName); + controllerMapping.from(Controller.Standard.LS).to(function (value) { + if (value === 1.0) { + setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); + } + return; + }); + setControllerMappingStatus(switchViewFromController); + sendToQml({ method: 'updateControllerMappingCheckbox', params: switchViewFromController }); + } + // // Function Name: onTabletButtonClicked() // @@ -396,7 +441,7 @@ setMonitorShowsCameraView(message.params); break; case 'changeSwitchViewFromControllerPreference': - print('FIXME: Preference is now: ' + message.params); + setSwitchViewFromController(message.params); break; default: print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); @@ -442,6 +487,7 @@ tablet.screenChanged.disconnect(onTabletScreenChanged); HMD.displayModeChanged.disconnect(onHMDChanged); Controller.keyPressEvent.disconnect(keyPressEvent); + controllerMapping.disable(); } // From 65b910bcf68bca4c70bf0d471d3d80c443ac0534 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 15:15:56 -0700 Subject: [PATCH 56/79] Support Vive --- scripts/system/spectatorCamera.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 26fca11305..744d8501a4 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -324,6 +324,7 @@ // Relevant Variables: // controllerMappingName: The name of the controller mapping // controllerMapping: The controller mapping itself + // controllerType: "OculusTouch", "Vive", "Other" // // Arguments: // None @@ -333,15 +334,32 @@ // var controllerMappingName; var controllerMapping; + var controllerType = "Other"; function registerButtonMappings() { + var controllersDeviceNames = Controller.getDeviceNames(); + if (controllersDeviceNames.indexOf("OculusTouch") !== -1) { + controllerType = "OculusTouch"; + } else if (controllerDeviceNames.indexOf("Vive") !== -1) { + controllerType = "Vive"; + } + controllerMappingName = 'Hifi-SpectatorCamera-Mapping-' + Math.random(); controllerMapping = Controller.newMapping(controllerMappingName); - controllerMapping.from(Controller.Standard.LS).to(function (value) { - if (value === 1.0) { - setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); - } - return; - }); + if (controllerType === "OculusTouch") { + controllerMapping.from(Controller.Standard.LS).to(function (value) { + if (value === 1.0) { + setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); + } + return; + }); + } else if (controllerType === "Vive") { + controllerMapping.from(Controller.Standard.LeftPrimaryThumb).to(function (value) { + if (value === 1.0) { + setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); + } + return; + }); + } setControllerMappingStatus(switchViewFromController); sendToQml({ method: 'updateControllerMappingCheckbox', params: switchViewFromController }); } From 3df414df36156f1d66a836f3f7f31e64a8b236c3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 16:10:05 -0700 Subject: [PATCH 57/79] Bugfixes and language changes --- interface/resources/qml/hifi/SpectatorCamera.qml | 14 ++++++++++++-- scripts/system/spectatorCamera.js | 6 +++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index fcbac5e60d..80b92a9e08 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -253,7 +253,7 @@ Rectangle { anchors.left: parent.left; anchors.top: monitorShowsSwitch.bottom; anchors.topMargin: 25; - text: "Pressing Vive's Left Thumbpad Switches Monitor View"; + text: "Pressing Ctrl+0 Switches Monitor View"; boxSize: 24; onClicked: { sendToScript({method: 'changeSwitchViewFromControllerPreference', params: checked}); @@ -289,7 +289,17 @@ Rectangle { monitorShowsSwitch.checked = message.params; break; case 'updateControllerMappingCheckbox': - switchViewFromControllerCheckBox.checked = message.params; + switchViewFromControllerCheckBox.checked = message.setting; + switchViewFromControllerCheckBox.enabled = true; + if (message.controller === "OculusTouch") { + switchViewFromControllerCheckBox.text = "Clicking Left Touch's Thumbstick Switches Monitor View"; + } else if (message.controller === "Vive") { + switchViewFromControllerCheckBox.text = "Clicking Left Thumb Pad Switches Monitor View"; + } else { + switchViewFromControllerCheckBox.text = "Pressing Ctrl+0 Switches Monitor View"; + switchViewFromControllerCheckBox.checked = true; + switchViewFromControllerCheckBox.enabled = false; + } break; default: console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 744d8501a4..d6d3f230b2 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -361,7 +361,7 @@ }); } setControllerMappingStatus(switchViewFromController); - sendToQml({ method: 'updateControllerMappingCheckbox', params: switchViewFromController }); + sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType }); } // @@ -389,8 +389,8 @@ tablet.loadQMLSource("../SpectatorCamera.qml"); onSpectatorCameraScreen = true; sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); - sendToQml({ method: 'updateMonitorShowsSwitch', params: !!Settings.getValue('spectatorCamera/monitorShowsCameraView', false) }); - setMonitorShowsCameraViewAndSendToQml(monitorShowsCameraView); + sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView }); + sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType }); } } From 749dede8b3d12fb8b9fbdb7fc3fc4f3512515b4d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 16:34:13 -0700 Subject: [PATCH 58/79] Start with empty string for checkbox --- interface/resources/qml/hifi/SpectatorCamera.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 80b92a9e08..6bb25b2958 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -253,7 +253,7 @@ Rectangle { anchors.left: parent.left; anchors.top: monitorShowsSwitch.bottom; anchors.topMargin: 25; - text: "Pressing Ctrl+0 Switches Monitor View"; + text: ""; boxSize: 24; onClicked: { sendToScript({method: 'changeSwitchViewFromControllerPreference', params: checked}); From e2c6993ae95f6d4da482a0d19e2a491dde25d95a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 15 Jun 2017 19:07:10 -0700 Subject: [PATCH 59/79] Fix bug found by Cain with his patch - thank you! --- scripts/system/spectatorCamera.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index d6d3f230b2..e8efb98826 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -336,11 +336,11 @@ var controllerMapping; var controllerType = "Other"; function registerButtonMappings() { - var controllersDeviceNames = Controller.getDeviceNames(); - if (controllersDeviceNames.indexOf("OculusTouch") !== -1) { - controllerType = "OculusTouch"; - } else if (controllerDeviceNames.indexOf("Vive") !== -1) { + var VRDevices = Controller.getDeviceNames().toString(); + if (VRDevices.includes("Vive")) { controllerType = "Vive"; + } else if (VRDevices.includes("OculusTouch")) { + controllerType = "OculusTouch"; } controllerMappingName = 'Hifi-SpectatorCamera-Mapping-' + Math.random(); From 378d8e80cf8f1b8a22128489c8b20aed7fd51f93 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 16 Jun 2017 09:46:14 -0700 Subject: [PATCH 60/79] Remove random component of button mapping name --- scripts/system/spectatorCamera.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index e8efb98826..725de0215c 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -303,7 +303,7 @@ const SWITCH_VIEW_FROM_CONTROLLER_DEFAULT = false; var switchViewFromController = !!Settings.getValue('spectatorCamera/switchViewFromController', SWITCH_VIEW_FROM_CONTROLLER_DEFAULT); function setControllerMappingStatus(status) { - if (status === true) { + if (status) { controllerMapping.enable(); } else { controllerMapping.disable(); @@ -343,7 +343,7 @@ controllerType = "OculusTouch"; } - controllerMappingName = 'Hifi-SpectatorCamera-Mapping-' + Math.random(); + controllerMappingName = 'Hifi-SpectatorCamera-Mapping'; controllerMapping = Controller.newMapping(controllerMappingName); if (controllerType === "OculusTouch") { controllerMapping.from(Controller.Standard.LS).to(function (value) { From 35a0c41cf59ee6f3641e03e82e4cb2b888958eff Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 10:54:03 -0700 Subject: [PATCH 61/79] Move Ktx processing to thread pool. --- libraries/gpu/src/gpu/Texture_ktx.cpp | 5 + .../src/model-networking/TextureCache.cpp | 195 +++++++++++++----- .../src/model-networking/TextureCache.h | 2 +- libraries/networking/src/FileCache.cpp | 7 +- libraries/shared/src/shared/Storage.cpp | 7 + 5 files changed, 157 insertions(+), 59 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index f455fde009..8c185e0b22 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "GPULogging.h" @@ -242,6 +243,7 @@ uint16 KtxStorage::minAvailableMipLevel() const { } void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) { + PROFILE_RANGE(app, __FUNCTION__) if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored, expected: " << (_minMipLevelAvailable - 1) << ", got: " << level << " " << _filename.c_str(); return; @@ -283,6 +285,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor } memcpy(imageData, storage->data(), storage->size()); + _minMipLevelAvailable = level; if (_offsetToMinMipKV > 0) { auto minMipKeyData = fileData + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; @@ -311,6 +314,7 @@ void Texture::setKtxBacking(const std::string& filename) { ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { + PROFILE_RANGE(app, __FUNCTION__) ktx::Header header; // From texture format to ktx format description @@ -453,6 +457,7 @@ TexturePointer Texture::unserialize(const std::string& ktxfile) { } TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDescriptor& descriptor) { + PROFILE_RANGE(app, __FUNCTION__) const auto& header = descriptor.header; Format mipFormat = Format::COLOR_BGRA_32; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8683d56b6b..3158ab386d 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -300,16 +300,23 @@ void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth, _textureSource->resetTexture(texture); if (texture) { + if (_sourceIsKTX) { + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + } + _width = texture->getWidth(); _height = texture->getHeight(); setSize(texture->getStoredSize()); + finishedLoading(true); } else { // FIXME: If !gpuTexture, we failed to load! - _width = _height = 0; - qWarning() << "Texture did not load"; - } + if (_sourceIsKTX) { + _ktxResourceState = FAILED_TO_LOAD; + } - finishedLoading(true); + _width = _height = 0; + finishedLoading(false); + } emit networkTextureCreated(qWeakPointerCast (_self)); } @@ -407,6 +414,7 @@ void NetworkTexture::makeRequest() { } void NetworkTexture::startRequestForNextMipLevel() { + PROFILE_RANGE(app, __FUNCTION__); if (_lowestKnownPopulatedMip == 0) { qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _lowestKnownPopulatedMip << " " << _textureSource->getGPUTexture()->minAvailableMipLevel() << " " << _url; @@ -434,6 +442,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { if (_ktxMipRequest) { return; } + PROFILE_RANGE(app, __FUNCTION__); bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL; @@ -470,41 +479,101 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { void NetworkTexture::ktxHeaderRequestFinished() { + PROFILE_RANGE(app, __FUNCTION__); + + Q_ASSERT_X(_ktxHeaderRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); - if (!_ktxHeaderRequest) { + PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { + { "from_cache", _ktxHeaderRequest->loadedFromCache() }, + { "size_mb", _bytesTotal / 1000000.0 } + }); + + setSize(_bytesTotal); + + if (!_ktxHeaderRequest || _ktxHeaderRequest != sender()) { + // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. + qWarning(networking) << "Received signal NetworkTexture::ktxHeaderRequestFinished from ResourceRequest that is not the current" + << " request: " << sender() << ", " << _ktxHeaderRequest; return; } - _ktxHeaderRequestFinished = true; - maybeHandleFinishedInitialLoad(); + ResourceCache::requestCompleted(_self); + + auto result = _ktxHeaderRequest->getResult(); + if (result == ResourceRequest::Success) { + auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); + qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); + + auto data = _ktxHeaderRequest->getData(); + + //emit loaded(data); + //downloadFinished(data); + _ktxHeaderRequestFinished = true; + maybeHandleFinishedInitialLoad(); + + } else { + handleFailedRequest(result); + } + + _ktxHeaderRequest->disconnect(this); + _ktxHeaderRequest->deleteLater(); + _ktxHeaderRequest = nullptr; } void NetworkTexture::ktxMipRequestFinished() { + PROFILE_RANGE(app, __FUNCTION__); + + Q_ASSERT_X(_ktxMipRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA || _ktxResourceState == REQUESTING_MIP); - if (!_ktxMipRequest) { + PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { + { "from_cache", _ktxMipRequest->loadedFromCache() }, + { "size_mb", _bytesTotal / 1000000.0 } + }); + + setSize(_bytesTotal); + + if (!_ktxMipRequest || _ktxMipRequest != sender()) { + // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. + qWarning(networking) << "Received signal NetworkTexture::ktxHeaderRequestFinished from ResourceRequest that is not the current" + << " request: " << sender() << ", " << _ktxMipRequest; return; } - if (_ktxResourceState == LOADING_INITIAL_DATA) { - _ktxHighMipRequestFinished = true; - maybeHandleFinishedInitialLoad(); - } else if (_ktxResourceState == REQUESTING_MIP) { - Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); - TextureCache::requestCompleted(_self); + ResourceCache::requestCompleted(_self); - if (_ktxMipRequest->getResult() == ResourceRequest::Success) { + auto result = _ktxMipRequest->getResult(); + if (result == ResourceRequest::Success) { + auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); + qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); + + auto data = _ktxMipRequest->getData(); + + //emit loaded(data); + //downloadFinished(data); + + if (_ktxResourceState == LOADING_INITIAL_DATA) { + _ktxHighMipRequestFinished = true; + + //// + maybeHandleFinishedInitialLoad(); + } else if (_ktxResourceState == REQUESTING_MIP) { + Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); + _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) { + startRequestForNextMipLevel(); + } + + //// auto texture = _textureSource->getGPUTexture(); if (texture) { - texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, - _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); - + texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, + _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) { - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - _ktxResourceState = WAITING_FOR_MIP_REQUEST; } else { qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first; _ktxResourceState = FAILED_TO_LOAD; @@ -514,29 +583,29 @@ void NetworkTexture::ktxMipRequestFinished() { qWarning(networking) << "Trying to update mips but texture is null"; } finishedLoading(true); + } else { - finishedLoading(false); - if (handleFailedRequest(_ktxMipRequest->getResult())) { - _ktxResourceState = PENDING_MIP_REQUEST; - } else { - qWarning(networking) << "Failed to load mip: " << _url; - _ktxResourceState = FAILED_TO_LOAD; - } + qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState; } - _ktxMipRequest->deleteLater(); - _ktxMipRequest = nullptr; - if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) { - startRequestForNextMipLevel(); - } } else { - qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState; + if (handleFailedRequest(result)) { + _ktxResourceState = PENDING_MIP_REQUEST; + } else { + _ktxResourceState = FAILED_TO_LOAD; + } } + + _ktxMipRequest->disconnect(this); + _ktxMipRequest->deleteLater(); + _ktxMipRequest = nullptr; } // This is called when the header or top mips have been loaded void NetworkTexture::maybeHandleFinishedInitialLoad() { + PROFILE_RANGE(app, __FUNCTION__); + Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); if (_ktxHeaderRequestFinished && _ktxHighMipRequestFinished) { @@ -546,15 +615,9 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { if (_ktxHeaderRequest->getResult() != ResourceRequest::Success || _ktxMipRequest->getResult() != ResourceRequest::Success) { if (handleFailedRequest(_ktxMipRequest->getResult())) { _ktxResourceState = PENDING_INITIAL_LOAD; - } - else { + } else { _ktxResourceState = FAILED_TO_LOAD; } - - _ktxHeaderRequest->deleteLater(); - _ktxHeaderRequest = nullptr; - _ktxMipRequest->deleteLater(); - _ktxMipRequest = nullptr; } else { // create ktx... auto ktxHeaderData = _ktxHeaderRequest->getData(); @@ -564,16 +627,20 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { if (!ktx::checkIdentifier(header->identifier)) { qWarning() << "Cannot load " << _url << ", invalid header identifier"; - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } auto kvSize = header->bytesOfKeyValueData; if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } @@ -582,8 +649,11 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { auto imageDescriptors = header->generateImageDescriptors(); if (imageDescriptors.size() == 0) { qWarning(networking) << "Failed to process ktx file " << _url; - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; } _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); @@ -595,8 +665,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { std::string hash; if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { qWarning("Invalid source hash key found, bailing"); - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } else { // at this point the source hash is in binary 16-byte form @@ -624,7 +696,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { auto memKtx = ktx::KTX::createBare(*header, keyValues); if (!memKtx) { qWarning() << " Ktx could not be created, bailing"; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } @@ -635,8 +710,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { auto& ktxCache = textureCache->_ktxCache; if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { qCWarning(modelnetworking) << _url << " failed to write cache file"; - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } else { _file = file; @@ -672,14 +749,18 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - _ktxResourceState = WAITING_FOR_MIP_REQUEST; - setImage(texture, header->getPixelWidth(), header->getPixelHeight()); - _ktxHeaderRequest->deleteLater(); - _ktxHeaderRequest = nullptr; - _ktxMipRequest->deleteLater(); - _ktxMipRequest = nullptr; + QMetaObject::invokeMethod(resource.data(), "ktxRequestProcessed", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); } + + _ktxHeaderRequest->deleteLater(); + _ktxHeaderRequest = nullptr; + _ktxMipRequest->deleteLater(); + _ktxMipRequest = nullptr; + startRequestForNextMipLevel(); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 7dab18d457..a17fbd353e 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -74,7 +74,7 @@ protected: virtual bool isCacheable() const override { return _loaded; } virtual void downloadFinished(const QByteArray& data) override; - + Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); diff --git a/libraries/networking/src/FileCache.cpp b/libraries/networking/src/FileCache.cpp index 95304e3866..c3cc55cbae 100644 --- a/libraries/networking/src/FileCache.cpp +++ b/libraries/networking/src/FileCache.cpp @@ -21,8 +21,9 @@ #include #include -#include #include +#include +#include #ifdef Q_OS_WIN #include @@ -87,6 +88,7 @@ FileCache::~FileCache() { } void FileCache::initialize() { + PROFILE_RANGE(app, __FUNCTION__) QDir dir(_dirpath.c_str()); if (dir.exists()) { @@ -127,6 +129,7 @@ FilePointer FileCache::addFile(Metadata&& metadata, const std::string& filepath) } FilePointer FileCache::writeFile(const char* data, File::Metadata&& metadata, bool overwrite) { + PROFILE_RANGE(app, __FUNCTION__) assert(_initialized); std::string filepath = getFilepath(metadata.key); @@ -319,6 +322,7 @@ File::File(Metadata&& metadata, const std::string& filepath) : } File::~File() { + PROFILE_RANGE(app, __FUNCTION__) QFile file(getFilepath().c_str()); if (file.exists() && !_shouldPersist) { qCInfo(file_cache, "Unlinked %s", getFilepath().c_str()); @@ -327,6 +331,7 @@ File::~File() { } void File::touch() { + PROFILE_RANGE(app, __FUNCTION__) utime(_filepath.c_str(), nullptr); _modified = std::max(QFileInfo(_filepath.c_str()).lastRead().toMSecsSinceEpoch(), _modified); } \ No newline at end of file diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index b07f896df0..3e1b357019 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -12,6 +12,8 @@ #include #include +#include "../Profile.h" + Q_LOGGING_CATEGORY(storagelogging, "hifi.core.storage") using namespace storage; @@ -48,6 +50,7 @@ MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) { } StoragePointer FileStorage::create(const QString& filename, size_t size, const uint8_t* data) { + PROFILE_RANGE(app, "FileStorage::create()"); QFile file(filename); if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) { throw std::runtime_error("Unable to open file for writing"); @@ -70,6 +73,8 @@ StoragePointer FileStorage::create(const QString& filename, size_t size, const u } FileStorage::FileStorage(const QString& filename) : _file(filename) { + PROFILE_RANGE(app, "FileStorage()"); + bool opened = _file.open(QFile::ReadWrite); if (opened) { _hasWriteAccess = true; @@ -79,6 +84,7 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) { } if (opened) { + PROFILE_RANGE(app, "FileStorage() map"); _mapped = _file.map(0, _file.size()); if (_mapped) { _valid = true; @@ -91,6 +97,7 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) { } FileStorage::~FileStorage() { + PROFILE_RANGE(app, "~FileStorage()"); if (_mapped) { if (!_file.unmap(_mapped)) { throw std::runtime_error("Unable to unmap file"); From 3110dd72bf4cc7d03cea48bff93a1ca5087da89c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 13:20:19 -0700 Subject: [PATCH 62/79] More ktx work --- .../src/model-networking/TextureCache.cpp | 313 ++++++++---------- 1 file changed, 141 insertions(+), 172 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3158ab386d..1cd5298df6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -498,17 +498,13 @@ void NetworkTexture::ktxHeaderRequestFinished() { return; } - ResourceCache::requestCompleted(_self); + TextureCache::requestCompleted(_self); auto result = _ktxHeaderRequest->getResult(); if (result == ResourceRequest::Success) { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - auto data = _ktxHeaderRequest->getData(); - - //emit loaded(data); - //downloadFinished(data); _ktxHeaderRequestFinished = true; maybeHandleFinishedInitialLoad(); @@ -541,51 +537,39 @@ void NetworkTexture::ktxMipRequestFinished() { return; } - ResourceCache::requestCompleted(_self); + TextureCache::requestCompleted(_self); auto result = _ktxMipRequest->getResult(); if (result == ResourceRequest::Success) { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - auto data = _ktxMipRequest->getData(); - - //emit loaded(data); - //downloadFinished(data); - if (_ktxResourceState == LOADING_INITIAL_DATA) { _ktxHighMipRequestFinished = true; - - //// maybeHandleFinishedInitialLoad(); } else if (_ktxResourceState == REQUESTING_MIP) { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); + _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; _ktxResourceState = WAITING_FOR_MIP_REQUEST; - if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) { + if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { startRequestForNextMipLevel(); } - //// + //// Move to other thread auto texture = _textureSource->getGPUTexture(); if (texture) { - texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, - _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); - if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) { - } else { - qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first; - _ktxResourceState = FAILED_TO_LOAD; - } - } else { - _ktxResourceState = WAITING_FOR_MIP_REQUEST; - qWarning(networking) << "Trying to update mips but texture is null"; + auto data = _ktxMipRequest->getData(); + texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, + data.size(), reinterpret_cast(data.data())); } finishedLoading(true); } else { - qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState; + qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState; + finishedLoading(false); } @@ -610,158 +594,143 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { if (_ktxHeaderRequestFinished && _ktxHighMipRequestFinished) { - TextureCache::requestCompleted(_self); + auto resource = _self; - if (_ktxHeaderRequest->getResult() != ResourceRequest::Success || _ktxMipRequest->getResult() != ResourceRequest::Success) { - if (handleFailedRequest(_ktxMipRequest->getResult())) { - _ktxResourceState = PENDING_INITIAL_LOAD; - } else { - _ktxResourceState = FAILED_TO_LOAD; - } - } else { - // create ktx... - auto ktxHeaderData = _ktxHeaderRequest->getData(); - auto ktxHighMipData = _ktxMipRequest->getData(); + // create ktx... + auto ktxHeaderData = _ktxHeaderRequest->getData(); + auto ktxHighMipData = _ktxMipRequest->getData(); - auto header = reinterpret_cast(ktxHeaderData.data()); + auto header = reinterpret_cast(ktxHeaderData.data()); - if (!ktx::checkIdentifier(header->identifier)) { - qWarning() << "Cannot load " << _url << ", invalid header identifier"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - auto kvSize = header->bytesOfKeyValueData; - if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { - qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); - - auto imageDescriptors = header->generateImageDescriptors(); - if (imageDescriptors.size() == 0) { - qWarning(networking) << "Failed to process ktx file " << _url; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); - - // Create bare ktx in memory - auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { - return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; - }); - std::string filename; - std::string hash; - if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { - qWarning("Invalid source hash key found, bailing"); - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } else { - // at this point the source hash is in binary 16-byte form - // and we need it in a hexadecimal string - auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); - hash = filename = binaryHash.toHex().toStdString(); - } - - auto textureCache = DependencyManager::get(); - - gpu::TexturePointer texture = textureCache->getTextureByHash(hash); - - if (!texture) { - KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); - if (ktxFile) { - texture = gpu::Texture::unserialize(ktxFile->getFilepath()); - if (texture) { - texture = textureCache->cacheTextureByHash(hash, texture); - } - } - } - - if (!texture) { - - auto memKtx = ktx::KTX::createBare(*header, keyValues); - if (!memKtx) { - qWarning() << " Ktx could not be created, bailing"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - // Move ktx to file - const char* data = reinterpret_cast(memKtx->_storage->data()); - size_t length = memKtx->_storage->size(); - KTXFilePointer file; - auto& ktxCache = textureCache->_ktxCache; - if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << " failed to write cache file"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } else { - _file = file; - } - - auto newKtxDescriptor = memKtx->toDescriptor(); - - texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); - texture->setKtxBacking(file->getFilepath()); - texture->setSource(filename); - - auto& images = _originalKtxDescriptor->images; - size_t imageSizeRemaining = ktxHighMipData.size(); - uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); - ktxData += ktxHighMipData.size(); - // TODO Move image offset calculation to ktx ImageDescriptor - for (int level = static_cast(images.size()) - 1; level >= 0; --level) { - auto& image = images[level]; - if (image._imageSize > imageSizeRemaining) { - break; - } - ktxData -= image._imageSize; - texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); - ktxData -= ktx::IMAGE_SIZE_WIDTH; - imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); - } - - // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different - // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will - // be the winner - texture = textureCache->cacheTextureByHash(filename, texture); - } - - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - - - QMetaObject::invokeMethod(resource.data(), "ktxRequestProcessed", - Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, texture->getWidth()), - Q_ARG(int, texture->getHeight())); + if (!ktx::checkIdentifier(header->identifier)) { + qWarning() << "Cannot load " << _url << ", invalid header identifier"; + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; } - _ktxHeaderRequest->deleteLater(); - _ktxHeaderRequest = nullptr; - _ktxMipRequest->deleteLater(); - _ktxMipRequest = nullptr; + auto kvSize = header->bytesOfKeyValueData; + if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { + qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } - startRequestForNextMipLevel(); + auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); + + auto imageDescriptors = header->generateImageDescriptors(); + if (imageDescriptors.size() == 0) { + qWarning(networking) << "Failed to process ktx file " << _url; + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); + + // Create bare ktx in memory + auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { + return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; + }); + std::string filename; + std::string hash; + if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { + qWarning("Invalid source hash key found, bailing"); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } else { + // at this point the source hash is in binary 16-byte form + // and we need it in a hexadecimal string + auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); + hash = filename = binaryHash.toHex().toStdString(); + } + + auto textureCache = DependencyManager::get(); + + gpu::TexturePointer texture = textureCache->getTextureByHash(hash); + + if (!texture) { + KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); + if (ktxFile) { + texture = gpu::Texture::unserialize(ktxFile->getFilepath()); + if (texture) { + texture = textureCache->cacheTextureByHash(hash, texture); + } + } + } + + if (!texture) { + + auto memKtx = ktx::KTX::createBare(*header, keyValues); + if (!memKtx) { + qWarning() << " Ktx could not be created, bailing"; + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + // Move ktx to file + const char* data = reinterpret_cast(memKtx->_storage->data()); + size_t length = memKtx->_storage->size(); + KTXFilePointer file; + auto& ktxCache = textureCache->_ktxCache; + if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { + qCWarning(modelnetworking) << _url << " failed to write cache file"; + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } else { + _file = file; + } + + auto newKtxDescriptor = memKtx->toDescriptor(); + + texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); + texture->setKtxBacking(file->getFilepath()); + texture->setSource(filename); + + auto& images = _originalKtxDescriptor->images; + size_t imageSizeRemaining = ktxHighMipData.size(); + uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); + ktxData += ktxHighMipData.size(); + // TODO Move image offset calculation to ktx ImageDescriptor + for (int level = static_cast(images.size()) - 1; level >= 0; --level) { + auto& image = images[level]; + if (image._imageSize > imageSizeRemaining) { + break; + } + ktxData -= image._imageSize; + texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); + ktxData -= ktx::IMAGE_SIZE_WIDTH; + imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); + } + + // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different + // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will + // be the winner + texture = textureCache->cacheTextureByHash(filename, texture); + } + + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + + + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); } } From d2251bb8402ba15b2b12b973175ffec4cc8435ea Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 15:44:34 -0700 Subject: [PATCH 63/79] Offload ktx processing to threadpool --- .../src/model-networking/TextureCache.cpp | 315 +++++++++--------- .../src/model-networking/TextureCache.h | 6 +- 2 files changed, 169 insertions(+), 152 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1cd5298df6..7ccf081183 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -13,6 +13,8 @@ #include +#include + #include #include #include @@ -300,20 +302,11 @@ void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth, _textureSource->resetTexture(texture); if (texture) { - if (_sourceIsKTX) { - _ktxResourceState = WAITING_FOR_MIP_REQUEST; - } - _width = texture->getWidth(); _height = texture->getHeight(); setSize(texture->getStoredSize()); finishedLoading(true); } else { - // FIXME: If !gpuTexture, we failed to load! - if (_sourceIsKTX) { - _ktxResourceState = FAILED_TO_LOAD; - } - _width = _height = 0; finishedLoading(false); } @@ -484,10 +477,10 @@ void NetworkTexture::ktxHeaderRequestFinished() { Q_ASSERT_X(_ktxHeaderRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); - PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { - { "from_cache", _ktxHeaderRequest->loadedFromCache() }, - { "size_mb", _bytesTotal / 1000000.0 } - }); + //PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { + // { "from_cache", _ktxHeaderRequest->loadedFromCache() }, + // { "size_mb", _bytesTotal / 1000000.0 } + //}); setSize(_bytesTotal); @@ -505,9 +498,8 @@ void NetworkTexture::ktxHeaderRequestFinished() { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - _ktxHeaderRequestFinished = true; + _ktxHeaderData = _ktxHeaderRequest->getData(); maybeHandleFinishedInitialLoad(); - } else { handleFailedRequest(result); } @@ -545,7 +537,7 @@ void NetworkTexture::ktxMipRequestFinished() { qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); if (_ktxResourceState == LOADING_INITIAL_DATA) { - _ktxHighMipRequestFinished = true; + _ktxHighMipData = _ktxMipRequest->getData(); maybeHandleFinishedInitialLoad(); } else if (_ktxResourceState == REQUESTING_MIP) { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); @@ -558,21 +550,37 @@ void NetworkTexture::ktxMipRequestFinished() { startRequestForNextMipLevel(); } - //// Move to other thread - auto texture = _textureSource->getGPUTexture(); - if (texture) { - auto data = _ktxMipRequest->getData(); - texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, - data.size(), reinterpret_cast(data.data())); - } - finishedLoading(true); + + auto self = _self; + auto data = _ktxMipRequest->getData(); + auto mipLevel = _ktxMipLevelRangeInFlight.first; + QtConcurrent::run(QThreadPool::globalInstance(), [this, self, data, mipLevel] { + auto that = self.lock(); + if (!that) { + // Resource no longer exists, bail + return; + } + + auto texture = _textureSource->getGPUTexture(); + if (texture) { + texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast(data.data())); + + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); + } else { + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + } + }); } else { qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState; finishedLoading(false); } - - } else { if (handleFailedRequest(result)) { _ktxResourceState = PENDING_MIP_REQUEST; @@ -588,149 +596,158 @@ void NetworkTexture::ktxMipRequestFinished() { // This is called when the header or top mips have been loaded void NetworkTexture::maybeHandleFinishedInitialLoad() { - PROFILE_RANGE(app, __FUNCTION__); - Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); - if (_ktxHeaderRequestFinished && _ktxHighMipRequestFinished) { - - auto resource = _self; + PROFILE_RANGE(app, __FUNCTION__); + if (!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty()) { // create ktx... - auto ktxHeaderData = _ktxHeaderRequest->getData(); - auto ktxHighMipData = _ktxMipRequest->getData(); + auto ktxHeaderData = _ktxHeaderData; + auto ktxHighMipData = _ktxHighMipData; + _ktxHeaderData.clear(); + _ktxHighMipData.clear(); - auto header = reinterpret_cast(ktxHeaderData.data()); - - if (!ktx::checkIdentifier(header->identifier)) { - qWarning() << "Cannot load " << _url << ", invalid header identifier"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - auto kvSize = header->bytesOfKeyValueData; - if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { - qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); - - auto imageDescriptors = header->generateImageDescriptors(); - if (imageDescriptors.size() == 0) { - qWarning(networking) << "Failed to process ktx file " << _url; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); - - // Create bare ktx in memory - auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { - return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; - }); - std::string filename; - std::string hash; - if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { - qWarning("Invalid source hash key found, bailing"); - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } else { - // at this point the source hash is in binary 16-byte form - // and we need it in a hexadecimal string - auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); - hash = filename = binaryHash.toHex().toStdString(); - } - - auto textureCache = DependencyManager::get(); - - gpu::TexturePointer texture = textureCache->getTextureByHash(hash); - - if (!texture) { - KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); - if (ktxFile) { - texture = gpu::Texture::unserialize(ktxFile->getFilepath()); - if (texture) { - texture = textureCache->cacheTextureByHash(hash, texture); - } - } - } - - if (!texture) { - - auto memKtx = ktx::KTX::createBare(*header, keyValues); - if (!memKtx) { - qWarning() << " Ktx could not be created, bailing"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); + auto self = _self; + QtConcurrent::run(QThreadPool::globalInstance(), [=] { + auto that = self.lock(); + if (!that) { + // Resource no longer exists, bail return; } - // Move ktx to file - const char* data = reinterpret_cast(memKtx->_storage->data()); - size_t length = memKtx->_storage->size(); - KTXFilePointer file; - auto& ktxCache = textureCache->_ktxCache; - if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << " failed to write cache file"; - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); + auto header = reinterpret_cast(ktxHeaderData.data()); + + if (!ktx::checkIdentifier(header->identifier)) { + qWarning() << "Cannot load " << _url << ", invalid header identifier"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + auto kvSize = header->bytesOfKeyValueData; + if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { + qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); + + auto imageDescriptors = header->generateImageDescriptors(); + if (imageDescriptors.size() == 0) { + qWarning(networking) << "Failed to process ktx file " << _url; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); + + // Create bare ktx in memory + auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { + return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; + }); + std::string filename; + std::string hash; + if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { + qWarning("Invalid source hash key found, bailing"); + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); return; } else { - _file = file; + // at this point the source hash is in binary 16-byte form + // and we need it in a hexadecimal string + auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); + hash = filename = binaryHash.toHex().toStdString(); } - auto newKtxDescriptor = memKtx->toDescriptor(); + auto textureCache = DependencyManager::get(); - texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); - texture->setKtxBacking(file->getFilepath()); - texture->setSource(filename); + gpu::TexturePointer texture = textureCache->getTextureByHash(hash); - auto& images = _originalKtxDescriptor->images; - size_t imageSizeRemaining = ktxHighMipData.size(); - uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); - ktxData += ktxHighMipData.size(); - // TODO Move image offset calculation to ktx ImageDescriptor - for (int level = static_cast(images.size()) - 1; level >= 0; --level) { - auto& image = images[level]; - if (image._imageSize > imageSizeRemaining) { - break; + if (!texture) { + KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); + if (ktxFile) { + texture = gpu::Texture::unserialize(ktxFile->getFilepath()); + if (texture) { + texture = textureCache->cacheTextureByHash(hash, texture); + } } - ktxData -= image._imageSize; - texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); - ktxData -= ktx::IMAGE_SIZE_WIDTH; - imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); } - // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different - // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will - // be the winner - texture = textureCache->cacheTextureByHash(filename, texture); - } + if (!texture) { - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + auto memKtx = ktx::KTX::createBare(*header, keyValues); + if (!memKtx) { + qWarning() << " Ktx could not be created, bailing"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + // Move ktx to file + const char* data = reinterpret_cast(memKtx->_storage->data()); + size_t length = memKtx->_storage->size(); + KTXFilePointer file; + auto& ktxCache = textureCache->_ktxCache; + if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { + qCWarning(modelnetworking) << _url << " failed to write cache file"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } else { + _file = file; + } + + auto newKtxDescriptor = memKtx->toDescriptor(); + + texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); + texture->setKtxBacking(file->getFilepath()); + texture->setSource(filename); + + auto& images = _originalKtxDescriptor->images; + size_t imageSizeRemaining = ktxHighMipData.size(); + const uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); + ktxData += ktxHighMipData.size(); + // TODO Move image offset calculation to ktx ImageDescriptor + for (int level = static_cast(images.size()) - 1; level >= 0; --level) { + auto& image = images[level]; + if (image._imageSize > imageSizeRemaining) { + break; + } + ktxData -= image._imageSize; + texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); + ktxData -= ktx::IMAGE_SIZE_WIDTH; + imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); + } + + // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different + // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will + // be the winner + texture = textureCache->cacheTextureByHash(filename, texture); + } + + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - QMetaObject::invokeMethod(resource.data(), "setImage", - Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, texture->getWidth()), - Q_ARG(int, texture->getHeight())); + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); + QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); + }); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index a17fbd353e..a93d45dac9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -78,7 +78,7 @@ protected: Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); - void startRequestForNextMipLevel(); + Q_INVOKABLE void startRequestForNextMipLevel(); void startMipRangeRequest(uint16_t low, uint16_t high); void maybeHandleFinishedInitialLoad(); @@ -110,8 +110,8 @@ private: ResourceRequest* _ktxHeaderRequest { nullptr }; ResourceRequest* _ktxMipRequest { nullptr }; - bool _ktxHeaderRequestFinished{ false }; - bool _ktxHighMipRequestFinished{ false }; + QByteArray _ktxHeaderData; + QByteArray _ktxHighMipData; uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL }; uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL }; From 31d2592e7dbce5ef96bf3072d19160a329aca643 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 16:39:29 -0700 Subject: [PATCH 64/79] Handle header and high mips in the same callback --- .../src/model-networking/TextureCache.cpp | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 7ccf081183..2f7121bbf1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -472,48 +472,65 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { void NetworkTexture::ktxHeaderRequestFinished() { - PROFILE_RANGE(app, __FUNCTION__); - - Q_ASSERT_X(_ktxHeaderRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); - - //PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { - // { "from_cache", _ktxHeaderRequest->loadedFromCache() }, - // { "size_mb", _bytesTotal / 1000000.0 } - //}); - - setSize(_bytesTotal); - - if (!_ktxHeaderRequest || _ktxHeaderRequest != sender()) { - // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. - qWarning(networking) << "Received signal NetworkTexture::ktxHeaderRequestFinished from ResourceRequest that is not the current" - << " request: " << sender() << ", " << _ktxHeaderRequest; + if (!_ktxHeaderRequest || _ktxHeaderRequest->getState() != ResourceRequest::Finished || + !_ktxMipRequest || _ktxMipRequest->getState() != ResourceRequest::Finished) { + // Wait for both request to be finished return; } + PROFILE_RANGE(app, __FUNCTION__); + + Q_ASSERT_X(_ktxHeaderRequest, __FUNCTION__, "Request should not be null while in handleReplyFinished"); + Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in handleReplyFinished"); + Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); + + PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { + { "from_cache", _ktxHeaderRequest->loadedFromCache() }, + { "size_mb", _bytesTotal / 1000000.0 } + }); + + setSize(_bytesTotal); TextureCache::requestCompleted(_self); auto result = _ktxHeaderRequest->getResult(); + if (result == ResourceRequest::Success) { + result = _ktxMipRequest->getResult(); + } + if (result == ResourceRequest::Success) { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); _ktxHeaderData = _ktxHeaderRequest->getData(); + _ktxHighMipData = _ktxMipRequest->getData(); maybeHandleFinishedInitialLoad(); } else { - handleFailedRequest(result); + if (handleFailedRequest(result)) { + _ktxResourceState = PENDING_INITIAL_LOAD; + } else { + _ktxResourceState = FAILED_TO_LOAD; + } } _ktxHeaderRequest->disconnect(this); _ktxHeaderRequest->deleteLater(); _ktxHeaderRequest = nullptr; + _ktxMipRequest->disconnect(this); + _ktxMipRequest->deleteLater(); + _ktxMipRequest = nullptr; } void NetworkTexture::ktxMipRequestFinished() { + // If this is the high mips request, redirect it to ktxHeaderRequestFinished + if (_ktxResourceState == LOADING_INITIAL_DATA) { + ktxHeaderRequestFinished(); + return; + } + PROFILE_RANGE(app, __FUNCTION__); Q_ASSERT_X(_ktxMipRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); - Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA || _ktxResourceState == REQUESTING_MIP); + Q_ASSERT(_ktxResourceState == REQUESTING_MIP); PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { { "from_cache", _ktxMipRequest->loadedFromCache() }, @@ -536,10 +553,7 @@ void NetworkTexture::ktxMipRequestFinished() { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - if (_ktxResourceState == LOADING_INITIAL_DATA) { - _ktxHighMipData = _ktxMipRequest->getData(); - maybeHandleFinishedInitialLoad(); - } else if (_ktxResourceState == REQUESTING_MIP) { + if (_ktxResourceState == REQUESTING_MIP) { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); @@ -576,7 +590,6 @@ void NetworkTexture::ktxMipRequestFinished() { Q_ARG(int, 0)); } }); - } else { qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState; finishedLoading(false); From 57e8d8e1fd691cf10c6c17a7696fc8834567fd4e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 16:53:30 -0700 Subject: [PATCH 65/79] Fix download retries --- .../src/model-networking/TextureCache.cpp | 274 +++++++++--------- .../src/model-networking/TextureCache.h | 7 +- 2 files changed, 135 insertions(+), 146 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 2f7121bbf1..c31f8f464b 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -13,7 +13,7 @@ #include -#include +#include #include #include @@ -382,8 +382,7 @@ void NetworkTexture::makeRequest() { emit loading(); - connect(_ktxHeaderRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxHeaderRequestProgress); - connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxHeaderRequestFinished); + connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished); _bytesReceived = _bytesTotal = _bytes = 0; @@ -455,6 +454,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { ByteRange range; range.fromInclusive = -HIGH_MIP_MAX_SIZE; _ktxMipRequest->setByteRange(range); + + connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished); } else { ByteRange range; range.fromInclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData @@ -462,16 +463,15 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { range.toExclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData + _originalKtxDescriptor->images[high + 1]._imageOffset; _ktxMipRequest->setByteRange(range); - } - connect(_ktxMipRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxMipRequestProgress); - connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished); + connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished); + } _ktxMipRequest->send(); } -void NetworkTexture::ktxHeaderRequestFinished() { +void NetworkTexture::ktxInitialDataRequestFinished() { if (!_ktxHeaderRequest || _ktxHeaderRequest->getState() != ResourceRequest::Finished || !_ktxMipRequest || _ktxMipRequest->getState() != ResourceRequest::Finished) { // Wait for both request to be finished @@ -479,9 +479,8 @@ void NetworkTexture::ktxHeaderRequestFinished() { } PROFILE_RANGE(app, __FUNCTION__); - Q_ASSERT_X(_ktxHeaderRequest, __FUNCTION__, "Request should not be null while in handleReplyFinished"); - Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in handleReplyFinished"); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); + Q_ASSERT_X(_ktxHeaderRequest && _ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxInitialDataRequestFinished"); PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { { "from_cache", _ktxHeaderRequest->loadedFromCache() }, @@ -503,7 +502,7 @@ void NetworkTexture::ktxHeaderRequestFinished() { _ktxHeaderData = _ktxHeaderRequest->getData(); _ktxHighMipData = _ktxMipRequest->getData(); - maybeHandleFinishedInitialLoad(); + handleFinishedInitialLoad(); } else { if (handleFailedRequest(result)) { _ktxResourceState = PENDING_INITIAL_LOAD; @@ -521,15 +520,9 @@ void NetworkTexture::ktxHeaderRequestFinished() { } void NetworkTexture::ktxMipRequestFinished() { - // If this is the high mips request, redirect it to ktxHeaderRequestFinished - if (_ktxResourceState == LOADING_INITIAL_DATA) { - ktxHeaderRequestFinished(); - return; - } - PROFILE_RANGE(app, __FUNCTION__); - Q_ASSERT_X(_ktxMipRequest, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished"); + Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxMipRequestFinished"); Q_ASSERT(_ktxResourceState == REQUESTING_MIP); PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), { @@ -541,7 +534,7 @@ void NetworkTexture::ktxMipRequestFinished() { if (!_ktxMipRequest || _ktxMipRequest != sender()) { // This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted. - qWarning(networking) << "Received signal NetworkTexture::ktxHeaderRequestFinished from ResourceRequest that is not the current" + qWarning(networking) << "Received signal NetworkTexture::ktxMipRequestFinished from ResourceRequest that is not the current" << " request: " << sender() << ", " << _ktxMipRequest; return; } @@ -608,30 +601,99 @@ void NetworkTexture::ktxMipRequestFinished() { } // This is called when the header or top mips have been loaded -void NetworkTexture::maybeHandleFinishedInitialLoad() { +void NetworkTexture::handleFinishedInitialLoad() { Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); + Q_ASSERT(!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty()); PROFILE_RANGE(app, __FUNCTION__); - if (!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty()) { - // create ktx... - auto ktxHeaderData = _ktxHeaderData; - auto ktxHighMipData = _ktxHighMipData; - _ktxHeaderData.clear(); - _ktxHighMipData.clear(); + // create ktx... + auto ktxHeaderData = _ktxHeaderData; + auto ktxHighMipData = _ktxHighMipData; + _ktxHeaderData.clear(); + _ktxHighMipData.clear(); - auto self = _self; - QtConcurrent::run(QThreadPool::globalInstance(), [=] { - auto that = self.lock(); - if (!that) { - // Resource no longer exists, bail - return; + auto self = _self; + QtConcurrent::run(QThreadPool::globalInstance(), [=] { + auto that = self.lock(); + if (!that) { + // Resource no longer exists, bail + return; + } + + auto header = reinterpret_cast(ktxHeaderData.data()); + + if (!ktx::checkIdentifier(header->identifier)) { + qWarning() << "Cannot load " << _url << ", invalid header identifier"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + auto kvSize = header->bytesOfKeyValueData; + if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { + qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + + auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); + + auto imageDescriptors = header->generateImageDescriptors(); + if (imageDescriptors.size() == 0) { + qWarning(networking) << "Failed to process ktx file " << _url; + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } + _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); + + // Create bare ktx in memory + auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { + return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; + }); + std::string filename; + std::string hash; + if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { + qWarning("Invalid source hash key found, bailing"); + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, nullptr), + Q_ARG(int, 0), + Q_ARG(int, 0)); + return; + } else { + // at this point the source hash is in binary 16-byte form + // and we need it in a hexadecimal string + auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); + hash = filename = binaryHash.toHex().toStdString(); + } + + auto textureCache = DependencyManager::get(); + + gpu::TexturePointer texture = textureCache->getTextureByHash(hash); + + if (!texture) { + KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); + if (ktxFile) { + texture = gpu::Texture::unserialize(ktxFile->getFilepath()); + if (texture) { + texture = textureCache->cacheTextureByHash(hash, texture); + } } + } - auto header = reinterpret_cast(ktxHeaderData.data()); + if (!texture) { - if (!ktx::checkIdentifier(header->identifier)) { - qWarning() << "Cannot load " << _url << ", invalid header identifier"; + auto memKtx = ktx::KTX::createBare(*header, keyValues); + if (!memKtx) { + qWarning() << " Ktx could not be created, bailing"; QMetaObject::invokeMethod(this, "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), @@ -639,129 +701,59 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { return; } - auto kvSize = header->bytesOfKeyValueData; - if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { - qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); - - auto imageDescriptors = header->generateImageDescriptors(); - if (imageDescriptors.size() == 0) { - qWarning(networking) << "Failed to process ktx file " << _url; - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); - - // Create bare ktx in memory - auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { - return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; - }); - std::string filename; - std::string hash; - if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { - qWarning("Invalid source hash key found, bailing"); + // Move ktx to file + const char* data = reinterpret_cast(memKtx->_storage->data()); + size_t length = memKtx->_storage->size(); + KTXFilePointer file; + auto& ktxCache = textureCache->_ktxCache; + if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { + qCWarning(modelnetworking) << _url << " failed to write cache file"; QMetaObject::invokeMethod(this, "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); return; } else { - // at this point the source hash is in binary 16-byte form - // and we need it in a hexadecimal string - auto binaryHash = QByteArray(reinterpret_cast(found->_value.data()), gpu::SOURCE_HASH_BYTES); - hash = filename = binaryHash.toHex().toStdString(); + _file = file; } - auto textureCache = DependencyManager::get(); + auto newKtxDescriptor = memKtx->toDescriptor(); - gpu::TexturePointer texture = textureCache->getTextureByHash(hash); + texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); + texture->setKtxBacking(file->getFilepath()); + texture->setSource(filename); - if (!texture) { - KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); - if (ktxFile) { - texture = gpu::Texture::unserialize(ktxFile->getFilepath()); - if (texture) { - texture = textureCache->cacheTextureByHash(hash, texture); - } + auto& images = _originalKtxDescriptor->images; + size_t imageSizeRemaining = ktxHighMipData.size(); + const uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); + ktxData += ktxHighMipData.size(); + // TODO Move image offset calculation to ktx ImageDescriptor + for (int level = static_cast(images.size()) - 1; level >= 0; --level) { + auto& image = images[level]; + if (image._imageSize > imageSizeRemaining) { + break; } + ktxData -= image._imageSize; + texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); + ktxData -= ktx::IMAGE_SIZE_WIDTH; + imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); } - if (!texture) { + // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different + // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will + // be the winner + texture = textureCache->cacheTextureByHash(filename, texture); + } - auto memKtx = ktx::KTX::createBare(*header, keyValues); - if (!memKtx) { - qWarning() << " Ktx could not be created, bailing"; - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } - - // Move ktx to file - const char* data = reinterpret_cast(memKtx->_storage->data()); - size_t length = memKtx->_storage->size(); - KTXFilePointer file; - auto& ktxCache = textureCache->_ktxCache; - if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << " failed to write cache file"; - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - return; - } else { - _file = file; - } - - auto newKtxDescriptor = memKtx->toDescriptor(); - - texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); - texture->setKtxBacking(file->getFilepath()); - texture->setSource(filename); - - auto& images = _originalKtxDescriptor->images; - size_t imageSizeRemaining = ktxHighMipData.size(); - const uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); - ktxData += ktxHighMipData.size(); - // TODO Move image offset calculation to ktx ImageDescriptor - for (int level = static_cast(images.size()) - 1; level >= 0; --level) { - auto& image = images[level]; - if (image._imageSize > imageSizeRemaining) { - break; - } - ktxData -= image._imageSize; - texture->assignStoredMip(static_cast(level), image._imageSize, ktxData); - ktxData -= ktx::IMAGE_SIZE_WIDTH; - imageSizeRemaining -= (image._imageSize + ktx::IMAGE_SIZE_WIDTH); - } - - // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different - // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will - // be the winner - texture = textureCache->cacheTextureByHash(filename, texture); - } - - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, texture->getWidth()), - Q_ARG(int, texture->getHeight())); - QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); - }); - } + QMetaObject::invokeMethod(this, "setImage", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); + QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); + }); } void NetworkTexture::downloadFinished(const QByteArray& data) { diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index a93d45dac9..0b55839319 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -62,10 +62,7 @@ signals: void networkTextureCreated(const QWeakPointer& self); public slots: - void ktxHeaderRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { } - void ktxHeaderRequestFinished(); - - void ktxMipRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { } + void ktxInitialDataRequestFinished(); void ktxMipRequestFinished(); protected: @@ -81,7 +78,7 @@ protected: Q_INVOKABLE void startRequestForNextMipLevel(); void startMipRangeRequest(uint16_t low, uint16_t high); - void maybeHandleFinishedInitialLoad(); + void handleFinishedInitialLoad(); private: friend class KTXReader; From 306b55e45d64df869bd0d0f49e47120c1bfd41e3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 14 Jun 2017 13:46:29 -0700 Subject: [PATCH 66/79] Synchronous mip loading --- .../src/model-networking/TextureCache.cpp | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index c31f8f464b..6c5fef7765 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -550,14 +550,6 @@ void NetworkTexture::ktxMipRequestFinished() { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); - _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; - _ktxResourceState = WAITING_FOR_MIP_REQUEST; - - if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { - startRequestForNextMipLevel(); - } - - auto self = _self; auto data = _ktxMipRequest->getData(); auto mipLevel = _ktxMipLevelRangeInFlight.first; @@ -572,10 +564,17 @@ void NetworkTexture::ktxMipRequestFinished() { if (texture) { texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast(data.data())); + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + QMetaObject::invokeMethod(this, "setImage", Q_ARG(gpu::TexturePointer, texture), Q_ARG(int, texture->getWidth()), Q_ARG(int, texture->getHeight())); + + if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { + QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); + } } else { QMetaObject::invokeMethod(this, "setImage", Q_ARG(gpu::TexturePointer, nullptr), @@ -746,13 +745,17 @@ void NetworkTexture::handleFinishedInitialLoad() { } _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + _ktxResourceState = WAITING_FOR_MIP_REQUEST; QMetaObject::invokeMethod(this, "setImage", Q_ARG(gpu::TexturePointer, texture), Q_ARG(int, texture->getWidth()), Q_ARG(int, texture->getHeight())); - QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); + + if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { + QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); + } }); } From fb8aa96a57468169f54ed9cc645bbd75cbc03d0b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 14 Jun 2017 14:42:18 -0700 Subject: [PATCH 67/79] Add resource processing tracking to KTX --- .../src/model-networking/TextureCache.cpp | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6c5fef7765..607338d32e 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -553,7 +553,19 @@ void NetworkTexture::ktxMipRequestFinished() { auto self = _self; auto data = _ktxMipRequest->getData(); auto mipLevel = _ktxMipLevelRangeInFlight.first; + DependencyManager::get()->incrementStat("PendingProcessing"); QtConcurrent::run(QThreadPool::globalInstance(), [this, self, data, mipLevel] { + PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", _url.toString() } }); + DependencyManager::get()->decrementStat("PendingProcessing"); + CounterStat counter("Processing"); + + auto originalPriority = QThread::currentThread()->priority(); + if (originalPriority == QThread::InheritPriority) { + originalPriority = QThread::NormalPriority; + } + QThread::currentThread()->setPriority(QThread::LowPriority); + Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); }); + auto that = self.lock(); if (!that) { // Resource no longer exists, bail @@ -613,7 +625,19 @@ void NetworkTexture::handleFinishedInitialLoad() { _ktxHighMipData.clear(); auto self = _self; - QtConcurrent::run(QThreadPool::globalInstance(), [=] { + DependencyManager::get()->incrementStat("PendingProcessing"); + QtConcurrent::run(QThreadPool::globalInstance(), [this, self, ktxHeaderData, ktxHighMipData] { + PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", _url.toString() } }); + DependencyManager::get()->decrementStat("PendingProcessing"); + CounterStat counter("Processing"); + + auto originalPriority = QThread::currentThread()->priority(); + if (originalPriority == QThread::InheritPriority) { + originalPriority = QThread::NormalPriority; + } + QThread::currentThread()->setPriority(QThread::LowPriority); + Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); }); + auto that = self.lock(); if (!that) { // Resource no longer exists, bail From 4d3fc39ab62fa61c79a272ea69b83a47cb0d4c5d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 14 Jun 2017 17:20:38 -0700 Subject: [PATCH 68/79] Make KTX async tasks thread safe --- .../src/model-networking/TextureCache.cpp | 112 ++++++++---------- .../src/model-networking/TextureCache.h | 2 + 2 files changed, 53 insertions(+), 61 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 607338d32e..1d280aecc9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -406,19 +406,18 @@ void NetworkTexture::makeRequest() { } void NetworkTexture::startRequestForNextMipLevel() { - PROFILE_RANGE(app, __FUNCTION__); - if (_lowestKnownPopulatedMip == 0) { - qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _lowestKnownPopulatedMip - << " " << _textureSource->getGPUTexture()->minAvailableMipLevel() << " " << _url; + auto self = _self.lock(); + if (!self) { return; } - if (_ktxResourceState == WAITING_FOR_MIP_REQUEST) { - auto self = _self.lock(); - if (!self) { - return; - } + auto texture = _textureSource->getGPUTexture(); + if (!texture || _ktxResourceState != WAITING_FOR_MIP_REQUEST) { + return; + } + _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); + if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { _ktxResourceState = PENDING_MIP_REQUEST; init(false); @@ -434,7 +433,6 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { if (_ktxMipRequest) { return; } - PROFILE_RANGE(app, __FUNCTION__); bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL; @@ -477,7 +475,6 @@ void NetworkTexture::ktxInitialDataRequestFinished() { // Wait for both request to be finished return; } - PROFILE_RANGE(app, __FUNCTION__); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); Q_ASSERT_X(_ktxHeaderRequest && _ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxInitialDataRequestFinished"); @@ -487,6 +484,8 @@ void NetworkTexture::ktxInitialDataRequestFinished() { { "size_mb", _bytesTotal / 1000000.0 } }); + PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } }); + setSize(_bytesTotal); TextureCache::requestCompleted(_self); @@ -520,8 +519,6 @@ void NetworkTexture::ktxInitialDataRequestFinished() { } void NetworkTexture::ktxMipRequestFinished() { - PROFILE_RANGE(app, __FUNCTION__); - Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxMipRequestFinished"); Q_ASSERT(_ktxResourceState == REQUESTING_MIP); @@ -530,6 +527,9 @@ void NetworkTexture::ktxMipRequestFinished() { { "size_mb", _bytesTotal / 1000000.0 } }); + PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } }); + + setSize(_bytesTotal); if (!_ktxMipRequest || _ktxMipRequest != sender()) { @@ -550,12 +550,16 @@ void NetworkTexture::ktxMipRequestFinished() { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + auto self = _self; + auto url = _url; auto data = _ktxMipRequest->getData(); auto mipLevel = _ktxMipLevelRangeInFlight.first; + auto texture = _textureSource->getGPUTexture(); DependencyManager::get()->incrementStat("PendingProcessing"); - QtConcurrent::run(QThreadPool::globalInstance(), [this, self, data, mipLevel] { - PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", _url.toString() } }); + QtConcurrent::run(QThreadPool::globalInstance(), [self, data, mipLevel, url, texture] { + PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", url.toString() } }); DependencyManager::get()->decrementStat("PendingProcessing"); CounterStat counter("Processing"); @@ -566,33 +570,22 @@ void NetworkTexture::ktxMipRequestFinished() { QThread::currentThread()->setPriority(QThread::LowPriority); Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); }); - auto that = self.lock(); - if (!that) { + auto resource = self.lock(); + if (!resource) { // Resource no longer exists, bail return; } - auto texture = _textureSource->getGPUTexture(); - if (texture) { - texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast(data.data())); + Q_ASSERT_X(texture, "Async - NetworkTexture::ktxMipRequestFinished", "NetworkTexture should have been assigned a GPU texture by now."); - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - _ktxResourceState = WAITING_FOR_MIP_REQUEST; + texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast(data.data())); - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, texture->getWidth()), - Q_ARG(int, texture->getHeight())); + QMetaObject::invokeMethod(resource.data(), "setImage", + Q_ARG(gpu::TexturePointer, texture), + Q_ARG(int, texture->getWidth()), + Q_ARG(int, texture->getHeight())); - if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { - QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); - } - } else { - QMetaObject::invokeMethod(this, "setImage", - Q_ARG(gpu::TexturePointer, nullptr), - Q_ARG(int, 0), - Q_ARG(int, 0)); - } + QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel"); }); } else { qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState; @@ -616,18 +609,19 @@ void NetworkTexture::handleFinishedInitialLoad() { Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); Q_ASSERT(!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty()); - PROFILE_RANGE(app, __FUNCTION__); - // create ktx... auto ktxHeaderData = _ktxHeaderData; auto ktxHighMipData = _ktxHighMipData; _ktxHeaderData.clear(); _ktxHighMipData.clear(); + _ktxResourceState = WAITING_FOR_MIP_REQUEST; + auto self = _self; + auto url = _url; DependencyManager::get()->incrementStat("PendingProcessing"); - QtConcurrent::run(QThreadPool::globalInstance(), [this, self, ktxHeaderData, ktxHighMipData] { - PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", _url.toString() } }); + QtConcurrent::run(QThreadPool::globalInstance(), [self, ktxHeaderData, ktxHighMipData, url] { + PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", url.toString() } }); DependencyManager::get()->decrementStat("PendingProcessing"); CounterStat counter("Processing"); @@ -638,8 +632,8 @@ void NetworkTexture::handleFinishedInitialLoad() { QThread::currentThread()->setPriority(QThread::LowPriority); Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); }); - auto that = self.lock(); - if (!that) { + auto resource = self.lock(); + if (!resource) { // Resource no longer exists, bail return; } @@ -647,8 +641,8 @@ void NetworkTexture::handleFinishedInitialLoad() { auto header = reinterpret_cast(ktxHeaderData.data()); if (!ktx::checkIdentifier(header->identifier)) { - qWarning() << "Cannot load " << _url << ", invalid header identifier"; - QMetaObject::invokeMethod(this, "setImage", + qWarning() << "Cannot load " << url << ", invalid header identifier"; + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -657,8 +651,8 @@ void NetworkTexture::handleFinishedInitialLoad() { auto kvSize = header->bytesOfKeyValueData; if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { - qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; - QMetaObject::invokeMethod(this, "setImage", + qWarning() << "Cannot load " << url << ", did not receive all kv data with initial request"; + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -669,14 +663,16 @@ void NetworkTexture::handleFinishedInitialLoad() { auto imageDescriptors = header->generateImageDescriptors(); if (imageDescriptors.size() == 0) { - qWarning(networking) << "Failed to process ktx file " << _url; - QMetaObject::invokeMethod(this, "setImage", + qWarning(networking) << "Failed to process ktx file " << url; + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); return; } - _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); + auto originalKtxDescriptor = new ktx::KTXDescriptor(*header, keyValues, imageDescriptors); + QMetaObject::invokeMethod(resource.data(), "setOriginalDescriptor", + Q_ARG(ktx::KTXDescriptor*, originalKtxDescriptor)); // Create bare ktx in memory auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { @@ -686,7 +682,7 @@ void NetworkTexture::handleFinishedInitialLoad() { std::string hash; if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { qWarning("Invalid source hash key found, bailing"); - QMetaObject::invokeMethod(this, "setImage", + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -717,7 +713,7 @@ void NetworkTexture::handleFinishedInitialLoad() { auto memKtx = ktx::KTX::createBare(*header, keyValues); if (!memKtx) { qWarning() << " Ktx could not be created, bailing"; - QMetaObject::invokeMethod(this, "setImage", + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -730,8 +726,8 @@ void NetworkTexture::handleFinishedInitialLoad() { KTXFilePointer file; auto& ktxCache = textureCache->_ktxCache; if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << " failed to write cache file"; - QMetaObject::invokeMethod(this, "setImage", + qCWarning(modelnetworking) << url << " failed to write cache file"; + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, nullptr), Q_ARG(int, 0), Q_ARG(int, 0)); @@ -746,7 +742,7 @@ void NetworkTexture::handleFinishedInitialLoad() { texture->setKtxBacking(file->getFilepath()); texture->setSource(filename); - auto& images = _originalKtxDescriptor->images; + auto& images = originalKtxDescriptor->images; size_t imageSizeRemaining = ktxHighMipData.size(); const uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); ktxData += ktxHighMipData.size(); @@ -768,18 +764,12 @@ void NetworkTexture::handleFinishedInitialLoad() { texture = textureCache->cacheTextureByHash(filename, texture); } - _lowestKnownPopulatedMip = texture->minAvailableMipLevel(); - _ktxResourceState = WAITING_FOR_MIP_REQUEST; - - - QMetaObject::invokeMethod(this, "setImage", + QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, texture), Q_ARG(int, texture->getWidth()), Q_ARG(int, texture->getHeight())); - if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) { - QMetaObject::invokeMethod(this, "startRequestForNextMipLevel"); - } + QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel"); }); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 0b55839319..555c43636e 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -58,6 +58,8 @@ public: void refresh() override; + Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); } + signals: void networkTextureCreated(const QWeakPointer& self); From 54fc8085f38273ef1694f72ab79291fa3c450a63 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 14 Jun 2017 17:35:59 -0700 Subject: [PATCH 69/79] Remove pointer to file in NetworkTexture --- .../src/model-networking/TextureCache.cpp | 10 ++++------ .../src/model-networking/TextureCache.h | 3 --- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1d280aecc9..6772f5e3bd 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -732,13 +732,11 @@ void NetworkTexture::handleFinishedInitialLoad() { Q_ARG(int, 0), Q_ARG(int, 0)); return; - } else { - _file = file; } auto newKtxDescriptor = memKtx->toDescriptor(); - texture = gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor); + texture = gpu::Texture::unserialize(file->getFilepath(), newKtxDescriptor); texture->setKtxBacking(file->getFilepath()); texture->setSource(filename); @@ -933,11 +931,11 @@ void ImageReader::read() { const char* data = reinterpret_cast(memKtx->_storage->data()); size_t length = memKtx->_storage->size(); auto& ktxCache = textureCache->_ktxCache; - networkTexture->_file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length)); // - if (!networkTexture->_file) { + auto file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length)); + if (!file) { qCWarning(modelnetworking) << _url << "file cache failed"; } else { - texture->setKtxBacking(networkTexture->_file->getFilepath()); + texture->setKtxBacking(file->getFilepath()); } } else { qCWarning(modelnetworking) << "Unable to serialize texture to KTX " << _url; diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 555c43636e..b86a685dcd 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -101,9 +101,6 @@ private: bool _sourceIsKTX { false }; KTXResourceState _ktxResourceState { PENDING_INITIAL_LOAD }; - // TODO Can this be removed? - KTXFilePointer _file; - // The current mips that are currently being requested w/ _ktxMipRequest std::pair _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL }; From c2650c2b712929c6001a6a78ce3be32db988227c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 14 Jun 2017 18:14:39 -0700 Subject: [PATCH 70/79] Declare KTXDescriptor* metatype --- libraries/ktx/src/ktx/KTX.cpp | 2 ++ libraries/ktx/src/ktx/KTX.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 788ec54a47..3b1a12cba7 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -16,6 +16,8 @@ using namespace ktx; +int ktxDescriptorMetaTypeId = qRegisterMetaType(); + const Header::Identifier ktx::Header::IDENTIFIER {{ 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }}; diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index b02e2ada75..8dc4ec7a47 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -387,4 +387,6 @@ namespace ktx { } +Q_DECLARE_METATYPE(ktx::KTXDescriptor*); + #endif // hifi_ktx_KTX_h From 097e75285a94883906be3f54a93c34211fad79ca Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 16 Jun 2017 14:31:31 -0700 Subject: [PATCH 71/79] Remove extra profiling --- libraries/gpu/src/gpu/Texture_ktx.cpp | 5 ----- libraries/networking/src/FileCache.cpp | 7 +------ libraries/shared/src/shared/Storage.cpp | 7 ------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 8c185e0b22..f455fde009 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -15,7 +15,6 @@ #include #include -#include #include "GPULogging.h" @@ -243,7 +242,6 @@ uint16 KtxStorage::minAvailableMipLevel() const { } void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) { - PROFILE_RANGE(app, __FUNCTION__) if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored, expected: " << (_minMipLevelAvailable - 1) << ", got: " << level << " " << _filename.c_str(); return; @@ -285,7 +283,6 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor } memcpy(imageData, storage->data(), storage->size()); - _minMipLevelAvailable = level; if (_offsetToMinMipKV > 0) { auto minMipKeyData = fileData + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; @@ -314,7 +311,6 @@ void Texture::setKtxBacking(const std::string& filename) { ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { - PROFILE_RANGE(app, __FUNCTION__) ktx::Header header; // From texture format to ktx format description @@ -457,7 +453,6 @@ TexturePointer Texture::unserialize(const std::string& ktxfile) { } TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDescriptor& descriptor) { - PROFILE_RANGE(app, __FUNCTION__) const auto& header = descriptor.header; Format mipFormat = Format::COLOR_BGRA_32; diff --git a/libraries/networking/src/FileCache.cpp b/libraries/networking/src/FileCache.cpp index c3cc55cbae..95304e3866 100644 --- a/libraries/networking/src/FileCache.cpp +++ b/libraries/networking/src/FileCache.cpp @@ -21,9 +21,8 @@ #include #include -#include #include -#include +#include #ifdef Q_OS_WIN #include @@ -88,7 +87,6 @@ FileCache::~FileCache() { } void FileCache::initialize() { - PROFILE_RANGE(app, __FUNCTION__) QDir dir(_dirpath.c_str()); if (dir.exists()) { @@ -129,7 +127,6 @@ FilePointer FileCache::addFile(Metadata&& metadata, const std::string& filepath) } FilePointer FileCache::writeFile(const char* data, File::Metadata&& metadata, bool overwrite) { - PROFILE_RANGE(app, __FUNCTION__) assert(_initialized); std::string filepath = getFilepath(metadata.key); @@ -322,7 +319,6 @@ File::File(Metadata&& metadata, const std::string& filepath) : } File::~File() { - PROFILE_RANGE(app, __FUNCTION__) QFile file(getFilepath().c_str()); if (file.exists() && !_shouldPersist) { qCInfo(file_cache, "Unlinked %s", getFilepath().c_str()); @@ -331,7 +327,6 @@ File::~File() { } void File::touch() { - PROFILE_RANGE(app, __FUNCTION__) utime(_filepath.c_str(), nullptr); _modified = std::max(QFileInfo(_filepath.c_str()).lastRead().toMSecsSinceEpoch(), _modified); } \ No newline at end of file diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index 3e1b357019..b07f896df0 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -12,8 +12,6 @@ #include #include -#include "../Profile.h" - Q_LOGGING_CATEGORY(storagelogging, "hifi.core.storage") using namespace storage; @@ -50,7 +48,6 @@ MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) { } StoragePointer FileStorage::create(const QString& filename, size_t size, const uint8_t* data) { - PROFILE_RANGE(app, "FileStorage::create()"); QFile file(filename); if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) { throw std::runtime_error("Unable to open file for writing"); @@ -73,8 +70,6 @@ StoragePointer FileStorage::create(const QString& filename, size_t size, const u } FileStorage::FileStorage(const QString& filename) : _file(filename) { - PROFILE_RANGE(app, "FileStorage()"); - bool opened = _file.open(QFile::ReadWrite); if (opened) { _hasWriteAccess = true; @@ -84,7 +79,6 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) { } if (opened) { - PROFILE_RANGE(app, "FileStorage() map"); _mapped = _file.map(0, _file.size()); if (_mapped) { _valid = true; @@ -97,7 +91,6 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) { } FileStorage::~FileStorage() { - PROFILE_RANGE(app, "~FileStorage()"); if (_mapped) { if (!_file.unmap(_mapped)) { throw std::runtime_error("Unable to unmap file"); From d090ac4396693426fc08a4d3d40f89ca4f39f3f9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 16 Jun 2017 17:04:57 -0700 Subject: [PATCH 72/79] CR --- .../model-networking/src/model-networking/TextureCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6772f5e3bd..864e79220f 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -546,7 +546,7 @@ void NetworkTexture::ktxMipRequestFinished() { auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); - if (_ktxResourceState == REQUESTING_MIP) { + if (_ktxResourceState == REQUESTING_MIP) { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); From 36ff765d7f15a54a9ab19e5872ad38cd28bf7de2 Mon Sep 17 00:00:00 2001 From: Vladyslav Stelmakhovskyi Date: Sun, 18 Jun 2017 22:19:28 +0200 Subject: [PATCH 73/79] Make sure registered object have different name from iport alias --- interface/resources/qml/hifi/audio/Audio.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index a30aba2a6b..929752f925 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -18,7 +18,7 @@ import QtQuick.Layouts 1.3 import "../../styles-uit" import "../../controls-uit" as HifiControls import "../../windows" -import "./" as Audio +import "./" as AudioControls Rectangle { id: root; @@ -57,7 +57,7 @@ Rectangle { x: 16; // padding does not work spacing: 16; - Audio.CheckBox { + AudioControls.CheckBox { text: qsTr("Mute microphone"); checked: Audio.muted; onClicked: { @@ -65,7 +65,7 @@ Rectangle { checked = Qt.binding(function() { return Audio.muted; }); // restore binding } } - Audio.CheckBox { + AudioControls.CheckBox { text: qsTr("Enable noise reduction"); checked: Audio.noiseReduction; onClicked: { @@ -73,7 +73,7 @@ Rectangle { checked = Qt.binding(function() { return Audio.noiseReduction; }); // restore binding } } - Audio.CheckBox { + AudioControls.CheckBox { text: qsTr("Show audio level meter"); checked: AvatarInputs.showAudioTools; onClicked: { @@ -110,7 +110,7 @@ Rectangle { delegate: Item { width: parent.width; height: 36; - Audio.CheckBox { + AudioControls.CheckBox { text: display; checked: selected; onClicked: { @@ -148,7 +148,7 @@ Rectangle { delegate: Item { width: parent.width; height: 36; - Audio.CheckBox { + AudioControls.CheckBox { text: display; checked: selected; onClicked: { From 5245237bb264012cf79ffe3903bd4218c5ef5f67 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 19 Jun 2017 10:33:22 -0700 Subject: [PATCH 74/79] Removing unmergeable files before PR --- .../resources/qml/controls-uit/Separator.qml | 38 -- .../resources/qml/controls-uit/Switch.qml | 156 ------ .../resources/qml/hifi/SpectatorCamera.qml | 313 ----------- .../qml/styles-uit/HifiConstants.qml | 2 +- scripts/defaultScripts.js | 1 - scripts/system/spectatorCamera.js | 517 ------------------ 6 files changed, 1 insertion(+), 1026 deletions(-) delete mode 100644 interface/resources/qml/controls-uit/Separator.qml delete mode 100644 interface/resources/qml/controls-uit/Switch.qml delete mode 100644 interface/resources/qml/hifi/SpectatorCamera.qml delete mode 100644 scripts/system/spectatorCamera.js diff --git a/interface/resources/qml/controls-uit/Separator.qml b/interface/resources/qml/controls-uit/Separator.qml deleted file mode 100644 index 5a775221f6..0000000000 --- a/interface/resources/qml/controls-uit/Separator.qml +++ /dev/null @@ -1,38 +0,0 @@ -// -// Separator.qml -// -// Created by Zach Fox on 2017-06-06 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import "../styles-uit" - -Item { - // Size - height: 2; - Rectangle { - // Size - width: parent.width; - height: 1; - // Anchors - anchors.left: parent.left; - anchors.bottom: parent.bottom; - anchors.bottomMargin: height; - // Style - color: hifi.colors.baseGrayShadow; - } - Rectangle { - // Size - width: parent.width; - height: 1; - // Anchors - anchors.left: parent.left; - anchors.bottom: parent.bottom; - // Style - color: hifi.colors.baseGrayHighlight; - } -} diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml deleted file mode 100644 index d54f986717..0000000000 --- a/interface/resources/qml/controls-uit/Switch.qml +++ /dev/null @@ -1,156 +0,0 @@ -// -// Switch.qml -// -// Created by Zach Fox on 2017-06-06 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 - -import "../styles-uit" - -Item { - id: rootSwitch; - - property int colorScheme: hifi.colorSchemes.light; - readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light; - property int switchWidth: 70; - readonly property int switchRadius: height/2; - property string labelTextOff: ""; - property string labelGlyphOffText: ""; - property int labelGlyphOffSize: 32; - property string labelTextOn: ""; - property string labelGlyphOnText: ""; - property int labelGlyphOnSize: 32; - property alias checked: originalSwitch.checked; - signal onCheckedChanged; - signal clicked; - - Original.Switch { - id: originalSwitch; - activeFocusOnPress: true; - anchors.top: rootSwitch.top; - anchors.left: rootSwitch.left; - anchors.leftMargin: rootSwitch.width/2 - rootSwitch.switchWidth/2; - onCheckedChanged: rootSwitch.onCheckedChanged(); - onClicked: rootSwitch.clicked(); - - style: SwitchStyle { - - padding { - top: 3; - left: 3; - right: 3; - bottom: 3; - } - - groove: Rectangle { - color: "#252525"; - implicitWidth: rootSwitch.switchWidth; - implicitHeight: rootSwitch.height; - radius: rootSwitch.switchRadius; - } - - handle: Rectangle { - id: switchHandle; - implicitWidth: rootSwitch.height - padding.top - padding.bottom; - implicitHeight: implicitWidth; - radius: implicitWidth/2; - border.color: hifi.colors.lightGrayText; - color: hifi.colors.lightGray; - - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = hifi.colors.lightGray; - } - } - } - } - - // OFF Label - Item { - anchors.right: originalSwitch.left; - anchors.rightMargin: 10; - anchors.top: rootSwitch.top; - height: rootSwitch.height; - - RalewaySemiBold { - id: labelOff; - text: labelTextOff; - size: hifi.fontSizes.inputLabel; - color: originalSwitch.checked ? hifi.colors.lightGrayText : "#FFFFFF"; - anchors.top: parent.top; - anchors.right: parent.right; - width: paintedWidth; - height: parent.height; - verticalAlignment: Text.AlignVCenter; - } - - HiFiGlyphs { - id: labelGlyphOff; - text: labelGlyphOffText; - size: labelGlyphOffSize; - color: labelOff.color; - anchors.top: parent.top; - anchors.topMargin: 2; - anchors.right: labelOff.left; - anchors.rightMargin: 4; - } - - MouseArea { - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: labelGlyphOff.left; - anchors.right: labelOff.right; - onClicked: { - originalSwitch.checked = false; - } - } - } - - // ON Label - Item { - anchors.left: originalSwitch.right; - anchors.leftMargin: 10; - anchors.top: rootSwitch.top; - height: rootSwitch.height; - - RalewaySemiBold { - id: labelOn; - text: labelTextOn; - size: hifi.fontSizes.inputLabel; - color: originalSwitch.checked ? "#FFFFFF" : hifi.colors.lightGrayText; - anchors.top: parent.top; - anchors.left: parent.left; - width: paintedWidth; - height: parent.height; - verticalAlignment: Text.AlignVCenter; - } - - HiFiGlyphs { - id: labelGlyphOn; - text: labelGlyphOnText; - size: labelGlyphOnSize; - color: labelOn.color; - anchors.top: parent.top; - anchors.left: labelOn.right; - } - - MouseArea { - anchors.top: parent.top; - anchors.bottom: parent.bottom; - anchors.left: labelOn.left; - anchors.right: labelGlyphOn.right; - onClicked: { - originalSwitch.checked = true; - } - } - } -} diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml deleted file mode 100644 index 6bb25b2958..0000000000 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ /dev/null @@ -1,313 +0,0 @@ -// -// SpectatorCamera.qml -// qml/hifi -// -// Spectator Camera -// -// Created by Zach Fox on 2017-06-05 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "../styles-uit" -import "../controls-uit" as HifiControlsUit -import "../controls" as HifiControls - -// references HMD, XXX from root context - -Rectangle { - HifiConstants { id: hifi; } - - id: spectatorCamera; - // Style - color: hifi.colors.baseGray; - - // - // TITLE BAR START - // - Item { - id: titleBarContainer; - // Size - width: spectatorCamera.width; - height: 50; - // Anchors - anchors.left: parent.left; - anchors.top: parent.top; - - // "Spectator" text - RalewaySemiBold { - id: titleBarText; - text: "Spectator"; - // Text size - size: hifi.fontSizes.overlayTitle; - // Anchors - anchors.fill: parent; - anchors.leftMargin: 16; - // Style - color: hifi.colors.lightGrayText; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - // Separator - HifiControlsUit.Separator { - anchors.left: parent.left; - anchors.right: parent.right; - anchors.bottom: parent.bottom; - } - } - // - // TITLE BAR END - // - - // - // SPECTATOR APP DESCRIPTION START - // - Item { - id: spectatorDescriptionContainer; - // Size - width: spectatorCamera.width; - height: childrenRect.height; - // Anchors - anchors.left: parent.left; - anchors.top: titleBarContainer.bottom; - - // (i) Glyph - HiFiGlyphs { - id: spectatorDescriptionGlyph; - text: hifi.glyphs.info; - // Size - width: 20; - height: parent.height; - size: 60; - // Anchors - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.top: parent.top; - anchors.topMargin: 0; - // Style - color: hifi.colors.lightGrayText; - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignTop; - } - - // "Spectator" app description text - RalewayLight { - id: spectatorDescriptionText; - text: "Spectator lets you change what your monitor displays while you're using a VR headset. Use Spectator when streaming and recording video."; - // Text size - size: 14; - // Size - width: 350; - height: paintedHeight; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 15; - anchors.left: spectatorDescriptionGlyph.right; - anchors.leftMargin: 40; - // Style - color: hifi.colors.lightGrayText; - wrapMode: Text.WordWrap; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - } - - // "Learn More" text - RalewayRegular { - id: spectatorLearnMoreText; - text: "Learn More About Spectator"; - // Text size - size: 14; - // Size - width: paintedWidth; - height: paintedHeight; - // Anchors - anchors.top: spectatorDescriptionText.bottom; - anchors.topMargin: 10; - anchors.left: spectatorDescriptionText.anchors.left; - anchors.leftMargin: spectatorDescriptionText.anchors.leftMargin; - // Style - color: hifi.colors.blueAccent; - wrapMode: Text.WordWrap; - font.underline: true; - // Alignment - horizontalAlignment: Text.AlignHLeft; - verticalAlignment: Text.AlignVCenter; - - MouseArea { - anchors.fill: parent; - hoverEnabled: enabled; - onClicked: { - console.log("FIXME! Add popup pointing to 'Learn More' page"); - } - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = hifi.colors.blueAccent; - } - } - - // Separator - HifiControlsUit.Separator { - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: spectatorLearnMoreText.bottom; - anchors.topMargin: spectatorDescriptionText.anchors.topMargin; - } - } - // - // SPECTATOR APP DESCRIPTION END - // - - - // - // SPECTATOR CONTROLS START - // - Item { - id: spectatorControlsContainer; - // Size - height: spectatorCamera.height - spectatorDescriptionContainer.height - titleBarContainer.height; - // Anchors - anchors.top: spectatorDescriptionContainer.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 25; - anchors.right: parent.right; - anchors.rightMargin: anchors.leftMargin; - - // "Camera On" Checkbox - HifiControlsUit.CheckBox { - id: cameraToggleCheckBox; - colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.top: parent.top; - text: "Camera On"; - boxSize: 24; - onClicked: { - sendToScript({method: (checked ? 'spectatorCameraOn' : 'spectatorCameraOff')}); - } - } - - // Spectator Camera Preview - Image { - id: spectatorCameraPreview; - height: 250; - anchors.left: parent.left; - anchors.top: cameraToggleCheckBox.bottom; - anchors.topMargin: 20; - anchors.right: parent.right; - fillMode: Image.PreserveAspectFit; - horizontalAlignment: Image.AlignHCenter; - verticalAlignment: Image.AlignVCenter; - source: "http://1.bp.blogspot.com/-1GABEq__054/T03B00j_OII/AAAAAAAAAa8/jo55LcvEPHI/s1600/Winning.jpg"; - } - - // "Monitor Shows" Switch Label Glyph - HiFiGlyphs { - id: monitorShowsSwitchLabelGlyph; - text: hifi.glyphs.screen; - size: 32; - color: hifi.colors.blueHighlight; - anchors.top: spectatorCameraPreview.bottom; - anchors.topMargin: 12; - anchors.left: parent.left; - } - // "Monitor Shows" Switch Label - RalewayLight { - id: monitorShowsSwitchLabel; - text: "MONITOR SHOWS:"; - anchors.top: spectatorCameraPreview.bottom; - anchors.topMargin: 20; - anchors.left: monitorShowsSwitchLabelGlyph.right; - anchors.leftMargin: 6; - size: 16; - width: paintedWidth; - height: paintedHeight; - color: hifi.colors.lightGrayText; - verticalAlignment: Text.AlignVCenter; - } - // "Monitor Shows" Switch - HifiControlsUit.Switch { - id: monitorShowsSwitch; - height: 30; - anchors.left: parent.left; - anchors.right: parent.right; - anchors.top: monitorShowsSwitchLabel.bottom; - anchors.topMargin: 10; - labelTextOff: "HMD Preview"; - labelTextOn: "Camera View"; - labelGlyphOnText: hifi.glyphs.alert; - onCheckedChanged: { - sendToScript({method: 'setMonitorShowsCameraView', params: checked}); - } - } - - // "Switch View From Controller" Checkbox - HifiControlsUit.CheckBox { - id: switchViewFromControllerCheckBox; - colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.top: monitorShowsSwitch.bottom; - anchors.topMargin: 25; - text: ""; - boxSize: 24; - onClicked: { - sendToScript({method: 'changeSwitchViewFromControllerPreference', params: checked}); - } - } - } - // - // SPECTATOR CONTROLS END - // - - // - // FUNCTION DEFINITIONS START - // - // - // Function Name: fromScript() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the SpectatorCamera JavaScript. - // Messages are in format "{method, params}", like json-rpc. - // - // Description: - // Called when a message is received from spectatorCamera.js. - // - function fromScript(message) { - switch (message.method) { - case 'updateSpectatorCameraCheckbox': - cameraToggleCheckBox.checked = message.params; - break; - case 'updateMonitorShowsSwitch': - monitorShowsSwitch.checked = message.params; - break; - case 'updateControllerMappingCheckbox': - switchViewFromControllerCheckBox.checked = message.setting; - switchViewFromControllerCheckBox.enabled = true; - if (message.controller === "OculusTouch") { - switchViewFromControllerCheckBox.text = "Clicking Left Touch's Thumbstick Switches Monitor View"; - } else if (message.controller === "Vive") { - switchViewFromControllerCheckBox.text = "Clicking Left Thumb Pad Switches Monitor View"; - } else { - switchViewFromControllerCheckBox.text = "Pressing Ctrl+0 Switches Monitor View"; - switchViewFromControllerCheckBox.checked = true; - switchViewFromControllerCheckBox.enabled = false; - } - break; - default: - console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message)); - } - } - signal sendToScript(var message); - - // - // FUNCTION DEFINITIONS END - // -} diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 1bd3891001..7b6efbd573 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -50,7 +50,7 @@ Item { id: colors // Base colors - readonly property color baseGray: "#393939" + readonly property color baseGray: "#404040" readonly property color darkGray: "#121212" readonly property color baseGrayShadow: "#252525" readonly property color baseGrayHighlight: "#575757" diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 4902f66a51..2270118861 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -25,7 +25,6 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-goto.js", "system/marketplaces/marketplaces.js", "system/edit.js", - "system/spectatorCamera.js", "system/notifications.js", "system/dialTone.js", "system/firstPersonHMD.js", diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js deleted file mode 100644 index 725de0215c..0000000000 --- a/scripts/system/spectatorCamera.js +++ /dev/null @@ -1,517 +0,0 @@ -"use strict"; -/*jslint vars:true, plusplus:true, forin:true*/ -/*global Tablet, Script, */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ -// -// spectatorCamera.js -// -// Created by Zach Fox on 2017-06-05 -// Copyright 2017 High Fidelity, Inc -// -// Distributed under the Apache License, Version 2.0 -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function () { // BEGIN LOCAL_SCOPE - - // - // FUNCTION VAR DECLARATIONS - // - var sendToQml, addOrRemoveButton, onTabletScreenChanged, fromQml, - onTabletButtonClicked, wireEventBridge, startup, shutdown, registerButtonMappings; - - // - // Function Name: inFrontOf() - // - // Description: - // Spectator camera utility functions and variables. - // - function inFrontOf(distance, position, orientation) { - return Vec3.sum(position || MyAvatar.position, - Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); - } - - // - // Function Name: updateRenderFromCamera() - // - // Relevant Variables: - // spectatorFrameRenderConfig: The render configuration of the spectator camera - // render job. Controls size. - // beginSpectatorFrameRenderConfig: The render configuration of the spectator camera - // render job. Controls position and orientation. - // viewFinderOverlay: The in-world overlay that displays the spectator camera's view. - // camera: The in-world entity that corresponds to the spectator camera. - // cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays - // drift with respect to their parent - // lastCameraPosition: Holds the last known camera position - // lastCameraRotation: Holds the last known camera rotation - // - // Arguments: - // None - // - // Description: - // The update function for the spectator camera. Modifies the camera's position - // and orientation. - // - var spectatorFrameRenderConfig = Render.getConfig("SecondaryCameraFrame"); - var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSecondaryCamera"); - var viewFinderOverlay = false; - var camera = false; - var cameraIsDynamic = false; - var lastCameraPosition = false; - var lastCameraRotation = false; - function updateRenderFromCamera() { - var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); - if (JSON.stringify(lastCameraRotation) !== JSON.stringify(cameraData.rotation)) { - lastCameraRotation = cameraData.rotation; - beginSpectatorFrameRenderConfig.orientation = lastCameraRotation; - } - if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) { - lastCameraPosition = cameraData.position; - beginSpectatorFrameRenderConfig.position = Vec3.sum(inFrontOf(0.17, lastCameraPosition, lastCameraRotation), {x: 0, y: 0.02, z: 0}); - } - } - - // - // Function Name: spectatorCameraOn() - // - // Relevant Variables: - // isUpdateRenderWired: Bool storing whether or not the camera's update - // function is wired. - // windowAspectRatio: The ratio of the Interface windows's sizeX/sizeY - // previewAspectRatio: The ratio of the camera preview's sizeX/sizeY - // vFoV: The vertical field of view of the spectator camera - // nearClipPlaneDistance: The near clip plane distance of the spectator camera - // farClipPlaneDistance: The far clip plane distance of the spectator camera - // - // Arguments: - // None - // - // Description: - // Call this function to set up the spectator camera and - // spawn the camera entity. - // - var isUpdateRenderWired = false; - var windowAspectRatio; - var previewAspectRatio = 16 / 9; - var vFoV = 45.0; - var nearClipPlaneDistance = 0.1; - var farClipPlaneDistance = 100.0; - function spectatorCameraOn() { - // Set the special texture size based on the window in which it will eventually be displayed. - var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. - var sizeX = Window.innerWidth; - var sizeY = Window.innerHeight; - windowAspectRatio = sizeX/sizeY; - spectatorFrameRenderConfig.resetSizeSpectatorCamera(sizeX, sizeY); - spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; - beginSpectatorFrameRenderConfig.vFoV = vFoV; - beginSpectatorFrameRenderConfig.nearClipPlaneDistance = nearClipPlaneDistance; - beginSpectatorFrameRenderConfig.farClipPlaneDistance = farClipPlaneDistance; - var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(1, Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 })); - Script.update.connect(updateRenderFromCamera); - isUpdateRenderWired = true; - camera = Entities.addEntity({ - "angularDamping": 0.98000001907348633, - "collisionsWillMove": 0, - "damping": 0.98000001907348633, - "dimensions": { - "x": 0.2338641881942749, - "y": 0.407032310962677, - "z": 0.38702544569969177 - }, - "dynamic": cameraIsDynamic, - "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/spectator-camera.fbx", - "queryAACube": { - "scale": 0.60840487480163574, - "x": -0.30420243740081787, - "y": -0.30420243740081787, - "z": -0.30420243740081787 - }, - "rotation": { x: 0, y: 0, z: 0 }, - "position": { x: 0, y: 0, z: 0 }, - "shapeType": "simple-compound", - "type": "Model", - "userData": "{\"grabbableKey\":{\"grabbable\":true}}" - }, true); - // This image3d overlay acts as the camera's preview screen. - viewFinderOverlay = Overlays.addOverlay("image3d", { - url: "resource://spectatorCameraFrame", - emissive: true, - parentID: camera, - alpha: 1, - position: { x: 0.007, y: 0.15, z: -0.005 }, - dimensions: { x: 0.16, y: -0.16 * windowAspectRatio / previewAspectRatio, z: 0 } - // Negative dimension for viewfinder is necessary for now due to the way Image3DOverlay - // draws textures. - // See Image3DOverlay.cpp:91. If you change the two lines there to: - // glm::vec2 topLeft(-x, -y); - // glm::vec2 bottomRight(x, y); - // the viewfinder will appear rightside up without this negative y-dimension. - // However, other Image3DOverlay textures (like the PAUSED one) will appear upside-down. *Why?* - // FIXME: This code will stretch the preview as the window aspect ratio changes. Fix that! - }); - Entities.editEntity(camera, { position: cameraPosition, rotation: cameraRotation }); - setDisplay(monitorShowsCameraView); - } - - // - // Function Name: spectatorCameraOff() - // - // Relevant Variables: - // None - // - // Arguments: - // None - // - // Description: - // Call this function to shut down the spectator camera and - // destroy the camera entity. - // - function spectatorCameraOff() { - spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = false; - if (isUpdateRenderWired) { - Script.update.disconnect(updateRenderFromCamera); - isUpdateRenderWired = false; - } - if (camera) { - Entities.deleteEntity(camera); - } - if (viewFinderOverlay) { - Overlays.deleteOverlay(viewFinderOverlay); - } - camera = false; - viewFinderOverlay = false; - setDisplay(monitorShowsCameraView); - } - - // - // Function Name: addOrRemoveButton() - // - // Relevant Variables: - // button: The tablet button. - // buttonName: The name of the button. - // tablet: The tablet instance to be modified. - // showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode - // - // Arguments: - // isShuttingDown: Set to "true" if you're calling this function upon script shutdown - // isHMDMode: "true" if user is in HMD; false otherwise - // - // Description: - // Used to add or remove the "SPECTATOR" app button from the HUD/tablet - // - var button = false; - var buttonName = "SPECTATOR"; - var tablet = null; - var showSpectatorInDesktop = true; - function addOrRemoveButton(isShuttingDown, isHMDMode) { - if (!button) { - if ((isHMDMode || showSpectatorInDesktop) && !isShuttingDown) { - button = tablet.addButton({ - text: buttonName - }); - button.clicked.connect(onTabletButtonClicked); - } - } else if (button) { - if ((!showSpectatorInDesktop || isShuttingDown) && !isHMDMode) { - button.clicked.disconnect(onTabletButtonClicked); - tablet.removeButton(button); - button = false; - } - } else { - print("ERROR adding/removing Spectator button!"); - } - } - - // - // Function Name: startup() - // - // Relevant Variables: - // None - // - // Arguments: - // None - // - // Description: - // startup() will be called when the script is loaded. - // - function startup() { - tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - addOrRemoveButton(false, HMD.active); - tablet.screenChanged.connect(onTabletScreenChanged); - Window.domainChanged.connect(spectatorCameraOff); - Controller.keyPressEvent.connect(keyPressEvent); - HMD.displayModeChanged.connect(onHMDChanged); - viewFinderOverlay = false; - camera = false; - registerButtonMappings(); - } - - // - // Function Name: wireEventBridge() - // - // Relevant Variables: - // hasEventBridge: true/false depending on whether we've already connected the event bridge - // - // Arguments: - // on: Enable or disable the event bridge - // - // Description: - // Used to connect/disconnect the script's response to the tablet's "fromQml" signal. - // - var hasEventBridge = false; - function wireEventBridge(on) { - if (on) { - if (!hasEventBridge) { - tablet.fromQml.connect(fromQml); - hasEventBridge = true; - } - } else { - if (hasEventBridge) { - tablet.fromQml.disconnect(fromQml); - hasEventBridge = false; - } - } - } - - function setDisplay(showCameraView) { - // It would be fancy if (showCameraView && !isUpdateRenderWired) would show instructions, but that's out of scope for now. - var url = (showCameraView && isUpdateRenderWired) ? "resource://spectatorCameraFrame" : ""; - Window.setDisplayTexture(url); - } - const MONITOR_SHOWS_CAMERA_VIEW_DEFAULT = false; - var monitorShowsCameraView = !!Settings.getValue('spectatorCamera/monitorShowsCameraView', MONITOR_SHOWS_CAMERA_VIEW_DEFAULT); - function setMonitorShowsCameraView(showCameraView) { - if (showCameraView === monitorShowsCameraView) { - return; - } - monitorShowsCameraView = showCameraView; - setDisplay(showCameraView); - Settings.setValue('spectatorCamera/monitorShowsCameraView', showCameraView); - } - function setMonitorShowsCameraViewAndSendToQml(showCameraView) { - setMonitorShowsCameraView(showCameraView); - sendToQml({ method: 'updateMonitorShowsSwitch', params: showCameraView }); - } - function keyPressEvent(event) { - if ((event.text === "0") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && event.isControl && !event.isAlt) { - setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); - } - } - - const SWITCH_VIEW_FROM_CONTROLLER_DEFAULT = false; - var switchViewFromController = !!Settings.getValue('spectatorCamera/switchViewFromController', SWITCH_VIEW_FROM_CONTROLLER_DEFAULT); - function setControllerMappingStatus(status) { - if (status) { - controllerMapping.enable(); - } else { - controllerMapping.disable(); - } - } - function setSwitchViewFromController(setting) { - if (setting === switchViewFromController) { - return; - } - switchViewFromController = setting; - setControllerMappingStatus(switchViewFromController); - Settings.setValue('spectatorCamera/switchViewFromController', setting); - } - - // - // Function Name: registerButtonMappings() - // - // Relevant Variables: - // controllerMappingName: The name of the controller mapping - // controllerMapping: The controller mapping itself - // controllerType: "OculusTouch", "Vive", "Other" - // - // Arguments: - // None - // - // Description: - // Updates controller button mappings for Spectator Camera. - // - var controllerMappingName; - var controllerMapping; - var controllerType = "Other"; - function registerButtonMappings() { - var VRDevices = Controller.getDeviceNames().toString(); - if (VRDevices.includes("Vive")) { - controllerType = "Vive"; - } else if (VRDevices.includes("OculusTouch")) { - controllerType = "OculusTouch"; - } - - controllerMappingName = 'Hifi-SpectatorCamera-Mapping'; - controllerMapping = Controller.newMapping(controllerMappingName); - if (controllerType === "OculusTouch") { - controllerMapping.from(Controller.Standard.LS).to(function (value) { - if (value === 1.0) { - setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); - } - return; - }); - } else if (controllerType === "Vive") { - controllerMapping.from(Controller.Standard.LeftPrimaryThumb).to(function (value) { - if (value === 1.0) { - setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView); - } - return; - }); - } - setControllerMappingStatus(switchViewFromController); - sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType }); - } - - // - // Function Name: onTabletButtonClicked() - // - // Relevant Variables: - // onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app - // shouldActivateButton: true/false depending on whether we should show the button as white or gray the - // next time we edit the button's properties - // - // Arguments: - // None - // - // Description: - // Fired when the Spectator Camera app button is pressed. - // - var onSpectatorCameraScreen = false; - var shouldActivateButton = false; - function onTabletButtonClicked() { - if (onSpectatorCameraScreen) { - // for toolbar-mode: go back to home screen, this will close the window. - tablet.gotoHomeScreen(); - } else { - shouldActivateButton = true; - tablet.loadQMLSource("../SpectatorCamera.qml"); - onSpectatorCameraScreen = true; - sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera }); - sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView }); - sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType }); - } - } - - // - // Function Name: onTabletScreenChanged() - // - // Relevant Variables: - // None - // - // Arguments: - // type: "Home", "Web", "Menu", "QML", "Closed" - // url: Only valid for Web and QML. - // - // Description: - // Called when the TabletScriptingInterface::screenChanged() signal is emitted. - // - function onTabletScreenChanged(type, url) { - wireEventBridge(shouldActivateButton); - // for toolbar mode: change button to active when window is first openend, false otherwise. - if (button) { - button.editProperties({ isActive: shouldActivateButton }); - } - shouldActivateButton = false; - onSpectatorCameraScreen = false; - } - - // - // Function Name: sendToQml() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message to send to the SpectatorCamera QML. - // Messages are in format "{method, params}", like json-rpc. See also fromQml(). - // - // Description: - // Use this function to send a message to the QML (i.e. to change appearances). - // - function sendToQml(message) { - tablet.sendToQml(message); - } - - // - // Function Name: fromQml() - // - // Relevant Variables: - // None - // - // Arguments: - // message: The message sent from the SpectatorCamera QML. - // Messages are in format "{method, params}", like json-rpc. See also sendToQml(). - // - // Description: - // Called when a message is received from SpectatorCamera.qml. - // - function fromQml(message) { - switch (message.method) { - case 'spectatorCameraOn': - spectatorCameraOn(); - break; - case 'spectatorCameraOff': - spectatorCameraOff(); - break; - case 'setMonitorShowsCameraView': - setMonitorShowsCameraView(message.params); - break; - case 'changeSwitchViewFromControllerPreference': - setSwitchViewFromController(message.params); - break; - default: - print('Unrecognized message from SpectatorCamera.qml:', JSON.stringify(message)); - } - } - - // - // Function Name: onHMDChanged() - // - // Relevant Variables: - // None - // - // Arguments: - // isHMDMode: "true" if HMD is on; "false" otherwise - // - // Description: - // Called from C++ when HMD mode is changed - // - function onHMDChanged(isHMDMode) { - setDisplay(monitorShowsCameraView); - addOrRemoveButton(false, isHMDMode); - if (!isHMDMode && !showSpectatorInDesktop) { - spectatorCameraOff(); - } - } - - // - // Function Name: shutdown() - // - // Relevant Variables: - // None - // - // Arguments: - // None - // - // Description: - // shutdown() will be called when the script ends (i.e. is stopped). - // - function shutdown() { - spectatorCameraOff(); - Window.domainChanged.disconnect(spectatorCameraOff); - addOrRemoveButton(true, HMD.active); - tablet.screenChanged.disconnect(onTabletScreenChanged); - HMD.displayModeChanged.disconnect(onHMDChanged); - Controller.keyPressEvent.disconnect(keyPressEvent); - controllerMapping.disable(); - } - - // - // These functions will be called when the script is loaded. - // - startup(); - Script.scriptEnding.connect(shutdown); - -}()); // END LOCAL_SCOPE From 8d45c4da7c596b138b714668168cdfe9736293b4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 19 Jun 2017 11:02:31 -0700 Subject: [PATCH 75/79] Fix comments --- .../model-networking/src/model-networking/TextureCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 864e79220f..982d0138b9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -469,6 +469,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { } +// This is called when the header or top mips have been loaded void NetworkTexture::ktxInitialDataRequestFinished() { if (!_ktxHeaderRequest || _ktxHeaderRequest->getState() != ResourceRequest::Finished || !_ktxMipRequest || _ktxMipRequest->getState() != ResourceRequest::Finished) { @@ -604,7 +605,7 @@ void NetworkTexture::ktxMipRequestFinished() { _ktxMipRequest = nullptr; } -// This is called when the header or top mips have been loaded +// This is called when the header and top mips have been loaded void NetworkTexture::handleFinishedInitialLoad() { Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); Q_ASSERT(!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty()); From 2e215e6544a9ac82174487fab4385980c8d63e25 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 19 Jun 2017 14:04:51 -0700 Subject: [PATCH 76/79] Fix build problems --- interface/src/SecondaryCamera.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index 0f74ff8be0..5ad19c9614 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -17,7 +17,6 @@ #include #include #include -#include "OctreeRenderer.h" class MainRenderTask { From 0c7f1cda0f7828b1952f5af40febdf3eb3e80aaa Mon Sep 17 00:00:00 2001 From: seefo Date: Mon, 19 Jun 2017 15:01:50 -0700 Subject: [PATCH 77/79] Added a restart button to domain server settings page --- domain-server/resources/web/header.html | 16 +++++++++- .../resources/web/js/domain-server.js | 31 +++++++++++++++++++ .../resources/web/settings/index.shtml | 13 -------- .../resources/web/settings/js/settings.js | 25 --------------- domain-server/src/DomainServer.cpp | 5 +++ 5 files changed, 51 insertions(+), 39 deletions(-) diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 965f86b0a1..0dc08e6e31 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -10,7 +10,6 @@ - + + +
diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index 3f78d8f466..88ab7b1470 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -1,3 +1,28 @@ +function showRestartModal() { + $('#restart-modal').modal({ + backdrop: 'static', + keyboard: false + }); + + var secondsElapsed = 0; + var numberOfSecondsToWait = 3; + + var refreshSpan = $('span#refresh-time') + refreshSpan.html(numberOfSecondsToWait + " seconds"); + + // call ourselves every 1 second to countdown + var refreshCountdown = setInterval(function(){ + secondsElapsed++; + secondsLeft = numberOfSecondsToWait - secondsElapsed + refreshSpan.html(secondsLeft + (secondsLeft == 1 ? " second" : " seconds")) + + if (secondsElapsed == numberOfSecondsToWait) { + location.reload(true); + clearInterval(refreshCountdown); + } + }, 1000); +} + $(document).ready(function(){ var url = window.location; // Will only work if string in href matches with location @@ -7,4 +32,10 @@ $(document).ready(function(){ $('ul.nav a').filter(function() { return this.href == url; }).parent().addClass('active'); + + $('body').on('click', '#restart-server', function(e){ + $.get("/restart"); + showRestartModal(); + return false; + }); }); \ No newline at end of file diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 1812c52dad..92ba7cf988 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -81,19 +81,6 @@
- - diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 39628ebb11..35573e4300 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1656,31 +1656,6 @@ function updateDataChangedForSiblingRows(row, forceTrue) { }) } -function showRestartModal() { - $('#restart-modal').modal({ - backdrop: 'static', - keyboard: false - }); - - var secondsElapsed = 0; - var numberOfSecondsToWait = 3; - - var refreshSpan = $('span#refresh-time') - refreshSpan.html(numberOfSecondsToWait + " seconds"); - - // call ourselves every 1 second to countdown - var refreshCountdown = setInterval(function(){ - secondsElapsed++; - secondsLeft = numberOfSecondsToWait - secondsElapsed - refreshSpan.html(secondsLeft + (secondsLeft == 1 ? " second" : " seconds")) - - if (secondsElapsed == numberOfSecondsToWait) { - location.reload(true); - clearInterval(refreshCountdown); - } - }, 1000); -} - function cleanupFormValues(node) { if (node.type && node.type === 'checkbox') { return { name: node.name, value: node.checked ? true : false }; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d637a20454..0c1ebbf189 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1650,6 +1650,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString URI_NODES = "/nodes"; const QString URI_SETTINGS = "/settings"; const QString URI_ENTITY_FILE_UPLOAD = "/content/upload"; + const QString URI_RESTART = "/restart"; const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; @@ -1804,6 +1805,10 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url // send the response connection->respond(HTTPConnection::StatusCode200, nodesDocument.toJson(), qPrintable(JSON_MIME_TYPE)); + return true; + } else if (url.path() == URI_RESTART) { + connection->respond(HTTPConnection::StatusCode200); + restart(); return true; } else { // check if this is for json stats for a node From cf9a97cf101bb6003f8f50579e595efc74e751ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 9 Jun 2017 11:56:52 -0700 Subject: [PATCH 78/79] use length sent by AssetServer to verify asset size --- libraries/networking/src/AssetClient.cpp | 18 ++++++++++++------ libraries/networking/src/AssetClient.h | 2 +- libraries/networking/src/AssetRequest.cpp | 7 +------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 054557e920..3faa9981dc 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -353,13 +353,20 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S connect(message.data(), &ReceivedMessage::progress, this, [this, weakNode, messageID, length](qint64 size) { handleProgressCallback(weakNode, messageID, size, length); }); - connect(message.data(), &ReceivedMessage::completed, this, [this, weakNode, messageID]() { - handleCompleteCallback(weakNode, messageID); + connect(message.data(), &ReceivedMessage::completed, this, [this, weakNode, messageID, length]() { + handleCompleteCallback(weakNode, messageID, length); }); if (message->isComplete()) { disconnect(message.data(), nullptr, this, nullptr); - callbacks.completeCallback(true, error, message->readAll()); + + if (length != message->getBytesLeftToRead()) { + callbacks.completeCallback(false, error, QByteArray()); + } else { + callbacks.completeCallback(true, error, message->readAll()); + } + + messageCallbackMap.erase(requestIt); } } @@ -391,7 +398,7 @@ void AssetClient::handleProgressCallback(const QWeakPointer& node, Message callbacks.progressCallback(size, length); } -void AssetClient::handleCompleteCallback(const QWeakPointer& node, MessageID messageID) { +void AssetClient::handleCompleteCallback(const QWeakPointer& node, MessageID messageID, DataOffset length) { auto senderNode = node.toStrongRef(); if (!senderNode) { @@ -424,8 +431,7 @@ void AssetClient::handleCompleteCallback(const QWeakPointer& node, Message return; } - - if (message->failed()) { + if (message->failed() || length != message->getBytesLeftToRead()) { callbacks.completeCallback(false, AssetServerError::NoError, QByteArray()); } else { callbacks.completeCallback(true, AssetServerError::NoError, message->readAll()); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 6f9cc3cd31..cab4a4f5b0 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -93,7 +93,7 @@ private: bool cancelUploadAssetRequest(MessageID id); void handleProgressCallback(const QWeakPointer& node, MessageID messageID, qint64 size, DataOffset length); - void handleCompleteCallback(const QWeakPointer& node, MessageID messageID); + void handleCompleteCallback(const QWeakPointer& node, MessageID messageID, DataOffset length); void forceFailureOfPendingRequests(SharedNodePointer node); diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 00fa3d9f2f..7fa563d4ad 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -104,12 +104,7 @@ void AssetRequest::start() { break; } } else { - if (_byteRange.isSet()) { - // we had a byte range, the size of the data does not match what we expect, so we return an error - if (data.size() != _byteRange.size()) { - _error = SizeVerificationFailed; - } - } else if (hashData(data).toHex() != _hash) { + if (!_byteRange.isSet() && hashData(data).toHex() != _hash) { // the hash of the received data does not match what we expect, so we return an error _error = HashVerificationFailed; } From ba9dbbb4d46bac650feed2d9db137723e071d4e8 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 19 Jun 2017 17:34:50 -0700 Subject: [PATCH 79/79] Fix the local lights issue, and correct the script relying on the Render.getConfig(), this one is on me... --- libraries/render-utils/src/LightClusters.cpp | 8 +--- .../utilities/render/ambientOcclusionPass.qml | 13 ++--- .../developer/utilities/render/culling.qml | 15 +++--- .../render/debugAmbientOcclusionPass.js | 2 +- .../render/debugSubsurfaceScattering.js | 2 +- .../utilities/render/deferredLighting.qml | 47 ++++++++++--------- .../utilities/render/lightClustering.qml | 47 ++++++++++--------- scripts/developer/utilities/render/stats.qml | 21 +++++---- .../developer/utilities/render/statsGPU.qml | 23 ++++----- .../utilities/render/subsurfaceScattering.qml | 35 +++++++------- .../utilities/render/surfaceGeometryPass.qml | 11 +++-- .../utilities/render/textureMonitor.qml | 3 +- 12 files changed, 116 insertions(+), 111 deletions(-) diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 7e04b1c2a4..e35120eb5b 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -548,6 +548,7 @@ glm::ivec3 LightClusters::updateClusters() { LightClusteringPass::LightClusteringPass() { + _lightClusters = std::make_shared(); } @@ -566,12 +567,7 @@ void LightClusteringPass::run(const render::RenderContextPointer& renderContext, auto deferredTransform = inputs.get0(); auto lightingModel = inputs.get1(); auto surfaceGeometryFramebuffer = inputs.get2(); - - - if (!_lightClusters) { - _lightClusters = std::make_shared(); - } - + // first update the Grid with the new frustum if (!_freeze) { _lightClusters->updateFrustum(args->getViewFrustum()); diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 3ebc80d2f1..86f55ef6aa 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -13,6 +13,7 @@ import "configSlider" import "../lib/plotperf" Column { + property var mainViewTask: Render.getConfig("RenderMainView") spacing: 8 Column { id: surfaceGeometry @@ -32,7 +33,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: (modelData.split(":")[3] == 'true') - config: Render.getConfig("AmbientOcclusion") + config: mainViewTask.getConfig("AmbientOcclusion") property: modelData.split(":")[1] max: modelData.split(":")[2] min: 0.0 @@ -50,8 +51,8 @@ Column { ] CheckBox { text: qsTr(modelData.split(":")[0]) - checked: Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] - onCheckedChanged: { Render.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked } + checked: mainViewTask.getConfig("AmbientOcclusion")[modelData.split(":")[1]] + onCheckedChanged: { mainViewTask.getConfig("AmbientOcclusion")[modelData.split(":")[1]] = checked } } } } @@ -62,8 +63,8 @@ Column { ] CheckBox { text: qsTr(modelData.split(":")[0]) - checked: Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] - onCheckedChanged: { Render.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] = checked } + checked: mainViewTask.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] + onCheckedChanged: { mainViewTask.getConfig("DebugAmbientOcclusion")[modelData.split(":")[1]] = checked } } } } @@ -72,7 +73,7 @@ Column { PlotPerf { title: "Timing" height: 50 - object: Render.getConfig("AmbientOcclusion") + object: mainViewTask.getConfig("AmbientOcclusion") valueUnit: "ms" valueScale: 1 valueNumDigits: "3" diff --git a/scripts/developer/utilities/render/culling.qml b/scripts/developer/utilities/render/culling.qml index e3f5e67bbe..3c3c0f67d9 100644 --- a/scripts/developer/utilities/render/culling.qml +++ b/scripts/developer/utilities/render/culling.qml @@ -14,8 +14,9 @@ import "configSlider" Column { id: root spacing: 8 - property var sceneOctree: Render.getConfig("DrawSceneOctree"); - property var itemSelection: Render.getConfig("DrawItemSelection"); + property var mainViewTask: Render.getConfig("RenderMainView"); + property var sceneOctree: mainViewTask.getConfig("DrawSceneOctree"); + property var itemSelection: mainViewTask.getConfig("DrawItemSelection"); Component.onCompleted: { sceneOctree.enabled = true; @@ -30,8 +31,8 @@ Column { Component.onDestruction: { sceneOctree.enabled = false; itemSelection.enabled = false; - Render.getConfig("FetchSceneSelection").freezeFrustum = false; - Render.getConfig("CullSceneSelection").freezeFrustum = false; + mainViewTask.getConfig("FetchSceneSelection").freezeFrustum = false; + mainViewTask.getConfig("CullSceneSelection").freezeFrustum = false; } GroupBox { @@ -45,8 +46,8 @@ Column { text: "Freeze Culling Frustum" checked: false onCheckedChanged: { - Render.getConfig("FetchSceneSelection").freezeFrustum = checked; - Render.getConfig("CullSceneSelection").freezeFrustum = checked; + mainViewTask.getConfig("FetchSceneSelection").freezeFrustum = checked; + mainViewTask.getConfig("CullSceneSelection").freezeFrustum = checked; } } Label { @@ -103,7 +104,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: true - config: Render.getConfig(modelData.split(":")[1]) + config: mainViewTask.getConfig(modelData.split(":")[1]) property: "maxDrawn" max: config.numDrawn min: -1 diff --git a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js index c57fdf0526..e93d153486 100644 --- a/scripts/developer/utilities/render/debugAmbientOcclusionPass.js +++ b/scripts/developer/utilities/render/debugAmbientOcclusionPass.js @@ -34,5 +34,5 @@ function setDebugCursor(x, y) { nx = (x / Window.innerWidth); ny = 1.0 - ((y) / (Window.innerHeight - 32)); - Render.getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; + Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny }; } diff --git a/scripts/developer/utilities/render/debugSubsurfaceScattering.js b/scripts/developer/utilities/render/debugSubsurfaceScattering.js index 72b15546e0..c578ef0f06 100644 --- a/scripts/developer/utilities/render/debugSubsurfaceScattering.js +++ b/scripts/developer/utilities/render/debugSubsurfaceScattering.js @@ -33,5 +33,5 @@ function setDebugCursor(x, y) { nx = (x / Window.innerWidth); ny = 1.0 - ((y) / (Window.innerHeight - 32)); - Render.getConfig("DebugScattering").debugCursorTexcoord = { x: nx, y: ny }; + Render.getConfig("RenderMainView").getConfig("DebugScattering").debugCursorTexcoord = { x: nx, y: ny }; } diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index ff4621a87a..2254b6d95f 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -13,6 +13,7 @@ import "configSlider" Column { spacing: 8 + property var mainViewTask: Render.getConfig("RenderMainView") Row { spacing: 8 @@ -29,8 +30,8 @@ Column { ] CheckBox { text: modelData.split(":")[0] - checked: Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] - onCheckedChanged: { Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } + checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] + onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } } } } @@ -49,8 +50,8 @@ Column { ] CheckBox { text: modelData.split(":")[0] - checked: Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] - onCheckedChanged: { Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } + checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] + onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } } } } @@ -69,8 +70,8 @@ Column { ] CheckBox { text: modelData.split(":")[0] - checked: Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] - onCheckedChanged: { Render.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } + checked: mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] + onCheckedChanged: { mainViewTask.getConfig(modelData.split(":")[1])[modelData.split(":")[2]] = checked } } } } @@ -83,7 +84,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: false - config: Render.getConfig(modelData.split(":")[1]) + config: mainViewTask.getConfig(modelData.split(":")[1]) property: modelData.split(":")[2] max: modelData.split(":")[3] min: modelData.split(":")[4] @@ -107,7 +108,7 @@ Column { ListElement { text: "Filmic"; color: "White" } } width: 200 - onCurrentIndexChanged: { Render.getConfig("ToneMapping")["curve"] = currentIndex } + onCurrentIndexChanged: { mainViewTask.getConfig("ToneMapping")["curve"] = currentIndex } } } } @@ -120,7 +121,7 @@ Column { anchors.left: root.left } - property var config: Render.getConfig("DebugDeferredBuffer") + property var config: mainViewTask.getConfig("DebugDeferredBuffer") function setDebugMode(mode) { framebuffer.config.enabled = (mode != 0); @@ -168,40 +169,40 @@ Column { CheckBox { text: "Opaques" - checked: Render.getConfig("DrawOpaqueBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawOpaqueBounds")["enabled"] = checked } + checked: mainViewTask.getConfig("DrawOpaqueBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawOpaqueBounds")["enabled"] = checked } } CheckBox { text: "Transparents" - checked: Render.getConfig("DrawTransparentBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawTransparentBounds")["enabled"] = checked } + checked: mainViewTask.getConfig("DrawTransparentBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawTransparentBounds")["enabled"] = checked } } CheckBox { text: "Overlay Opaques" - checked: Render.getConfig("DrawOverlayOpaqueBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawOverlayOpaqueBounds")["enabled"] = checked } + checked: mainViewTask.getConfig("DrawOverlayOpaqueBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawOverlayOpaqueBounds")["enabled"] = checked } } CheckBox { text: "Overlay Transparents" - checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked } + checked: mainViewTask.getConfig("DrawOverlayTransparentBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked } } } Column { CheckBox { text: "Metas" - checked: Render.getConfig("DrawMetaBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawMetaBounds")["enabled"] = checked } + checked: mainViewTask.getConfig("DrawMetaBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawMetaBounds")["enabled"] = checked } } CheckBox { text: "Lights" - checked: Render.getConfig("DrawLightBounds")["enabled"] - onCheckedChanged: { Render.getConfig("DrawLightBounds")["enabled"] = checked; } + checked: mainViewTask.getConfig("DrawLightBounds")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("DrawLightBounds")["enabled"] = checked; } } CheckBox { text: "Zones" - checked: Render.getConfig("DrawZones")["enabled"] - onCheckedChanged: { Render.getConfig("ZoneRenderer")["enabled"] = checked; Render.getConfig("DrawZones")["enabled"] = checked; } + checked: mainViewTask.getConfig("DrawZones")["enabled"] + onCheckedChanged: { mainViewTask.getConfig("ZoneRenderer")["enabled"] = checked; mainViewTask.getConfig("DrawZones")["enabled"] = checked; } } } } diff --git a/scripts/developer/utilities/render/lightClustering.qml b/scripts/developer/utilities/render/lightClustering.qml index 4db7aa8c39..930fd79db3 100644 --- a/scripts/developer/utilities/render/lightClustering.qml +++ b/scripts/developer/utilities/render/lightClustering.qml @@ -17,18 +17,19 @@ Column { Column { id: lightClustering spacing: 10 + property var mainViewTask: Render.getConfig("RenderMainView"); Column{ PlotPerf { title: "Light CLustering Timing" height: 50 - object: Render.getConfig("LightClustering") + object: mainViewTask.getConfig("LightClustering") valueUnit: "ms" valueScale: 1 valueNumDigits: "4" plots: [ { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "cpuRunTime", label: "time", scale: 1, @@ -40,19 +41,19 @@ Column { PlotPerf { title: "Lights" height: 50 - object: Render.getConfig("LightClustering") + object: mainViewTask.getConfig("LightClustering") valueUnit: "" valueScale: 1 valueNumDigits: "0" plots: [ { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "numClusteredLights", label: "visible", color: "#D959FE" }, { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "numInputLights", label: "input", color: "#FED959" @@ -63,25 +64,25 @@ Column { PlotPerf { title: "Scene Lights" height: 80 - object: Render.getConfig("LightClustering") + object: mainViewTask.getConfig("LightClustering") valueUnit: "" valueScale: 1 valueNumDigits: "0" plots: [ { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "numSceneLights", label: "current", color: "#00B4EF" }, { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "numFreeSceneLights", label: "free", color: "#1AC567" }, { - object: Render.getConfig("LightClustering"), + object: mainViewTask.getConfig("LightClustering"), prop: "numAllocatedSceneLights", label: "allocated", color: "#9495FF" @@ -92,7 +93,7 @@ Column { ConfigSlider { label: qsTr("Range Near [m]") integral: false - config: Render.getConfig("LightClustering") + config: mainViewTask.getConfig("LightClustering") property: "rangeNear" max: 20.0 min: 0.1 @@ -100,7 +101,7 @@ Column { ConfigSlider { label: qsTr("Range Far [m]") integral: false - config: Render.getConfig("LightClustering") + config: mainViewTask.getConfig("LightClustering") property: "rangeFar" max: 500.0 min: 100.0 @@ -108,7 +109,7 @@ Column { ConfigSlider { label: qsTr("Grid X") integral: true - config: Render.getConfig("LightClustering") + config: mainViewTask.getConfig("LightClustering") property: "dimX" max: 32 min: 1 @@ -116,7 +117,7 @@ Column { ConfigSlider { label: qsTr("Grid Y") integral: true - config: Render.getConfig("LightClustering") + config: mainViewTask.getConfig("LightClustering") property: "dimY" max: 32 min: 1 @@ -124,33 +125,33 @@ Column { ConfigSlider { label: qsTr("Grid Z") integral: true - config: Render.getConfig("LightClustering") + config: mainViewTask.getConfig("LightClustering") property: "dimZ" max: 31 min: 1 } CheckBox { text: "Freeze" - checked: Render.getConfig("LightClustering")["freeze"] - onCheckedChanged: { Render.getConfig("LightClustering")["freeze"] = checked } + checked: mainViewTask.getConfig("LightClustering")["freeze"] + onCheckedChanged: { mainViewTask.getConfig("LightClustering")["freeze"] = checked } } CheckBox { text: "Draw Grid" - checked: Render.getConfig("DebugLightClusters")["doDrawGrid"] - onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawGrid"] = checked } + checked: mainViewTask.getConfig("DebugLightClusters")["doDrawGrid"] + onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawGrid"] = checked } } CheckBox { text: "Draw Cluster From Depth" - checked: Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] - onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] = checked } + checked: mainViewTask.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] + onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawClusterFromDepth"] = checked } } CheckBox { text: "Draw Content" - checked: Render.getConfig("DebugLightClusters")["doDrawContent"] - onCheckedChanged: { Render.getConfig("DebugLightClusters")["doDrawContent"] = checked } + checked: mainViewTask.getConfig("DebugLightClusters")["doDrawContent"] + onCheckedChanged: { mainViewTask.getConfig("DebugLightClusters")["doDrawContent"] = checked } } Label { - text: "Num Cluster Items = " + Render.getConfig("LightClustering")["numClusteredLightReferences"].toFixed(0) + text: "Num Cluster Items = " + mainViewTask.getConfig("LightClustering")["numClusteredLightReferences"].toFixed(0) } } diff --git a/scripts/developer/utilities/render/stats.qml b/scripts/developer/utilities/render/stats.qml index 54e0dc4ce8..064045e8f5 100644 --- a/scripts/developer/utilities/render/stats.qml +++ b/scripts/developer/utilities/render/stats.qml @@ -21,7 +21,8 @@ Item { spacing: 8 anchors.fill:parent - property var config: Render.getConfig("Stats") + property var mainViewTask: Render.getConfig("RenderMainView"); + property var config: mainViewTask.getConfig("Stats") function evalEvenHeight() { // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? @@ -182,9 +183,9 @@ Item { ] } - property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred") - property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred") - property var drawLightConfig: Render.getConfig("DrawLight") + property var drawOpaqueConfig: mainViewTask.getConfig("DrawOpaqueDeferred") + property var drawTransparentConfig: mainViewTask.getConfig("DrawTransparentDeferred") + property var drawLightConfig: mainViewTask.getConfig("DrawLight") PlotPerf { title: "Items" @@ -199,13 +200,13 @@ Item { color: "#1AC567" }, { - object: Render.getConfig("DrawTransparentDeferred"), + object: mainViewTask.getConfig("DrawTransparentDeferred"), prop: "numDrawn", label: "Translucents", color: "#00B4EF" }, { - object: Render.getConfig("DrawLight"), + object: mainViewTask.getConfig("DrawLight"), prop: "numDrawn", label: "Lights", color: "#FED959" @@ -222,25 +223,25 @@ Item { valueNumDigits: "2" plots: [ { - object: Render.getConfig("DrawOpaqueDeferred"), + object: mainViewTask.getConfig("DrawOpaqueDeferred"), prop: "cpuRunTime", label: "Opaques", color: "#1AC567" }, { - object: Render.getConfig("DrawTransparentDeferred"), + object: mainViewTask.getConfig("DrawTransparentDeferred"), prop: "cpuRunTime", label: "Translucents", color: "#00B4EF" }, { - object: Render.getConfig("RenderDeferred"), + object: mainViewTask.getConfig("RenderDeferred"), prop: "cpuRunTime", label: "Lighting", color: "#FED959" }, { - object: Render.getConfig("RenderDeferredTask"), + object: mainViewTask.getConfig("RenderDeferredTask"), prop: "cpuRunTime", label: "RenderFrame", color: "#E2334D" diff --git a/scripts/developer/utilities/render/statsGPU.qml b/scripts/developer/utilities/render/statsGPU.qml index 3d23c2c6dc..b3f5ec6e45 100644 --- a/scripts/developer/utilities/render/statsGPU.qml +++ b/scripts/developer/utilities/render/statsGPU.qml @@ -21,7 +21,8 @@ Item { spacing: 8 anchors.fill:parent - property var config: Render.getConfig("Stats") + property var mainViewTask: Render.getConfig("RenderMainView"); + property var config: mainViewTask.getConfig("Stats") function evalEvenHeight() { // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? @@ -38,31 +39,31 @@ Item { valueNumDigits: "4" plots: [ { - object: Render.getConfig("OpaqueRangeTimer"), + object: mainViewTask.getConfig("OpaqueRangeTimer"), prop: "gpuRunTime", label: "Opaque", color: "#FFFFFF" }, { - object: Render.getConfig("LinearDepth"), + object: mainViewTask.getConfig("LinearDepth"), prop: "gpuRunTime", label: "LinearDepth", color: "#00FF00" },{ - object: Render.getConfig("SurfaceGeometry"), + object: mainViewTask.getConfig("SurfaceGeometry"), prop: "gpuRunTime", label: "SurfaceGeometry", color: "#00FFFF" }, { - object: Render.getConfig("RenderDeferred"), + object: mainViewTask.getConfig("RenderDeferred"), prop: "gpuRunTime", label: "DeferredLighting", color: "#FF00FF" } , { - object: Render.getConfig("ToneAndPostRangeTimer"), + object: mainViewTask.getConfig("ToneAndPostRangeTimer"), prop: "gpuRunTime", label: "tone and post", color: "#FF0000" @@ -78,31 +79,31 @@ Item { valueNumDigits: "3" plots: [ { - object: Render.getConfig("OpaqueRangeTimer"), + object: mainViewTask.getConfig("OpaqueRangeTimer"), prop: "batchRunTime", label: "Opaque", color: "#FFFFFF" }, { - object: Render.getConfig("LinearDepth"), + object: mainViewTask.getConfig("LinearDepth"), prop: "batchRunTime", label: "LinearDepth", color: "#00FF00" },{ - object: Render.getConfig("SurfaceGeometry"), + object: mainViewTask.getConfig("SurfaceGeometry"), prop: "batchRunTime", label: "SurfaceGeometry", color: "#00FFFF" }, { - object: Render.getConfig("RenderDeferred"), + object: mainViewTask.getConfig("RenderDeferred"), prop: "batchRunTime", label: "DeferredLighting", color: "#FF00FF" } , { - object: Render.getConfig("ToneAndPostRangeTimer"), + object: mainViewTask.getConfig("ToneAndPostRangeTimer"), prop: "batchRunTime", label: "tone and post", color: "#FF0000" diff --git a/scripts/developer/utilities/render/subsurfaceScattering.qml b/scripts/developer/utilities/render/subsurfaceScattering.qml index 47b960c98b..53bca7f2b8 100644 --- a/scripts/developer/utilities/render/subsurfaceScattering.qml +++ b/scripts/developer/utilities/render/subsurfaceScattering.qml @@ -16,28 +16,29 @@ Column { Column { id: scattering spacing: 10 + property var mainViewTask: Render.getConfig("RenderMainView"); Column{ CheckBox { text: "Scattering" - checked: Render.getConfig("Scattering").enableScattering - onCheckedChanged: { Render.getConfig("Scattering").enableScattering = checked } + checked: mainViewTask.getConfig("Scattering").enableScattering + onCheckedChanged: { mainViewTask.getConfig("Scattering").enableScattering = checked } } CheckBox { text: "Show Scattering BRDF" - checked: Render.getConfig("Scattering").showScatteringBRDF - onCheckedChanged: { Render.getConfig("Scattering").showScatteringBRDF = checked } + checked: mainViewTask.getConfig("Scattering").showScatteringBRDF + onCheckedChanged: { mainViewTask.getConfig("Scattering").showScatteringBRDF = checked } } CheckBox { text: "Show Curvature" - checked: Render.getConfig("Scattering").showCurvature - onCheckedChanged: { Render.getConfig("Scattering").showCurvature = checked } + checked: mainViewTask.getConfig("Scattering").showCurvature + onCheckedChanged: { mainViewTask.getConfig("Scattering").showCurvature = checked } } CheckBox { text: "Show Diffused Normal" - checked: Render.getConfig("Scattering").showDiffusedNormal - onCheckedChanged: { Render.getConfig("Scattering").showDiffusedNormal = checked } + checked: mainViewTask.getConfig("Scattering").showDiffusedNormal + onCheckedChanged: { mainViewTask.getConfig("Scattering").showDiffusedNormal = checked } } Repeater { model: [ "Scattering Bent Red:Scattering:bentRed:2.0", @@ -50,7 +51,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: false - config: Render.getConfig(modelData.split(":")[1]) + config: mainViewTask.getConfig(modelData.split(":")[1]) property: modelData.split(":")[2] max: modelData.split(":")[3] min: 0.0 @@ -58,23 +59,23 @@ Column { } CheckBox { text: "Scattering Profile" - checked: Render.getConfig("DebugScattering").showProfile - onCheckedChanged: { Render.getConfig("DebugScattering").showProfile = checked } + checked: mainViewTask.getConfig("DebugScattering").showProfile + onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showProfile = checked } } CheckBox { text: "Scattering Table" - checked: Render.getConfig("DebugScattering").showLUT - onCheckedChanged: { Render.getConfig("DebugScattering").showLUT = checked } + checked: mainViewTask.getConfig("DebugScattering").showLUT + onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showLUT = checked } } CheckBox { text: "Cursor Pixel" - checked: Render.getConfig("DebugScattering").showCursorPixel - onCheckedChanged: { Render.getConfig("DebugScattering").showCursorPixel = checked } + checked: mainViewTask.getConfig("DebugScattering").showCursorPixel + onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showCursorPixel = checked } } CheckBox { text: "Skin Specular Beckmann" - checked: Render.getConfig("DebugScattering").showSpecularTable - onCheckedChanged: { Render.getConfig("DebugScattering").showSpecularTable = checked } + checked: mainViewTask.getConfig("DebugScattering").showSpecularTable + onCheckedChanged: { mainViewTask.getConfig("DebugScattering").showSpecularTable = checked } } } } diff --git a/scripts/developer/utilities/render/surfaceGeometryPass.qml b/scripts/developer/utilities/render/surfaceGeometryPass.qml index 1ff0efa15d..7e70dceef1 100644 --- a/scripts/developer/utilities/render/surfaceGeometryPass.qml +++ b/scripts/developer/utilities/render/surfaceGeometryPass.qml @@ -16,12 +16,13 @@ Column { Column { id: surfaceGeometry spacing: 10 + property var mainViewTask: Render.getConfig("RenderMainView"); Column{ ConfigSlider { label: qsTr("Depth Threshold [cm]") integral: false - config: Render.getConfig("SurfaceGeometry") + config: mainViewTask.getConfig("SurfaceGeometry") property: "depthThreshold" max: 5.0 min: 0.0 @@ -34,7 +35,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: (modelData.split(":")[3] == 'true') - config: Render.getConfig("SurfaceGeometry") + config: mainViewTask.getConfig("SurfaceGeometry") property: modelData.split(":")[1] max: modelData.split(":")[2] min: 0.0 @@ -42,8 +43,8 @@ Column { } CheckBox { text: "Half Resolution" - checked: Render.getConfig("SurfaceGeometry")["resolutionLevel"] - onCheckedChanged: { Render.getConfig("SurfaceGeometry")["resolutionLevel"] = checked } + checked: mainViewTask.getConfig("SurfaceGeometry")["resolutionLevel"] + onCheckedChanged: { mainViewTask.getConfig("SurfaceGeometry")["resolutionLevel"] = checked } } Repeater { @@ -53,7 +54,7 @@ Column { ConfigSlider { label: qsTr(modelData.split(":")[0]) integral: false - config: Render.getConfig(modelData.split(":")[1]) + config: mainViewTask.getConfig(modelData.split(":")[1]) property: modelData.split(":")[2] max: modelData.split(":")[3] min: 0.0 diff --git a/scripts/developer/utilities/render/textureMonitor.qml b/scripts/developer/utilities/render/textureMonitor.qml index 97cc577ff9..1a6dffab23 100644 --- a/scripts/developer/utilities/render/textureMonitor.qml +++ b/scripts/developer/utilities/render/textureMonitor.qml @@ -22,7 +22,8 @@ Item { spacing: 8 anchors.fill:parent - property var config: Render.getConfig("Stats") + property var mainViewTask: Render.getConfig("RenderMainView"); + property var config: mainViewTask.getConfig("Stats") function evalEvenHeight() { // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?