From b8fdb667457e8339b7ad240d88e80bd2b5425073 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 20 Sep 2017 14:20:43 -0700 Subject: [PATCH 001/171] added support for fbx formats --- interface/src/Application.cpp | 53 ++++++++++++++++++++++++++++------- interface/src/Application.h | 1 + 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bd870ff8bb..8491a8dc07 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -341,7 +341,8 @@ const QHash Application::_acceptedExtensi { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, - { ZIP_EXTENSION, &Application::importFromZIP } + { ZIP_EXTENSION, &Application::importFromZIP }, + { FBX_EXTENSION, &Application::importFromFBX } }; class DeadlockWatchdogThread : public QThread { @@ -2893,6 +2894,18 @@ bool Application::importFromZIP(const QString& filePath) { return true; } +bool Application::importFromFBX(const QString& filePath) { + qDebug() << "An fbx file has been dropped in: " << filePath; + QUrl empty; + // handle Blocks download from Marketplace + if (filePath.contains("vr.google.com/downloads")) { + addAssetToWorldFromURL(filePath); + } else { + addAssetToWorld(filePath, "", false, false); + } + return true; +} + void Application::onPresent(quint32 frameCount) { postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); if (_renderEventHandler && !isAboutToQuit()) { @@ -6412,7 +6425,11 @@ void Application::addAssetToWorldFromURL(QString url) { if (url.contains("vr.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { - filename.remove(".zip?noDownload=false"); + if (url.contains(".fbx")) { + filename.remove("?noDownload=false"); + } else { + filename.remove(".zip?noDownload=false"); + } } else { filename.remove(".zip"); } @@ -6439,7 +6456,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { auto result = request->getResult(); QString filename; - bool isBlocks = false; + bool isBlocksOBJ = false; if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. @@ -6447,11 +6464,15 @@ void Application::addAssetToWorldFromURLRequestFinished() { if (url.contains("vr.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { - filename.remove(".zip?noDownload=false"); + if (url.contains(".fbx")) { + filename.remove("?noDownload=false"); + } else { + filename.remove(".zip?noDownload=false"); + } } else { filename.remove(".zip"); } - isBlocks = true; + isBlocksOBJ = true; } if (result == ResourceRequest::Success) { @@ -6468,7 +6489,11 @@ void Application::addAssetToWorldFromURLRequestFinished() { tempFile.write(request->getData()); addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key. tempFile.close(); - qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocks); + if (url.contains(".fbx")) { + addAssetToWorld(downloadPath, "", false, false); + } else { + qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocksOBJ); + } } else { QString errorInfo = "Couldn't open temporary file for download"; qWarning(interfaceapp) << errorInfo; @@ -6498,7 +6523,7 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { addAssetToWorldError(filename, "Couldn't unzip file " + filename + "."); } -void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks) { +void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocksOBJ) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString path = filePath; @@ -6507,7 +6532,7 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); mapping = "/" + assetFolder + "/" + filename; - } else if (isBlocks) { + } else if (isBlocksOBJ) { qCDebug(interfaceapp) << "Path to asset folder: " << zipFile; QString assetFolder = zipFile.section('/', -1); assetFolder.remove(".zip?noDownload=false"); @@ -6638,6 +6663,14 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // Close progress message box. addAssetToWorldInfoDone(filenameFromPath(filePath)); } + + // Delete temporary directories created from downloads + if (filePath.contains(".fbx")) { + qCDebug(interfaceapp) << "gonna try to remove the temp dir: " << filePath; + QString tempPath = filePath.remove(filePath.section("/", -1)); + qCDebug(interfaceapp) << tempPath; + qCDebug(interfaceapp) << QDir(tempPath).removeRecursively(); + } } void Application::addAssetToWorldCheckModelSize() { @@ -6891,12 +6924,12 @@ void Application::onAssetToWorldMessageBoxClosed() { } -void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks) { +void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocksOBJ) { if (autoAdd) { if (!unzipFile.isEmpty()) { for (int i = 0; i < unzipFile.length(); i++) { qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); - addAssetToWorld(unzipFile.at(i), zipFile, isZip, isBlocks); + addAssetToWorld(unzipFile.at(i), zipFile, isZip, isBlocksOBJ); } } else { addAssetToWorldUnzipFailure(zipFile); diff --git a/interface/src/Application.h b/interface/src/Application.h index 86e4f94917..c6643c38e6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -486,6 +486,7 @@ private: bool importJSONFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString); bool importFromZIP(const QString& filePath); + bool importFromFBX(const QString& filePath); bool nearbyEntitiesAreReadyForPhysics(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); From 92550b749c3ef958cbc731db30645c8e71cb2f7b Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 20 Sep 2017 14:23:09 -0700 Subject: [PATCH 002/171] removed extraneous printouts --- interface/src/Application.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7e7771a6d..95b13a1da7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6687,9 +6687,8 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // Delete temporary directories created from downloads if (filePath.contains(".fbx")) { - qCDebug(interfaceapp) << "gonna try to remove the temp dir: " << filePath; QString tempPath = filePath.remove(filePath.section("/", -1)); - qCDebug(interfaceapp) << tempPath; + qCDebug(interfaceapp) << "Removing temporary path: " << tempPath; qCDebug(interfaceapp) << QDir(tempPath).removeRecursively(); } } From 1ac0a8224fe47dcddf945368023e6cd930d154f1 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 20 Sep 2017 14:23:53 -0700 Subject: [PATCH 003/171] removed extraneous printouts again --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95b13a1da7..21e4a0ec53 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6689,7 +6689,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { if (filePath.contains(".fbx")) { QString tempPath = filePath.remove(filePath.section("/", -1)); qCDebug(interfaceapp) << "Removing temporary path: " << tempPath; - qCDebug(interfaceapp) << QDir(tempPath).removeRecursively(); + QDir(tempPath).removeRecursively(); } } From bcec3680b6ac0676262d755f588bfd0c6f0455b8 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 25 Sep 2017 11:51:23 +0200 Subject: [PATCH 004/171] First draft --- libraries/render-utils/src/BloomEffect.cpp | 36 ++++++++++++++ libraries/render-utils/src/BloomEffect.h | 47 +++++++++++++++++++ .../render-utils/src/RenderDeferredTask.cpp | 5 ++ 3 files changed, 88 insertions(+) create mode 100644 libraries/render-utils/src/BloomEffect.cpp create mode 100644 libraries/render-utils/src/BloomEffect.h diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp new file mode 100644 index 0000000000..a0a36a2194 --- /dev/null +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -0,0 +1,36 @@ +// +// BloomEffect.cpp +// render-utils/src/ +// +// Created by Olivier Prat on 09/25/17. +// 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 +// +#include "BloomEffect.h" + +#include + +void BloomConfig::setMix(float value) { + +} + +void BloomConfig::setSize(float value) { + auto blurConfig = getConfig("Blur"); + assert(blurConfig); + blurConfig->setProperty("filterScale", value*10.0f); +} + +Bloom::Bloom() { + +} + +void Bloom::configure(const Config& config) { + +} + +void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { + const auto& blurInput = inputs; + task.addJob("Blur", blurInput); +} diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h new file mode 100644 index 0000000000..278236d2e9 --- /dev/null +++ b/libraries/render-utils/src/BloomEffect.h @@ -0,0 +1,47 @@ +// +// BloomEffect.h +// render-utils/src/ +// +// Created by Olivier Prat on 09/25/17. +// 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 +// + +#ifndef hifi_render_utils_BloomEffect_h +#define hifi_render_utils_BloomEffect_h + +#include + +class BloomConfig : public render::Task::Config { + Q_OBJECT + Q_PROPERTY(float mix MEMBER mix WRITE setMix NOTIFY dirty) + Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) + +public: + + float mix{ 0.2f }; + float size{ 0.1f }; + + void setMix(float value); + void setSize(float value); + +signals: + void dirty(); +}; + +class Bloom { +public: + using Inputs = gpu::FramebufferPointer; + using Config = BloomConfig; + using JobModel = render::Task::ModelI; + + Bloom(); + + void configure(const Config& config); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); + +}; + +#endif // hifi_render_utils_BloomEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c67a1c7875..682d5db435 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -41,6 +41,7 @@ #include "ToneMappingEffect.h" #include "SubsurfaceScattering.h" #include "OutlineEffect.h" +#include "BloomEffect.h" #include @@ -168,6 +169,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneAndPostRangeTimer = task.addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); + // Add bloom + const auto bloomInputs = lightingFramebuffer; + task.addJob("Bloom", bloomInputs); + // Lighting Buffer ready for tone mapping const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying(); task.addJob("ToneMapping", toneMappingInputs); From 443d6dfacb1716d45ae8a03bd1a8e7987cb209fa Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 25 Sep 2017 14:24:40 +0200 Subject: [PATCH 005/171] Added user definable taps in blur task --- libraries/render/src/render/BlurTask.cpp | 56 ++++++++++++- libraries/render/src/render/BlurTask.h | 11 ++- libraries/render/src/render/BlurTask.slh | 83 ++++++++----------- .../render/src/render/BlurTask_shared.slh | 10 +++ 4 files changed, 107 insertions(+), 53 deletions(-) create mode 100644 libraries/render/src/render/BlurTask_shared.slh diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 73a8e0a0dd..2d51fd1271 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -29,11 +29,10 @@ enum BlurShaderMapSlots { BlurTask_DepthSlot, }; -const float BLUR_NUM_SAMPLES = 7.0f; - BlurParams::BlurParams() { Params params; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Params), (const gpu::Byte*) ¶ms)); + setGaussianFilterTaps(3); } void BlurParams::setWidthHeight(int width, int height, bool isStereo) { @@ -60,7 +59,58 @@ void BlurParams::setFilterRadiusScale(float scale) { auto filterInfo = _parametersBuffer.get().filterInfo; if (scale != filterInfo.x) { _parametersBuffer.edit().filterInfo.x = scale; - _parametersBuffer.edit().filterInfo.y = scale / BLUR_NUM_SAMPLES; + } +} + +void BlurParams::setFilterNumTaps(int count) { + assert(count <= BLUR_MAX_NUM_TAPS); + auto filterInfo = _parametersBuffer.get().filterInfo; + if (count != (int)filterInfo.y) { + _parametersBuffer.edit().filterInfo.y = count; + } +} + +void BlurParams::setFilterTap(int index, float offset, float value) { + auto filterTaps = _parametersBuffer.edit().filterTaps; + assert(index < BLUR_MAX_NUM_TAPS); + filterTaps[index].x = offset; + filterTaps[index].y = value; +} + +void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma, bool normalize) { + auto& params = _parametersBuffer.edit(); + const int numTaps = 2 * numHalfTaps + 1; + assert(numTaps <= BLUR_MAX_NUM_TAPS); + assert(sigma > 0.0f); + const float inverseTwoSigmaSquared = float(0.5 / (sigma*sigma)); + float totalWeight = 1.0f; + float weight; + float offset; + int i; + + params.filterInfo.y = numTaps; + params.filterTaps[0].x = 0.0f; + params.filterTaps[0].y = 1.0f; + + for (i = 0; i < numHalfTaps; i++) { + offset = i + 1; + weight = (float)exp(-offset*offset * inverseTwoSigmaSquared); + params.filterTaps[i + 1].x = offset; + params.filterTaps[i + 1].y = weight; + params.filterTaps[i + 1 + numHalfTaps].x = -offset; + params.filterTaps[i + 1 + numHalfTaps].y = weight; + totalWeight += 2 * weight; + } + + float normalizer; + if (normalize) { + normalizer = float(1.0 / totalWeight); + } else { + normalizer = float(1.0 / (sqrt(2 * M_PI)*sigma)); + } + + for (i = 0; i < numTaps; i++) { + params.filterTaps[i].y *= normalizer; } } diff --git a/libraries/render/src/render/BlurTask.h b/libraries/render/src/render/BlurTask.h index f023aabfe7..011da6ab68 100644 --- a/libraries/render/src/render/BlurTask.h +++ b/libraries/render/src/render/BlurTask.h @@ -14,6 +14,8 @@ #include "Engine.h" +#include "BlurTask_shared.slh" + namespace render { @@ -25,6 +27,10 @@ public: void setTexcoordTransform(const glm::vec4 texcoordTransformViewport); void setFilterRadiusScale(float scale); + void setFilterNumTaps(int count); + // Tap 0 is considered the center of the kernel + void setFilterTap(int index, float offset, float value); + void setGaussianFilterTaps(int numHalfTaps, float sigma = 1.47f, bool normalize = true); void setDepthPerspective(float oneOverTan2FOV); void setDepthThreshold(float threshold); @@ -40,7 +46,7 @@ public: // Viewport to Texcoord info, if the region of the blur (viewport) is smaller than the full frame glm::vec4 texcoordTransform{ 0.0f, 0.0f, 1.0f, 1.0f }; - // Filter info (radius scale + // Filter info (radius scale, number of taps, mix) glm::vec4 filterInfo{ 1.0f, 0.0f, 0.0f, 0.0f }; // Depth info (radius scale @@ -52,6 +58,9 @@ public: // LinearDepth info is { f } glm::vec4 linearDepthInfo{ 0.0f }; + // Taps (offset, weight) + glm::vec2 filterTaps[BLUR_MAX_NUM_TAPS]; + Params() {} }; gpu::BufferView _parametersBuffer; diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index de2614eb51..b871b59bed 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -9,17 +9,7 @@ <@func declareBlurUniforms()@> -#define NUM_TAPS 7 -#define NUM_TAPS_OFFSET 3.0f - -float uniformFilterWidth = 0.05f; - -const float gaussianDistributionCurve[NUM_TAPS] = float[]( - 0.383f, 0.006f, 0.061f, 0.242f, 0.242f, 0.061f, 0.006f -); -const float gaussianDistributionOffset[NUM_TAPS] = float[]( - 0.0f, -3.0f, -2.0f, -1.0f, 1.0f, 2.0f, 3.0f -); +<@include BlurTask_shared.slh@> struct BlurParameters { vec4 resolutionInfo; @@ -28,6 +18,7 @@ struct BlurParameters { vec4 depthInfo; vec4 stereoInfo; vec4 linearDepthInfo; + vec2 taps[BLUR_MAX_NUM_TAPS]; }; uniform blurParamsBuffer { @@ -46,6 +37,25 @@ float getFilterScale() { return parameters.filterInfo.x; } +int getFilterNumTaps() { + return int(parameters.filterInfo.y); +} + +float getFilterMix() { + return parameters.filterInfo.z; +} + +vec2 getFilterTap(int index) { + return parameters.taps[index]; +} + +float getFilterTapOffset(vec2 tap) { + return tap.x; +} + +float getFilterTapWeight(vec2 tap) { + return tap.y; +} float getDepthThreshold() { return parameters.depthInfo.x; @@ -70,17 +80,18 @@ uniform sampler2D sourceMap; vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); - vec4 sampleCenter = texture(sourceMap, texcoord); vec2 finalStep = getFilterScale() * direction * pixelStep; vec4 srcBlurred = vec4(0.0); + int numTaps = getFilterNumTaps(); - for(int i = 0; i < NUM_TAPS; i++) { + for(int i = 0; i < numTaps; i++) { + vec2 tapInfo = getFilterTap(i); // Fetch color and depth for current sample. - vec2 sampleCoord = texcoord + (gaussianDistributionOffset[i] * finalStep); + vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep); vec4 srcSample = texture(sourceMap, sampleCoord); // Accumulate. - srcBlurred += gaussianDistributionCurve[i] * srcSample; + srcBlurred += getFilterTapWeight(tapInfo) * srcSample; } return srcBlurred; @@ -95,15 +106,6 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { uniform sampler2D sourceMap; uniform sampler2D depthMap; -#define NUM_HALF_TAPS 4 - -const float gaussianDistributionCurveHalf[NUM_HALF_TAPS] = float[]( - 0.383f, 0.242f, 0.061f, 0.006f -); -const float gaussianDistributionOffsetHalf[NUM_HALF_TAPS] = float[]( - 0.0f, 1.0f, 2.0f, 3.0f -); - vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); float sampleDepth = texture(depthMap, texcoord).x; @@ -122,13 +124,17 @@ vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep float scale = distanceToProjectionWindow / sampleDepth; vec2 finalStep = filterScale * scale * direction * pixelStep; + int numTaps = getFilterNumTaps(); // Accumulate the center sample - vec4 srcBlurred = gaussianDistributionCurve[0] * sampleCenter; + vec2 tapInfo = getFilterTap(0); + vec4 srcBlurred = getFilterTapWeight(tapInfo) * sampleCenter; + + for(int i = 1; i < numTaps; i++) { + tapInfo = getFilterTap(i); - for(int i = 1; i < NUM_TAPS; i++) { // Fetch color and depth for current sample. - vec2 sampleCoord = texcoord + (gaussianDistributionOffset[i] * finalStep); + vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep); float srcDepth = texture(depthMap, sampleCoord).x; vec4 srcSample = texture(sourceMap, sampleCoord); @@ -137,29 +143,8 @@ vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep srcSample = mix(srcSample, sampleCenter, s); // Accumulate. - srcBlurred += gaussianDistributionCurve[i] * srcSample; + srcBlurred += getFilterTapWeight(tapInfo) * srcSample; } - - /* - for(int i = 1; i < NUM_HALF_TAPS; i++) { - // Fetch color and depth for current sample. - vec2 texcoordOffset = (gaussianDistributionOffsetHalf[i] * finalStep); - - float srcDepthN = texture(depthMap, texcoord - texcoordOffset).x; - float srcDepthP = texture(depthMap, texcoord + texcoordOffset).x; - vec4 srcSampleN = texture(sourceMap, texcoord - texcoordOffset); - vec4 srcSampleP = texture(sourceMap, texcoord + texcoordOffset); - - // If the difference in depth is huge, we lerp color back. - float sN = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepthN - sampleDepth), 0.0, 1.0); - float sP = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepthP - sampleDepth), 0.0, 1.0); - - srcSampleN = mix(srcSampleN, sampleCenter, sN); - srcSampleP = mix(srcSampleP, sampleCenter, sP); - - // Accumulate. - srcBlurred += gaussianDistributionCurveHalf[i] * (srcSampleP + srcSampleN); - }*/ return srcBlurred; } diff --git a/libraries/render/src/render/BlurTask_shared.slh b/libraries/render/src/render/BlurTask_shared.slh new file mode 100644 index 0000000000..94417fa939 --- /dev/null +++ b/libraries/render/src/render/BlurTask_shared.slh @@ -0,0 +1,10 @@ +// Generated on <$_SCRIBE_DATE$> +// +// Created by Olivier Prat on 09/25/17. +// 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 +// + +#define BLUR_MAX_NUM_TAPS 21 From 22b1507597e1aafea88ece8beb5d2d18c6e6f1eb Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 25 Sep 2017 16:41:20 +0200 Subject: [PATCH 006/171] Fixed blur to work correctly on four sides of screen --- .../src/RenderableModelEntityItem.cpp | 4 +- libraries/render-utils/src/BloomEffect.cpp | 10 +++-- libraries/render/src/render/BlurTask.cpp | 16 ++------ libraries/render/src/render/BlurTask.h | 4 +- libraries/render/src/render/BlurTask.slh | 40 +++++++++++++------ .../render/src/render/BlurTask_shared.slh | 2 +- 6 files changed, 44 insertions(+), 32 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 799a84aaee..b88ef5f8fb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -319,7 +319,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { // should never fall in here when collision model not fully loaded // hence we assert that all geometries exist and are loaded - assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); + assert(model && model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); const FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry(); ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); @@ -408,7 +408,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { shapeInfo.setParams(type, dimensions, getCompoundShapeURL()); } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { // should never fall in here when model not fully loaded - assert(_model && _model->isLoaded()); + assert(model && model->isLoaded()); updateModelBounds(); model->updateGeometry(); diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index a0a36a2194..eb02c4fa57 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -17,9 +17,10 @@ void BloomConfig::setMix(float value) { } void BloomConfig::setSize(float value) { - auto blurConfig = getConfig("Blur"); - assert(blurConfig); - blurConfig->setProperty("filterScale", value*10.0f); + auto& blurJob = static_cast(_task)->_jobs.front(); + auto& gaussianBlur = blurJob.edit(); + auto gaussianBlurParams = gaussianBlur.getParameters(); + gaussianBlurParams->setGaussianFilterTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); } Bloom::Bloom() { @@ -27,7 +28,8 @@ Bloom::Bloom() { } void Bloom::configure(const Config& config) { - + auto blurConfig = config.getConfig(); + blurConfig->setProperty("filterScale", 2.5f); } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 2d51fd1271..2e3cf8138f 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -77,7 +77,7 @@ void BlurParams::setFilterTap(int index, float offset, float value) { filterTaps[index].y = value; } -void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma, bool normalize) { +void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma) { auto& params = _parametersBuffer.edit(); const int numTaps = 2 * numHalfTaps + 1; assert(numTaps <= BLUR_MAX_NUM_TAPS); @@ -102,16 +102,8 @@ void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma, bool normal totalWeight += 2 * weight; } - float normalizer; - if (normalize) { - normalizer = float(1.0 / totalWeight); - } else { - normalizer = float(1.0 / (sqrt(2 * M_PI)*sigma)); - } - - for (i = 0; i < numTaps; i++) { - params.filterTaps[i].y *= normalizer; - } + // Tap weights will be normalized in shader because side cases on edges of screen + // won't have the same number of taps as in the center. } void BlurParams::setDepthPerspective(float oneOverTan2FOV) { @@ -158,7 +150,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra // _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); //} auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); - auto blurringTarget = gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); + auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); _blurredFramebuffer->setRenderBuffer(0, blurringTarget); } diff --git a/libraries/render/src/render/BlurTask.h b/libraries/render/src/render/BlurTask.h index 011da6ab68..4df5a09576 100644 --- a/libraries/render/src/render/BlurTask.h +++ b/libraries/render/src/render/BlurTask.h @@ -30,7 +30,7 @@ public: void setFilterNumTaps(int count); // Tap 0 is considered the center of the kernel void setFilterTap(int index, float offset, float value); - void setGaussianFilterTaps(int numHalfTaps, float sigma = 1.47f, bool normalize = true); + void setGaussianFilterTaps(int numHalfTaps, float sigma = 1.47f); void setDepthPerspective(float oneOverTan2FOV); void setDepthThreshold(float threshold); @@ -116,6 +116,8 @@ public: void configure(const Config& config); void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer); + BlurParamsPointer getParameters() const { return _parameters; } + protected: BlurParamsPointer _parameters; diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index b871b59bed..5a41a0b1c6 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -83,17 +83,25 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { vec2 finalStep = getFilterScale() * direction * pixelStep; vec4 srcBlurred = vec4(0.0); + float totalWeight = 0.f; int numTaps = getFilterNumTaps(); for(int i = 0; i < numTaps; i++) { vec2 tapInfo = getFilterTap(i); - // Fetch color and depth for current sample. + // Fetch color for current sample. vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep); - vec4 srcSample = texture(sourceMap, sampleCoord); - // Accumulate. - srcBlurred += getFilterTapWeight(tapInfo) * srcSample; + if (all(greaterThanEqual(sampleCoord, vec2(0,0))) && all(lessThanEqual(sampleCoord, vec2(1.0,1.0)))) { + vec4 srcSample = texture(sourceMap, sampleCoord); + float weight = getFilterTapWeight(tapInfo); + // Accumulate. + srcBlurred += srcSample * weight; + totalWeight += weight; + } } + if (totalWeight>0.0) { + srcBlurred /= totalWeight; + } return srcBlurred; } @@ -128,24 +136,32 @@ vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep // Accumulate the center sample vec2 tapInfo = getFilterTap(0); - vec4 srcBlurred = getFilterTapWeight(tapInfo) * sampleCenter; + float totalWeight = getFilterTapWeight(tapInfo); + vec4 srcBlurred = sampleCenter * totalWeight; for(int i = 1; i < numTaps; i++) { tapInfo = getFilterTap(i); // Fetch color and depth for current sample. vec2 sampleCoord = texcoord + (getFilterTapOffset(tapInfo) * finalStep); - float srcDepth = texture(depthMap, sampleCoord).x; - vec4 srcSample = texture(sourceMap, sampleCoord); + if (all(greaterThanEqual(sampleCoord, vec2(0,0))) && all(lessThanEqual(sampleCoord, vec2(1.0,1.0)))) { + float srcDepth = texture(depthMap, sampleCoord).x; + vec4 srcSample = texture(sourceMap, sampleCoord); + float weight = getFilterTapWeight(tapInfo); - // If the difference in depth is huge, we lerp color back. - float s = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepth - sampleDepth), 0.0, 1.0); - srcSample = mix(srcSample, sampleCenter, s); + // If the difference in depth is huge, we lerp color back. + float s = clamp(depthThreshold * distanceToProjectionWindow * filterScale * abs(srcDepth - sampleDepth), 0.0, 1.0); + srcSample = mix(srcSample, sampleCenter, s); - // Accumulate. - srcBlurred += getFilterTapWeight(tapInfo) * srcSample; + // Accumulate. + srcBlurred += srcSample * weight; + totalWeight += weight; + } } + if (totalWeight>0.0) { + srcBlurred /= totalWeight; + } return srcBlurred; } diff --git a/libraries/render/src/render/BlurTask_shared.slh b/libraries/render/src/render/BlurTask_shared.slh index 94417fa939..84c633d74c 100644 --- a/libraries/render/src/render/BlurTask_shared.slh +++ b/libraries/render/src/render/BlurTask_shared.slh @@ -7,4 +7,4 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#define BLUR_MAX_NUM_TAPS 21 +#define BLUR_MAX_NUM_TAPS 25 From 27b9f3516df5dc2395a4d71b69bfa91b94279f23 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 25 Sep 2017 18:05:30 +0200 Subject: [PATCH 007/171] Added mix parameter to blur and bloom --- libraries/render-utils/src/BloomEffect.cpp | 9 +++++---- libraries/render-utils/src/BloomEffect.h | 8 ++++---- libraries/render/src/render/BlurTask.cpp | 19 ++++++++++++++++--- libraries/render/src/render/BlurTask.h | 10 +++++++--- libraries/render/src/render/BlurTask.slh | 3 ++- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index eb02c4fa57..24cdd5fca3 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -12,15 +12,16 @@ #include -void BloomConfig::setMix(float value) { - +void BloomConfig::setIntensity(float value) { + auto blurConfig = getConfig(); + blurConfig->setProperty("mix", value*0.5f); } void BloomConfig::setSize(float value) { auto& blurJob = static_cast(_task)->_jobs.front(); auto& gaussianBlur = blurJob.edit(); auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setGaussianFilterTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); + gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); } Bloom::Bloom() { @@ -29,7 +30,7 @@ Bloom::Bloom() { void Bloom::configure(const Config& config) { auto blurConfig = config.getConfig(); - blurConfig->setProperty("filterScale", 2.5f); + blurConfig->setProperty("filterScale", 3.0f); } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 278236d2e9..c8588c7a15 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -16,15 +16,15 @@ class BloomConfig : public render::Task::Config { Q_OBJECT - Q_PROPERTY(float mix MEMBER mix WRITE setMix NOTIFY dirty) + Q_PROPERTY(float intensity MEMBER intensity WRITE setIntensity NOTIFY dirty) Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) public: - float mix{ 0.2f }; - float size{ 0.1f }; + float intensity{ 0.2f }; + float size{ 0.4f }; - void setMix(float value); + void setIntensity(float value); void setSize(float value); signals: diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 2e3cf8138f..66f098302d 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -32,7 +32,7 @@ enum BlurShaderMapSlots { BlurParams::BlurParams() { Params params; _parametersBuffer = gpu::BufferView(std::make_shared(sizeof(Params), (const gpu::Byte*) ¶ms)); - setGaussianFilterTaps(3); + setFilterGaussianTaps(3); } void BlurParams::setWidthHeight(int width, int height, bool isStereo) { @@ -77,7 +77,7 @@ void BlurParams::setFilterTap(int index, float offset, float value) { filterTaps[index].y = value; } -void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma) { +void BlurParams::setFilterGaussianTaps(int numHalfTaps, float sigma) { auto& params = _parametersBuffer.edit(); const int numTaps = 2 * numHalfTaps + 1; assert(numTaps <= BLUR_MAX_NUM_TAPS); @@ -106,6 +106,14 @@ void BlurParams::setGaussianFilterTaps(int numHalfTaps, float sigma) { // won't have the same number of taps as in the center. } +void BlurParams::setOutputAlpha(float value) { + value = glm::clamp(value, 0.0f, 1.0f); + auto filterInfo = _parametersBuffer.get().filterInfo; + if (value != filterInfo.z) { + _parametersBuffer.edit().filterInfo.z = value; + } +} + void BlurParams::setDepthPerspective(float oneOverTan2FOV) { auto depthInfo = _parametersBuffer.get().depthInfo; if (oneOverTan2FOV != depthInfo.w) { @@ -238,7 +246,13 @@ gpu::PipelinePointer BlurGaussian::getBlurHPipeline() { } void BlurGaussian::configure(const Config& config) { + auto blurHPipeline = getBlurHPipeline(); + _parameters->setFilterRadiusScale(config.filterScale); + _parameters->setOutputAlpha(config.mix); + + blurHPipeline->getState()->setBlendFunction(config.mix < 1.0f, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); } @@ -248,7 +262,6 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra RenderArgs* args = renderContext->args; - BlurInOutResource::Resources blurringResources; if (!_inOutResources.updateResources(sourceFramebuffer, blurringResources)) { // early exit if no valid blurring resources diff --git a/libraries/render/src/render/BlurTask.h b/libraries/render/src/render/BlurTask.h index 4df5a09576..cbee3e35f1 100644 --- a/libraries/render/src/render/BlurTask.h +++ b/libraries/render/src/render/BlurTask.h @@ -30,7 +30,8 @@ public: void setFilterNumTaps(int count); // Tap 0 is considered the center of the kernel void setFilterTap(int index, float offset, float value); - void setGaussianFilterTaps(int numHalfTaps, float sigma = 1.47f); + void setFilterGaussianTaps(int numHalfTaps, float sigma = 1.47f); + void setOutputAlpha(float value); void setDepthPerspective(float oneOverTan2FOV); void setDepthThreshold(float threshold); @@ -46,7 +47,7 @@ public: // Viewport to Texcoord info, if the region of the blur (viewport) is smaller than the full frame glm::vec4 texcoordTransform{ 0.0f, 0.0f, 1.0f, 1.0f }; - // Filter info (radius scale, number of taps, mix) + // Filter info (radius scale, number of taps, output alpha) glm::vec4 filterInfo{ 1.0f, 0.0f, 0.0f, 0.0f }; // Depth info (radius scale @@ -93,12 +94,15 @@ public: class BlurGaussianConfig : public Job::Config { Q_OBJECT Q_PROPERTY(bool enabled WRITE setEnabled READ isEnabled NOTIFY dirty) // expose enabled flag - Q_PROPERTY(float filterScale MEMBER filterScale NOTIFY dirty) // expose enabled flag + Q_PROPERTY(float filterScale MEMBER filterScale NOTIFY dirty) + Q_PROPERTY(float mix MEMBER mix NOTIFY dirty) public: BlurGaussianConfig() : Job::Config(true) {} float filterScale{ 0.2f }; + float mix{ 1.0f }; + signals : void dirty(); diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index 5a41a0b1c6..37f29496bd 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -41,7 +41,7 @@ int getFilterNumTaps() { return int(parameters.filterInfo.y); } -float getFilterMix() { +float getOutputAlpha() { return parameters.filterInfo.z; } @@ -102,6 +102,7 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { if (totalWeight>0.0) { srcBlurred /= totalWeight; } + srcBlurred.a = getOutputAlpha(); return srcBlurred; } From 27a0fb62d31c8f0e68f1fb48309926c386abb03d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 9 Oct 2017 09:35:38 +0200 Subject: [PATCH 008/171] Multiple gaussians as Unreal. First draft --- libraries/render-utils/src/BloomEffect.cpp | 145 +++++++++++++++++- libraries/render-utils/src/BloomEffect.h | 76 ++++++++- libraries/render-utils/src/BloomThreshold.slf | 40 +++++ .../render-utils/src/RenderDeferredTask.cpp | 2 +- scripts/developer/utilities/render/bloom.qml | 66 ++++++++ .../developer/utilities/render/debugBloom.js | 20 +++ 6 files changed, 332 insertions(+), 17 deletions(-) create mode 100644 libraries/render-utils/src/BloomThreshold.slf create mode 100644 scripts/developer/utilities/render/bloom.qml create mode 100644 scripts/developer/utilities/render/debugBloom.js diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 24cdd5fca3..f083bf7e6b 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -10,18 +10,145 @@ // #include "BloomEffect.h" +#include "gpu/Context.h" +#include "gpu/StandardShaderLib.h" + #include +#include "BloomThreshold_frag.h" + +ThresholdAndDownsampleJob::ThresholdAndDownsampleJob() { + +} + +void ThresholdAndDownsampleJob::configure(const Config& config) { + _threshold = config.threshold; +} + +void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + + RenderArgs* args = renderContext->args; + + const auto frameTransform = inputs.get0(); + const auto inputFrameBuffer = inputs.get1(); + + assert(inputFrameBuffer->hasColor()); + + auto inputColor = inputFrameBuffer->getRenderBuffer(0); + auto sourceViewport = args->_viewport; + auto fullSize = glm::ivec2(inputColor->getDimensions()); + auto halfSize = fullSize / 2; + auto halfViewport = args->_viewport >> 1; + + if (!_downsampledBuffer || _downsampledBuffer->getSize().x != halfSize.x || _downsampledBuffer->getSize().y != halfSize.y) { + auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputColor->getTexelFormat(), halfSize.x, halfSize.y, + gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR))); + + _downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomBlur0")); + _downsampledBuffer->setRenderBuffer(0, colorTexture); + } + + static const int COLOR_MAP_SLOT = 0; + static const int THRESHOLD_SLOT = 1; + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("colorMap", COLOR_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding("threshold", THRESHOLD_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + _pipeline = gpu::Pipeline::create(program, state); + } + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + +/* batch.setViewportTransform(halfViewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(inputFrameBuffer->getSize(), args->_viewport)); + batch.setPipeline(_pipeline);*/ + + batch.setFramebuffer(_downsampledBuffer); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, gpu::Vec4(1.0f, 0.2f, 0.9f, 1.f)); + /*batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); + batch._glUniform1f(THRESHOLD_SLOT, _threshold); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + batch.setViewportTransform(args->_viewport); + batch.setResourceTexture(COLOR_MAP_SLOT, nullptr); + batch.setFramebuffer(nullptr);*/ + }); + + outputs = _downsampledBuffer; +} + +DebugBloom::DebugBloom() { +} + +DebugBloom::~DebugBloom() { +} + +void DebugBloom::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + const auto frameBuffer = inputs.get0(); + const auto level0FB = inputs.get1(); + const gpu::TexturePointer levelTextures[1] = { + level0FB->getRenderBuffer(0) + }; + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); + auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false)); + _pipeline = gpu::Pipeline::create(program, state); + } + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + //batch.setFramebuffer(frameBuffer); + batch.setViewportTransform(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat, false); + batch.setPipeline(_pipeline); + batch.setResourceTexture(0, levelTextures[0]); + + batch.draw(gpu::TRIANGLE_STRIP, 4); + + batch.setResourceTexture(0, nullptr); + }); +} + void BloomConfig::setIntensity(float value) { - auto blurConfig = getConfig(); - blurConfig->setProperty("mix", value*0.5f); + /* auto blurConfig = getConfig(); + blurConfig->setProperty("mix", value*0.5f);*/ } void BloomConfig::setSize(float value) { - auto& blurJob = static_cast(_task)->_jobs.front(); + /* auto& blurJob = static_cast(_task)->_jobs.front(); auto& gaussianBlur = blurJob.edit(); auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); + gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f);*/ } Bloom::Bloom() { @@ -29,11 +156,13 @@ Bloom::Bloom() { } void Bloom::configure(const Config& config) { - auto blurConfig = config.getConfig(); - blurConfig->setProperty("filterScale", 3.0f); +/* auto blurConfig = config.getConfig(); + blurConfig->setProperty("filterScale", 3.0f);*/ } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto& blurInput = inputs; - task.addJob("Blur", blurInput); + const auto halfSizeBuffer = task.addJob("BloomThreshold", inputs); + + const auto debugInput = DebugBloom::Inputs(inputs.get().get1(), halfSizeBuffer).asVarying(); + task.addJob("DebugBloom", debugInput); } diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index c8588c7a15..ec14a6ad9f 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -14,27 +14,87 @@ #include +#include "DeferredFrameTransform.h" + class BloomConfig : public render::Task::Config { - Q_OBJECT - Q_PROPERTY(float intensity MEMBER intensity WRITE setIntensity NOTIFY dirty) - Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) + Q_OBJECT + Q_PROPERTY(float intensity MEMBER intensity WRITE setIntensity NOTIFY dirty) + Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) public: - float intensity{ 0.2f }; - float size{ 0.4f }; + BloomConfig() : render::Task::Config(true) {} + + float intensity{ 0.2f }; + float size{ 0.4f }; void setIntensity(float value); void setSize(float value); signals: - void dirty(); + void dirty(); +}; + +class ThresholdConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) + +public: + + float threshold{ 0.25f }; + +signals: + void dirty(); +}; + +class ThresholdAndDownsampleJob { +public: + using Inputs = render::VaryingSet2; + using Outputs = gpu::FramebufferPointer; + using Config = ThresholdConfig; + using JobModel = render::Job::ModelIO; + + ThresholdAndDownsampleJob(); + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + +private: + + gpu::FramebufferPointer _downsampledBuffer; + gpu::PipelinePointer _pipeline; + float _threshold; +}; + +class DebugBloomConfig : public render::Job::Config { + Q_OBJECT + +public: + + DebugBloomConfig() : render::Job::Config(true) {} + +}; + +class DebugBloom { +public: + using Inputs = render::VaryingSet2; + using Config = DebugBloomConfig; + using JobModel = render::Job::ModelI; + + DebugBloom(); + ~DebugBloom(); + + void configure(const Config& config) {} + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + +private: + gpu::PipelinePointer _pipeline; }; class Bloom { public: - using Inputs = gpu::FramebufferPointer; - using Config = BloomConfig; + using Inputs = render::VaryingSet2; + using Config = BloomConfig; using JobModel = render::Task::ModelI; Bloom(); diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf new file mode 100644 index 0000000000..7c87ed9fcd --- /dev/null +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -0,0 +1,40 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// BloomThreshold.slf +// Perform a soft threshold on an input texture and downsample to half size in one go. +// +// Created by Olivier Prat on 09/26/2017 +// 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 +// + +uniform sampler2D colorMap; +uniform float threshold; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + // Gather 2 by 2 quads from texture, threshold and downsample + vec4 reds = textureGather(colorMap, varTexCoord0, 0); + vec4 greens = textureGather(colorMap, varTexCoord0, 1); + vec4 blues = textureGather(colorMap, varTexCoord0, 2); + + float hardness = 8; + vec4 rMask = clamp((reds-threshold) * hardness, 0, 1); + vec4 gMask = clamp((greens-threshold) * hardness, 0, 1); + vec4 bMask = clamp((blues-threshold) * hardness, 0, 1); + + reds = smoothstep(vec4(0,0,0,0), reds, rMask); + greens = smoothstep(vec4(0,0,0,0), greens, gMask); + blues = smoothstep(vec4(0,0,0,0), blues, bMask); + + vec3 texel0 = vec3(reds.x, greens.x, blues.x); + vec3 texel1 = vec3(reds.y, greens.y, blues.y); + vec3 texel2 = vec3(reds.z, greens.z, blues.z); + vec3 texel3 = vec3(reds.w, greens.w, blues.w); + + outFragColor = vec4((texel0+texel1+texel2+texel3)/4.0, 1.0); +} diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 682d5db435..c3e0fec3b1 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -170,7 +170,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneAndPostRangeTimer = task.addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); // Add bloom - const auto bloomInputs = lightingFramebuffer; + const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying(); task.addJob("Bloom", bloomInputs); // Lighting Buffer ready for tone mapping diff --git a/scripts/developer/utilities/render/bloom.qml b/scripts/developer/utilities/render/bloom.qml new file mode 100644 index 0000000000..7deeffc218 --- /dev/null +++ b/scripts/developer/utilities/render/bloom.qml @@ -0,0 +1,66 @@ +// +// bloom.qml +// developer/utilities/render +// +// Olivier Prat, created on 09/25/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "configSlider" + +Item { + id: root + property var config: Render.getConfig("RenderMainView.Bloom") + property var configThreshold: Render.getConfig("RenderMainView.BloomThreshold") + property var configDebug: Render.getConfig("RenderMainView.DebugBloom") + + Column { + spacing: 8 + + CheckBox { + text: "Enable" + checked: root.config["enabled"] + onCheckedChanged: { + root.config["enabled"] = checked; + } + } + CheckBox { + text: "Debug" + checked: root.configDebug["enabled"] + onCheckedChanged: { + root.configDebug["enabled"] = checked; + } + } + ConfigSlider { + label: "Intensity" + integral: false + config: root.config + property: "intensity" + max: 1.0 + min: 0.0 + width: 280 + } + ConfigSlider { + label: "Size" + integral: false + config: root.config + property: "size" + max: 1.0 + min: 0.0 + width: 280 + } + ConfigSlider { + label: "Threshold" + integral: false + config: root.configThreshold + property: "threshold" + max: 1.0 + min: 0.0 + width: 280 + } + } +} diff --git a/scripts/developer/utilities/render/debugBloom.js b/scripts/developer/utilities/render/debugBloom.js new file mode 100644 index 0000000000..2328d524cf --- /dev/null +++ b/scripts/developer/utilities/render/debugBloom.js @@ -0,0 +1,20 @@ +// +// debugBloom.js +// developer/utilities/render +// +// Olivier Prat, created on 09/25/2017. +// 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 +// + +// Set up the qml ui +var qml = Script.resolvePath('bloom.qml'); +var window = new OverlayWindow({ + title: 'Bloom', + source: qml, + width: 285, + height: 170, +}); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file From 50ab73009a89a00f23459760bca4f24dc2d7d83f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 9 Oct 2017 11:09:51 +0200 Subject: [PATCH 009/171] Working threshold mask and debug on Bloom --- libraries/render-utils/src/BloomEffect.cpp | 31 +++++++++---------- libraries/render-utils/src/BloomThreshold.slf | 26 ++++++++++------ .../render-utils/src/RenderDeferredTask.cpp | 2 +- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index f083bf7e6b..1c62d031b7 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -70,21 +70,20 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); -/* batch.setViewportTransform(halfViewport); + batch.setViewportTransform(halfViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(inputFrameBuffer->getSize(), args->_viewport)); - batch.setPipeline(_pipeline);*/ + batch.setPipeline(_pipeline); batch.setFramebuffer(_downsampledBuffer); - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, gpu::Vec4(1.0f, 0.2f, 0.9f, 1.f)); - /*batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); + batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); batch._glUniform1f(THRESHOLD_SLOT, _threshold); batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setViewportTransform(args->_viewport); batch.setResourceTexture(COLOR_MAP_SLOT, nullptr); - batch.setFramebuffer(nullptr);*/ + batch.setFramebuffer(nullptr); }); outputs = _downsampledBuffer; @@ -102,13 +101,14 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In RenderArgs* args = renderContext->args; const auto frameBuffer = inputs.get0(); + const auto framebufferSize = frameBuffer->getSize(); const auto level0FB = inputs.get1(); const gpu::TexturePointer levelTextures[1] = { level0FB->getRenderBuffer(0) }; if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); @@ -123,19 +123,16 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - //batch.setFramebuffer(frameBuffer); - batch.setViewportTransform(args->_viewport); + batch.setFramebuffer(frameBuffer); + + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(glm::ivec2(framebufferSize.x, framebufferSize.y), args->_viewport)); - glm::mat4 projMat; - Transform viewMat; - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat, false); batch.setPipeline(_pipeline); batch.setResourceTexture(0, levelTextures[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); - - batch.setResourceTexture(0, nullptr); }); } @@ -162,7 +159,9 @@ void Bloom::configure(const Config& config) { void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { const auto halfSizeBuffer = task.addJob("BloomThreshold", inputs); + const auto& input = inputs.get(); + const auto& frameBuffer = input[1]; - const auto debugInput = DebugBloom::Inputs(inputs.get().get1(), halfSizeBuffer).asVarying(); + const auto debugInput = DebugBloom::Inputs(frameBuffer, halfSizeBuffer).asVarying(); task.addJob("DebugBloom", debugInput); } diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index 7c87ed9fcd..dbc16d892d 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -22,19 +22,25 @@ void main(void) { vec4 greens = textureGather(colorMap, varTexCoord0, 1); vec4 blues = textureGather(colorMap, varTexCoord0, 2); - float hardness = 8; - vec4 rMask = clamp((reds-threshold) * hardness, 0, 1); - vec4 gMask = clamp((greens-threshold) * hardness, 0, 1); - vec4 bMask = clamp((blues-threshold) * hardness, 0, 1); - - reds = smoothstep(vec4(0,0,0,0), reds, rMask); - greens = smoothstep(vec4(0,0,0,0), greens, gMask); - blues = smoothstep(vec4(0,0,0,0), blues, bMask); - vec3 texel0 = vec3(reds.x, greens.x, blues.x); vec3 texel1 = vec3(reds.y, greens.y, blues.y); vec3 texel2 = vec3(reds.z, greens.z, blues.z); vec3 texel3 = vec3(reds.w, greens.w, blues.w); - outFragColor = vec4((texel0+texel1+texel2+texel3)/4.0, 1.0); + vec4 luminances; + vec3 luminanceWeights = vec3(0.3,0.5,0.2); + + luminances.x = dot(texel0, luminanceWeights); + luminances.y = dot(texel1, luminanceWeights); + luminances.z = dot(texel2, luminanceWeights); + luminances.w = dot(texel0, luminanceWeights); + + float hardness = 8; + vec4 mask = clamp((luminances-threshold) * hardness, 0, 1); + vec3 color; + + color.x = dot(mask, reds); + color.y = dot(mask, greens); + color.z = dot(mask, blues); + outFragColor = vec4(color/4.0, 1.0); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index a27b8f0ab5..f2afae7531 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -161,7 +161,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).asVarying(); task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); - // LIght Cluster Grid Debuging job + // Light Cluster Grid Debuging job { const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).asVarying(); task.addJob("DebugLightClusters", debugLightClustersInputs); From 0d3d309bceb56c4f212e27c7727af301b3fefbfb Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 9 Oct 2017 11:49:29 +0200 Subject: [PATCH 010/171] Quarter size debug rendering of bloom --- libraries/render-utils/src/BloomEffect.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 1c62d031b7..6ec20d53c7 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -108,7 +108,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In }; if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); @@ -128,7 +128,10 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(glm::ivec2(framebufferSize.x, framebufferSize.y), args->_viewport)); + + Transform modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); + modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); + batch.setModelTransform(modelTransform); batch.setPipeline(_pipeline); batch.setResourceTexture(0, levelTextures[0]); From cda48cbf67e539b1fed6a7aa677351b2228d1134 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 9 Oct 2017 15:13:32 +0200 Subject: [PATCH 011/171] Three blurs working --- libraries/render-utils/src/BloomEffect.cpp | 55 ++++++++++++++++------ libraries/render-utils/src/BloomEffect.h | 2 +- libraries/render/src/render/BlurTask.cpp | 20 ++++---- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 6ec20d53c7..e292199bef 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -17,6 +17,8 @@ #include "BloomThreshold_frag.h" +#define BLOOM_BLUR_LEVEL_COUNT 3 + ThresholdAndDownsampleJob::ThresholdAndDownsampleJob() { } @@ -103,8 +105,12 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In const auto frameBuffer = inputs.get0(); const auto framebufferSize = frameBuffer->getSize(); const auto level0FB = inputs.get1(); - const gpu::TexturePointer levelTextures[1] = { - level0FB->getRenderBuffer(0) + const auto level1FB = inputs.get2(); + const auto level2FB = inputs.get3(); + const gpu::TexturePointer levelTextures[BLOOM_BLUR_LEVEL_COUNT] = { + level0FB->getRenderBuffer(0), + level1FB->getRenderBuffer(0), + level2FB->getRenderBuffer(0) }; if (!_pipeline) { @@ -128,27 +134,36 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); + batch.setPipeline(_pipeline); Transform modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); batch.setModelTransform(modelTransform); - - batch.setPipeline(_pipeline); batch.setResourceTexture(0, levelTextures[0]); batch.draw(gpu::TRIANGLE_STRIP, 4); + + modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[1]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + modelTransform.postTranslate(glm::vec3(-2.0f, -2.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[2]); + batch.draw(gpu::TRIANGLE_STRIP, 4); }); } void BloomConfig::setIntensity(float value) { - /* auto blurConfig = getConfig(); - blurConfig->setProperty("mix", value*0.5f);*/ } void BloomConfig::setSize(float value) { - /* auto& blurJob = static_cast(_task)->_jobs.front(); - auto& gaussianBlur = blurJob.edit(); - auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f);*/ + for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { + auto& blurJob = static_cast(_task)->_jobs[i+1]; + auto& gaussianBlur = blurJob.edit(); + auto gaussianBlurParams = gaussianBlur.getParameters(); + gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); + } } Bloom::Bloom() { @@ -156,15 +171,25 @@ Bloom::Bloom() { } void Bloom::configure(const Config& config) { -/* auto blurConfig = config.getConfig(); - blurConfig->setProperty("filterScale", 3.0f);*/ + std::string blurName{ "BloomBlurN" }; + + for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { + blurName.back() = '0' + i; + auto blurConfig = config.getConfig(blurName); + blurConfig->setProperty("filterScale", 3.0f); + } } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto halfSizeBuffer = task.addJob("BloomThreshold", inputs); + const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); + + // Level 0 blur + const auto blurFB0 = task.addJob("BloomBlur0", bloomInputBuffer); + const auto blurFB1 = task.addJob("BloomBlur1", blurFB0, true); + const auto blurFB2 = task.addJob("BloomBlur2", blurFB1, true); + const auto& input = inputs.get(); const auto& frameBuffer = input[1]; - - const auto debugInput = DebugBloom::Inputs(frameBuffer, halfSizeBuffer).asVarying(); + const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2).asVarying(); task.addJob("DebugBloom", debugInput); } diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index ec14a6ad9f..bd74939ea4 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -77,7 +77,7 @@ public: class DebugBloom { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet4; using Config = DebugBloomConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 66f098302d..b42bae3950 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -181,7 +181,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra _outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); }*/ auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); - auto blurringTarget = gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); + auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); _outputFramebuffer->setRenderBuffer(0, blurringTarget); } @@ -246,13 +246,16 @@ gpu::PipelinePointer BlurGaussian::getBlurHPipeline() { } void BlurGaussian::configure(const Config& config) { - auto blurHPipeline = getBlurHPipeline(); + auto state = getBlurHPipeline()->getState(); _parameters->setFilterRadiusScale(config.filterScale); _parameters->setOutputAlpha(config.mix); - - blurHPipeline->getState()->setBlendFunction(config.mix < 1.0f, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + if (config.mix < 1.0f) { + state->setBlendFunction(config.mix < 1.0f, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + } else { + state->setBlendFunction(false); + } } @@ -271,14 +274,15 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra auto blurVPipeline = getBlurVPipeline(); auto blurHPipeline = getBlurHPipeline(); + glm::ivec4 viewport = { 0, 0, blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight() }; - _parameters->setWidthHeight(args->_viewport.z, args->_viewport.w, args->isStereo()); + _parameters->setWidthHeight(viewport.z, viewport.w, args->isStereo()); glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions()); - _parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, args->_viewport)); + _parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, viewport)); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); + batch.setViewportTransform(viewport); batch.setUniformBuffer(BlurTask_ParamsSlot, _parameters->_parametersBuffer); From 02612653306c4dcb459aa5c40bbe770c1ce7cf4a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 9 Oct 2017 19:17:51 +0200 Subject: [PATCH 012/171] Working bloom but still visually unstable with geometry aliasing --- libraries/render-utils/src/BloomApply.slf | 27 +++++ libraries/render-utils/src/BloomEffect.cpp | 109 ++++++++++++++++-- libraries/render-utils/src/BloomEffect.h | 40 ++++++- libraries/render-utils/src/BloomThreshold.slf | 5 +- .../render-utils/src/DeferredFramebuffer.cpp | 4 +- libraries/render/src/render/BlurTask.cpp | 10 +- .../render/src/render/BlurTask_shared.slh | 2 +- libraries/render/src/render/ResampleTask.cpp | 88 ++++++++++++++ libraries/render/src/render/ResampleTask.h | 40 +++++++ libraries/render/src/task/Task.h | 20 ++++ scripts/developer/utilities/render/bloom.qml | 4 +- 11 files changed, 320 insertions(+), 29 deletions(-) create mode 100644 libraries/render-utils/src/BloomApply.slf create mode 100644 libraries/render/src/render/ResampleTask.cpp create mode 100644 libraries/render/src/render/ResampleTask.h diff --git a/libraries/render-utils/src/BloomApply.slf b/libraries/render-utils/src/BloomApply.slf new file mode 100644 index 0000000000..17f13b1187 --- /dev/null +++ b/libraries/render-utils/src/BloomApply.slf @@ -0,0 +1,27 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// BloomApply.slf +// Mix the three gaussian blur textures. +// +// Created by Olivier Prat on 10/09/2017 +// 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 +// + +uniform sampler2D blurMap0; +uniform sampler2D blurMap1; +uniform sampler2D blurMap2; +uniform float intensity; + +in vec2 varTexCoord0; +out vec4 outFragColor; + +void main(void) { + vec4 blur0 = texture(blurMap0, varTexCoord0); + vec4 blur1 = texture(blurMap1, varTexCoord0); + vec4 blur2 = texture(blurMap2, varTexCoord0); + + outFragColor = vec4((blur0.rgb+blur1.rgb+blur2.rgb)/3.0, intensity); +} diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index e292199bef..f289f59faa 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -14,8 +14,10 @@ #include "gpu/StandardShaderLib.h" #include +#include #include "BloomThreshold_frag.h" +#include "BloomApply_frag.h" #define BLOOM_BLUR_LEVEL_COUNT 3 @@ -46,9 +48,9 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo if (!_downsampledBuffer || _downsampledBuffer->getSize().x != halfSize.x || _downsampledBuffer->getSize().y != halfSize.y) { auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputColor->getTexelFormat(), halfSize.x, halfSize.y, - gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR))); + gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomBlur0")); + _downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); _downsampledBuffer->setRenderBuffer(0, colorTexture); } @@ -91,6 +93,67 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo outputs = _downsampledBuffer; } +BloomApply::BloomApply() { + +} + +void BloomApply::configure(const Config& config) { + _intensity = config.intensity; +} + +void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + static auto BLUR0_SLOT = 0; + static auto BLUR1_SLOT = 1; + static auto BLUR2_SLOT = 2; + static auto INTENSITY_SLOT = 3; + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto ps = gpu::Shader::createPixel(std::string(BloomApply_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("blurMap0", BLUR0_SLOT)); + slotBindings.insert(gpu::Shader::Binding("blurMap1", BLUR1_SLOT)); + slotBindings.insert(gpu::Shader::Binding("blurMap2", BLUR2_SLOT)); + slotBindings.insert(gpu::Shader::Binding("intensity", INTENSITY_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _pipeline = gpu::Pipeline::create(program, state); + } + + const auto frameBuffer = inputs.get0(); + const auto framebufferSize = frameBuffer->getSize(); + const auto blur0FB = inputs.get1(); + const auto blur1FB = inputs.get2(); + const auto blur2FB = inputs.get3(); + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setFramebuffer(frameBuffer); + + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setPipeline(_pipeline); + + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); + batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0)); + batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0)); + batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0)); + batch._glUniform1f(INTENSITY_SLOT, _intensity); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); +} + DebugBloom::DebugBloom() { } @@ -155,14 +218,34 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In } void BloomConfig::setIntensity(float value) { + auto task = static_cast(_task); + auto blurJobIt = task->editJob("BloomApply"); + assert(blurJobIt != task->_jobs.end()); + blurJobIt->getConfiguration()->setProperty("intensity", value); +} + +float BloomConfig::getIntensity() const { + auto task = static_cast(_task); + auto blurJobIt = task->getJob("BloomApply"); + assert(blurJobIt != task->_jobs.end()); + return blurJobIt->getConfiguration()->property("intensity").toFloat(); } void BloomConfig::setSize(float value) { + std::string blurName{ "BloomBlurN" }; + auto sigma = value*3.0f; + for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { - auto& blurJob = static_cast(_task)->_jobs[i+1]; - auto& gaussianBlur = blurJob.edit(); + blurName.back() = '0' + i; + auto task = static_cast(_task); + auto blurJobIt = task->editJob(blurName); + assert(blurJobIt != task->_jobs.end()); + auto& gaussianBlur = blurJobIt->edit(); auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, value*7.0f); + gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, sigma); + // Gaussian blur increases at each level to have a slower rolloff on the edge + // of the response + sigma *= 1.5f; } } @@ -176,20 +259,24 @@ void Bloom::configure(const Config& config) { for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { blurName.back() = '0' + i; auto blurConfig = config.getConfig(blurName); - blurConfig->setProperty("filterScale", 3.0f); + blurConfig->setProperty("filterScale", 1.0f); } } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); - // Level 0 blur + // Multi-scale blur const auto blurFB0 = task.addJob("BloomBlur0", bloomInputBuffer); - const auto blurFB1 = task.addJob("BloomBlur1", blurFB0, true); - const auto blurFB2 = task.addJob("BloomBlur2", blurFB1, true); + const auto halfBlurFB0 = task.addJob("BloomHalfBlur0", blurFB0); + const auto blurFB1 = task.addJob("BloomBlur1", halfBlurFB0, true); + const auto halfBlurFB1 = task.addJob("BloomHalfBlur1", blurFB1); + const auto blurFB2 = task.addJob("BloomBlur2", halfBlurFB1, true); const auto& input = inputs.get(); const auto& frameBuffer = input[1]; - const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2).asVarying(); - task.addJob("DebugBloom", debugInput); + + const auto applyInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2).asVarying(); + task.addJob("BloomApply", applyInput); + task.addJob("DebugBloom", applyInput); } diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index bd74939ea4..7c99555bd3 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -18,17 +18,17 @@ class BloomConfig : public render::Task::Config { Q_OBJECT - Q_PROPERTY(float intensity MEMBER intensity WRITE setIntensity NOTIFY dirty) + Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty) Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty) public: BloomConfig() : render::Task::Config(true) {} - float intensity{ 0.2f }; - float size{ 0.4f }; + float size{ 0.45f }; void setIntensity(float value); + float getIntensity() const; void setSize(float value); signals: @@ -41,7 +41,7 @@ class ThresholdConfig : public render::Job::Config { public: - float threshold{ 0.25f }; + float threshold{ 1.25f }; signals: void dirty(); @@ -66,12 +66,42 @@ private: float _threshold; }; + +class BloomApplyConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) + +public: + + float intensity{ 0.5f }; + +signals: + void dirty(); +}; + +class BloomApply { +public: + using Inputs = render::VaryingSet4; + using Config = BloomApplyConfig; + using JobModel = render::Job::ModelI; + + BloomApply(); + + void configure(const Config& config); + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + +private: + + gpu::PipelinePointer _pipeline; + float _intensity{ 1.0f }; +}; + class DebugBloomConfig : public render::Job::Config { Q_OBJECT public: - DebugBloomConfig() : render::Job::Config(true) {} + DebugBloomConfig() : render::Job::Config(false) {} }; diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index dbc16d892d..d14da4889d 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -28,15 +28,14 @@ void main(void) { vec3 texel3 = vec3(reds.w, greens.w, blues.w); vec4 luminances; - vec3 luminanceWeights = vec3(0.3,0.5,0.2); + vec3 luminanceWeights = vec3(0.333,0.333,0.333); luminances.x = dot(texel0, luminanceWeights); luminances.y = dot(texel1, luminanceWeights); luminances.z = dot(texel2, luminanceWeights); luminances.w = dot(texel0, luminanceWeights); - float hardness = 8; - vec4 mask = clamp((luminances-threshold) * hardness, 0, 1); + vec4 mask = clamp(luminances-threshold, 0, 1); vec3 color; color.x = dot(mask, reds); diff --git a/libraries/render-utils/src/DeferredFramebuffer.cpp b/libraries/render-utils/src/DeferredFramebuffer.cpp index 64ea8f0342..2df89b8808 100644 --- a/libraries/render-utils/src/DeferredFramebuffer.cpp +++ b/libraries/render-utils/src/DeferredFramebuffer.cpp @@ -73,9 +73,9 @@ void DeferredFramebuffer::allocate() { _deferredFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); + auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); - _lightingTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, defaultSampler); + _lightingTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, smoothSampler); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting")); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index b42bae3950..a200e0c8ec 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -48,10 +48,10 @@ void BlurParams::setWidthHeight(int width, int height, bool isStereo) { } } -void BlurParams::setTexcoordTransform(const glm::vec4 texcoordTransformViewport) { - auto texcoordTransform = _parametersBuffer.get().texcoordTransform; - if (texcoordTransformViewport != texcoordTransform) { - _parametersBuffer.edit().texcoordTransform = texcoordTransform; +void BlurParams::setTexcoordTransform(glm::vec4 texcoordTransformViewport) { + auto& params = _parametersBuffer.get(); + if (texcoordTransformViewport != params.texcoordTransform) { + _parametersBuffer.edit().texcoordTransform = texcoordTransformViewport; } } @@ -274,7 +274,7 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra auto blurVPipeline = getBlurVPipeline(); auto blurHPipeline = getBlurHPipeline(); - glm::ivec4 viewport = { 0, 0, blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight() }; + glm::ivec4 viewport { 0, 0, blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight() }; _parameters->setWidthHeight(viewport.z, viewport.w, args->isStereo()); glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions()); diff --git a/libraries/render/src/render/BlurTask_shared.slh b/libraries/render/src/render/BlurTask_shared.slh index 84c633d74c..beca32c1be 100644 --- a/libraries/render/src/render/BlurTask_shared.slh +++ b/libraries/render/src/render/BlurTask_shared.slh @@ -7,4 +7,4 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#define BLUR_MAX_NUM_TAPS 25 +#define BLUR_MAX_NUM_TAPS 33 diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp new file mode 100644 index 0000000000..5d4b5c18cb --- /dev/null +++ b/libraries/render/src/render/ResampleTask.cpp @@ -0,0 +1,88 @@ +// +// ResampleTask.cpp +// render/src/render +// +// Various to upsample or downsample textures into framebuffers. +// +// Created by Olivier Prat on 10/09/17. +// 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 +// +#include "ResampleTask.h" + +#include "gpu/Context.h" +#include "gpu/StandardShaderLib.h" + +using namespace render; + +HalfDownsample::HalfDownsample() { + +} + +void HalfDownsample::configure(const Config& config) { + +} + +gpu::FramebufferPointer HalfDownsample::getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer) { + auto resampledFramebufferSize = sourceFramebuffer->getSize(); + + resampledFramebufferSize.x /= 2U; + resampledFramebufferSize.y /= 2U; + + if (!_destinationFrameBuffer || resampledFramebufferSize != _destinationFrameBuffer->getSize()) { + _destinationFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("HalfOutput")); + + auto sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); + auto target = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), resampledFramebufferSize.x, resampledFramebufferSize.y, gpu::Texture::SINGLE_MIP, sampler); + _destinationFrameBuffer->setRenderBuffer(0, target); + } + return _destinationFrameBuffer; +} + +void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer); + + static auto TEXCOORD_RECT_SLOT = 1; + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS(); + auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false)); + _pipeline = gpu::Pipeline::create(program, state); + } + + const auto sourceSize = sourceFramebuffer->getSize(); + const auto bufferSize = resampledFrameBuffer->getSize(); + glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setFramebuffer(resampledFrameBuffer); + + batch.setViewportTransform(viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setPipeline(_pipeline); + + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); + batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); + // Add half a texel of offset to be sure to sample in the middle of 4 neighbouring texture pixels + // to perform box filtering. + batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f / sourceSize.x, 0.5f / sourceSize.y, 1.f, 1.f); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); +} diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h new file mode 100644 index 0000000000..70cb9a54bb --- /dev/null +++ b/libraries/render/src/render/ResampleTask.h @@ -0,0 +1,40 @@ +// +// ResampleTask.h +// render/src/render +// +// Various to upsample or downsample textures into framebuffers. +// +// Created by Olivier Prat on 10/09/17. +// 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 +// + +#ifndef hifi_render_ResampleTask_h +#define hifi_render_ResampleTask_h + +#include "Engine.h" + +namespace render { + + class HalfDownsample { + public: + using Config = JobConfig; + using JobModel = Job::ModelIO; + + HalfDownsample(); + + void configure(const Config& config); + void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& resampledFrameBuffer); + + protected: + + gpu::PipelinePointer _pipeline; + gpu::FramebufferPointer _destinationFrameBuffer; + + gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); + }; +} + +#endif // hifi_render_ResampleTask_h diff --git a/libraries/render/src/task/Task.h b/libraries/render/src/task/Task.h index e99b33305c..0f2265b396 100644 --- a/libraries/render/src/task/Task.h +++ b/libraries/render/src/task/Task.h @@ -171,6 +171,8 @@ public: _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); } + const std::string& getName() const { return _name; } + protected: ConceptPointer _concept; std::string _name = ""; @@ -206,6 +208,24 @@ public: const Varying getInput() const override { return _input; } const Varying getOutput() const override { return _output; } + typename Jobs::iterator editJob(std::string name) { + typename Jobs::iterator jobIt; + for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { + if (jobIt->getName() == name) { + return jobIt; + } + } + return jobIt; + } + typename Jobs::const_iterator getJob(std::string name) const { + typename Jobs::const_iterator jobIt; + for (jobIt = _jobs.begin(); jobIt != _jobs.end(); ++jobIt) { + if (jobIt->getName() == name) { + return jobIt; + } + } + return jobIt; + } TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {} diff --git a/scripts/developer/utilities/render/bloom.qml b/scripts/developer/utilities/render/bloom.qml index 7deeffc218..d2a928861c 100644 --- a/scripts/developer/utilities/render/bloom.qml +++ b/scripts/developer/utilities/render/bloom.qml @@ -40,7 +40,7 @@ Item { integral: false config: root.config property: "intensity" - max: 1.0 + max: 5.0 min: 0.0 width: 280 } @@ -58,7 +58,7 @@ Item { integral: false config: root.configThreshold property: "threshold" - max: 1.0 + max: 2.0 min: 0.0 width: 280 } From 76305c5285f6d33e100460677d9549652e8f9c2f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 10 Oct 2017 14:49:04 +0200 Subject: [PATCH 013/171] Better debugging options for bloom --- libraries/render-utils/src/BloomEffect.cpp | 53 +++++++++++----- libraries/render-utils/src/BloomEffect.h | 18 +++++- scripts/developer/utilities/render/bloom.qml | 63 ++++++++++++++++++-- 3 files changed, 112 insertions(+), 22 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index f289f59faa..c6c30e7ff6 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -157,7 +157,9 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In DebugBloom::DebugBloom() { } -DebugBloom::~DebugBloom() { +void DebugBloom::configure(const Config& config) { + _mode = static_cast(config.mode); + assert(_mode < DebugBloomConfig::MODE_COUNT); } void DebugBloom::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { @@ -176,12 +178,15 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In level2FB->getRenderBuffer(0) }; + static auto TEXCOORD_RECT_SLOT = 1; + if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -199,21 +204,39 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In batch.resetViewTransform(); batch.setPipeline(_pipeline); - Transform modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); - modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); - batch.setModelTransform(modelTransform); - batch.setResourceTexture(0, levelTextures[0]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + Transform modelTransform; + if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) { + batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.0f, 0.0f, 1.f, 1.f); - modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f)); - batch.setModelTransform(modelTransform); - batch.setResourceTexture(0, levelTextures[1]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); + modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[0]); + batch.draw(gpu::TRIANGLE_STRIP, 4); - modelTransform.postTranslate(glm::vec3(-2.0f, -2.0f, 0.0f)); - batch.setModelTransform(modelTransform); - batch.setResourceTexture(0, levelTextures[2]); - batch.draw(gpu::TRIANGLE_STRIP, 4); + modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[1]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + modelTransform.postTranslate(glm::vec3(-2.0f, -2.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[2]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } else { + auto viewport = args->_viewport; + auto blurLevel = _mode - DebugBloomConfig::MODE_LEVEL0; + + viewport.z /= 2; + + batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f, 0.0f, 0.5f, 1.f); + + modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport); + modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, levelTextures[blurLevel]); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } }); } diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 7c99555bd3..637e37aa04 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -98,11 +98,25 @@ private: class DebugBloomConfig : public render::Job::Config { Q_OBJECT + Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) public: + enum Mode { + MODE_LEVEL0 = 0, + MODE_LEVEL1, + MODE_LEVEL2, + MODE_ALL_LEVELS, + + MODE_COUNT + }; + DebugBloomConfig() : render::Job::Config(false) {} + int mode{ MODE_ALL_LEVELS }; + +signals: + void dirty(); }; class DebugBloom { @@ -112,13 +126,13 @@ public: using JobModel = render::Job::ModelI; DebugBloom(); - ~DebugBloom(); - void configure(const Config& config) {} + void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); private: gpu::PipelinePointer _pipeline; + DebugBloomConfig::Mode _mode; }; class Bloom { diff --git a/scripts/developer/utilities/render/bloom.qml b/scripts/developer/utilities/render/bloom.qml index d2a928861c..66e92e0eff 100644 --- a/scripts/developer/utilities/render/bloom.qml +++ b/scripts/developer/utilities/render/bloom.qml @@ -28,11 +28,64 @@ Item { root.config["enabled"] = checked; } } - CheckBox { - text: "Debug" - checked: root.configDebug["enabled"] - onCheckedChanged: { - root.configDebug["enabled"] = checked; + GroupBox { + title: "Debug" + Row { + ExclusiveGroup { id: debugGroup } + RadioButton { + text : "Off" + checked : !root.configDebug["enabled"] + onCheckedChanged: { + if (checked) { + root.configDebug["enabled"] = false + } + } + exclusiveGroup : debugGroup + } + RadioButton { + text : "Lvl 0" + checked :root.configDebug["enabled"] && root.configDebug["mode"]==0 + onCheckedChanged: { + if (checked) { + root.configDebug["enabled"] = true + root.configDebug["mode"] = 0 + } + } + exclusiveGroup : debugGroup + } + RadioButton { + text : "Lvl 1" + checked : root.configDebug["enabled"] && root.configDebug["mode"]==1 + onCheckedChanged: { + if (checked) { + root.configDebug["enabled"] = true + root.configDebug["mode"] = 1 + } + } + exclusiveGroup : debugGroup + } + RadioButton { + text : "Lvl 2" + checked : root.configDebug["enabled"] && root.configDebug["mode"]==2 + onCheckedChanged: { + if (checked) { + root.configDebug["enabled"] = true + root.configDebug["mode"] = 2 + } + } + exclusiveGroup : debugGroup + } + RadioButton { + text : "All" + checked : root.configDebug["enabled"] && root.configDebug["mode"]==3 + onCheckedChanged: { + if (checked) { + root.configDebug["enabled"] = true + root.configDebug["mode"] = 3 + } + } + exclusiveGroup : debugGroup + } } } ConfigSlider { From f55d44dfc33e0b48431ef41ea84ce5edd6fcba71 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 10 Oct 2017 17:49:35 +0200 Subject: [PATCH 014/171] Threshold now doesn't downsample anymore. Done in separate pass --- libraries/render-utils/src/BloomEffect.cpp | 53 +++++++++++-------- libraries/render-utils/src/BloomEffect.h | 16 +++--- libraries/render-utils/src/BloomThreshold.slf | 28 ++-------- libraries/render/src/render/ResampleTask.cpp | 8 +-- 4 files changed, 44 insertions(+), 61 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index c6c30e7ff6..e236b290c2 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -21,15 +21,15 @@ #define BLOOM_BLUR_LEVEL_COUNT 3 -ThresholdAndDownsampleJob::ThresholdAndDownsampleJob() { +BloomThreshold::BloomThreshold() { } -void ThresholdAndDownsampleJob::configure(const Config& config) { +void BloomThreshold::configure(const Config& config) { _threshold = config.threshold; } -void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { +void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -40,25 +40,23 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo assert(inputFrameBuffer->hasColor()); - auto inputColor = inputFrameBuffer->getRenderBuffer(0); + auto inputBuffer = inputFrameBuffer->getRenderBuffer(0); auto sourceViewport = args->_viewport; - auto fullSize = glm::ivec2(inputColor->getDimensions()); - auto halfSize = fullSize / 2; - auto halfViewport = args->_viewport >> 1; + auto bufferSize = glm::ivec2(inputBuffer->getDimensions()); - if (!_downsampledBuffer || _downsampledBuffer->getSize().x != halfSize.x || _downsampledBuffer->getSize().y != halfSize.y) { - auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputColor->getTexelFormat(), halfSize.x, halfSize.y, + if (!_outputBuffer || _outputBuffer->getSize() != inputFrameBuffer->getSize()) { + auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputBuffer->getTexelFormat(), bufferSize.x, bufferSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); - _downsampledBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); - _downsampledBuffer->setRenderBuffer(0, colorTexture); + _outputBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("BloomThreshold")); + _outputBuffer->setRenderBuffer(0, colorTexture); } static const int COLOR_MAP_SLOT = 0; static const int THRESHOLD_SLOT = 1; if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); @@ -74,23 +72,19 @@ void ThresholdAndDownsampleJob::run(const render::RenderContextPointer& renderCo gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setViewportTransform(halfViewport); + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(inputFrameBuffer->getSize(), args->_viewport)); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, args->_viewport)); batch.setPipeline(_pipeline); - batch.setFramebuffer(_downsampledBuffer); - batch.setResourceTexture(COLOR_MAP_SLOT, inputColor); + batch.setFramebuffer(_outputBuffer); + batch.setResourceTexture(COLOR_MAP_SLOT, inputBuffer); batch._glUniform1f(THRESHOLD_SLOT, _threshold); batch.draw(gpu::TRIANGLE_STRIP, 4); - - batch.setViewportTransform(args->_viewport); - batch.setResourceTexture(COLOR_MAP_SLOT, nullptr); - batch.setFramebuffer(nullptr); }); - outputs = _downsampledBuffer; + outputs = _outputBuffer; } BloomApply::BloomApply() { @@ -287,14 +281,27 @@ void Bloom::configure(const Config& config) { } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); + const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); + const auto bloomHalfInputBuffer = task.addJob("BloomHalf", bloomInputBuffer); + const auto bloomQuarterInputBuffer = task.addJob("BloomQuarter", bloomHalfInputBuffer); +#if 1 // Multi-scale blur - const auto blurFB0 = task.addJob("BloomBlur0", bloomInputBuffer); + const auto blurFB0 = task.addJob("BloomBlur0", bloomQuarterInputBuffer); const auto halfBlurFB0 = task.addJob("BloomHalfBlur0", blurFB0); const auto blurFB1 = task.addJob("BloomBlur1", halfBlurFB0, true); const auto halfBlurFB1 = task.addJob("BloomHalfBlur1", blurFB1); const auto blurFB2 = task.addJob("BloomBlur2", halfBlurFB1, true); +#else + // Multi-scale downsampling debug + const auto blurFB0 = bloomQuarterInputBuffer; + const auto blurFB1 = task.addJob("BloomHalfBlur1", blurFB0); + const auto blurFB2 = task.addJob("BloomHalfBlur2", blurFB1); + // This is only needed so as not to crash as we expect to have the three blur jobs + task.addJob("BloomBlur0", bloomHalfInputBuffer, true); + task.addJob("BloomBlur1", blurFB1, true); + task.addJob("BloomBlur2", blurFB2, true); +#endif const auto& input = inputs.get(); const auto& frameBuffer = input[1]; diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 637e37aa04..fdc2d1a0ba 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -25,7 +25,7 @@ public: BloomConfig() : render::Task::Config(true) {} - float size{ 0.45f }; + float size{ 0.8f }; void setIntensity(float value); float getIntensity() const; @@ -35,7 +35,7 @@ signals: void dirty(); }; -class ThresholdConfig : public render::Job::Config { +class BloomThresholdConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty) @@ -47,21 +47,21 @@ signals: void dirty(); }; -class ThresholdAndDownsampleJob { +class BloomThreshold { public: using Inputs = render::VaryingSet2; using Outputs = gpu::FramebufferPointer; - using Config = ThresholdConfig; - using JobModel = render::Job::ModelIO; + using Config = BloomThresholdConfig; + using JobModel = render::Job::ModelIO; - ThresholdAndDownsampleJob(); + BloomThreshold(); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); private: - gpu::FramebufferPointer _downsampledBuffer; + gpu::FramebufferPointer _outputBuffer; gpu::PipelinePointer _pipeline; float _threshold; }; @@ -73,7 +73,7 @@ class BloomApplyConfig : public render::Job::Config { public: - float intensity{ 0.5f }; + float intensity{ 0.8f }; signals: void dirty(); diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index d14da4889d..14d20dd684 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -17,29 +17,11 @@ in vec2 varTexCoord0; out vec4 outFragColor; void main(void) { - // Gather 2 by 2 quads from texture, threshold and downsample - vec4 reds = textureGather(colorMap, varTexCoord0, 0); - vec4 greens = textureGather(colorMap, varTexCoord0, 1); - vec4 blues = textureGather(colorMap, varTexCoord0, 2); + vec4 color = texture(colorMap, varTexCoord0); + float luminance = (color.r+color.g+color.b) / 3.0; + float mask = clamp((luminance-threshold)*0.25, 0, 1); - vec3 texel0 = vec3(reds.x, greens.x, blues.x); - vec3 texel1 = vec3(reds.y, greens.y, blues.y); - vec3 texel2 = vec3(reds.z, greens.z, blues.z); - vec3 texel3 = vec3(reds.w, greens.w, blues.w); + color *= mask; - vec4 luminances; - vec3 luminanceWeights = vec3(0.333,0.333,0.333); - - luminances.x = dot(texel0, luminanceWeights); - luminances.y = dot(texel1, luminanceWeights); - luminances.z = dot(texel2, luminanceWeights); - luminances.w = dot(texel0, luminanceWeights); - - vec4 mask = clamp(luminances-threshold, 0, 1); - vec3 color; - - color.x = dot(mask, reds); - color.y = dot(mask, greens); - color.z = dot(mask, blues); - outFragColor = vec4(color/4.0, 1.0); + outFragColor = vec4(color.rgb, 1.0); } diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index 5d4b5c18cb..ef75b54094 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -48,15 +48,12 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F resampledFrameBuffer = getResampledFrameBuffer(sourceFramebuffer); - static auto TEXCOORD_RECT_SLOT = 1; - if (!_pipeline) { - auto vs = gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS(); + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("texcoordRect"), TEXCOORD_RECT_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -80,9 +77,6 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); - // Add half a texel of offset to be sure to sample in the middle of 4 neighbouring texture pixels - // to perform box filtering. - batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f / sourceSize.x, 0.5f / sourceSize.y, 1.f, 1.f); batch.draw(gpu::TRIANGLE_STRIP, 4); }); } From d3add89b3c3a8b0cc88f589a55131c269535dccc Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 10 Oct 2017 18:28:42 +0200 Subject: [PATCH 015/171] Adjusted bloom size range --- libraries/render-utils/src/BloomEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index e236b290c2..239508cd50 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -250,7 +250,7 @@ float BloomConfig::getIntensity() const { void BloomConfig::setSize(float value) { std::string blurName{ "BloomBlurN" }; - auto sigma = value*3.0f; + auto sigma = 0.5f+value*3.5f; for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { blurName.back() = '0' + i; From 18d723b6b43b62f57ddeaf362bcc95ebf1afa261 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 10 Oct 2017 16:17:39 -0700 Subject: [PATCH 016/171] div by zero fixes, detected by address sanitizer --- interface/src/LODManager.cpp | 1 + libraries/animation/src/Rig.cpp | 7 ++++++- .../avatars-renderer/src/avatars-renderer/Avatar.cpp | 3 ++- libraries/shared/src/MovingMinMaxAvg.h | 8 ++++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d3c8746e16..199f3ea2c6 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -54,6 +54,7 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET; float maxTime = glm::max(renderTime, engineRunTime); const float BLEND_TIMESCALE = 0.3f; // sec + const float safeDeltaTime = (deltaTime == 0.0f) ? 0.001f : deltaTime; float blend = BLEND_TIMESCALE / deltaTimeSec; if (blend > 1.0f) { blend = 1.0f; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 0897c26a12..83d258fb08 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -38,7 +38,12 @@ static std::mutex rigRegistryMutex; static bool isEqual(const glm::vec3& u, const glm::vec3& v) { const float EPSILON = 0.0001f; - return glm::length(u - v) / glm::length(u) <= EPSILON; + float uLen = glm::length(u); + if (uLen == 0.0f) { + return glm::length(v) <= EPSILON; + } else { + return glm::length(u - v) / glm::length(u) <= EPSILON; + } } static bool isEqual(const glm::quat& p, const glm::quat& q) { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 87d4a2d343..a52582ff45 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -446,7 +446,8 @@ void Avatar::applyPositionDelta(const glm::vec3& delta) { void Avatar::measureMotionDerivatives(float deltaTime) { PerformanceTimer perfTimer("derivatives"); // linear - float invDeltaTime = 1.0f / deltaTime; + const float safeDeltaTime = (deltaTime == 0.0f) ? 0.001f : deltaTime; + float invDeltaTime = 1.0f / safeDeltaTime; // Floating point error prevents us from computing velocity in a naive way // (e.g. vel = (pos - oldPos) / dt) so instead we use _positionOffsetAccumulator. glm::vec3 velocity = _positionDeltaAccumulator * invDeltaTime; diff --git a/libraries/shared/src/MovingMinMaxAvg.h b/libraries/shared/src/MovingMinMaxAvg.h index 580baf7317..782b0dc523 100644 --- a/libraries/shared/src/MovingMinMaxAvg.h +++ b/libraries/shared/src/MovingMinMaxAvg.h @@ -59,8 +59,12 @@ public: _max = other._max; } double totalSamples = _samples + other._samples; - _average = _average * ((double)_samples / totalSamples) - + other._average * ((double)other._samples / totalSamples); + if (totalSamples > 0) { + _average = _average * ((double)_samples / totalSamples) + + other._average * ((double)other._samples / totalSamples); + } else { + _average = 0.0f; + } _samples += other._samples; } From cbb0d27f684b4e0f3c091c6a9268c1e2309426f7 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 10 Oct 2017 16:20:52 -0700 Subject: [PATCH 017/171] div by zero fix --- interface/src/LODManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 199f3ea2c6..4bdb13545e 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -55,7 +55,7 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta float maxTime = glm::max(renderTime, engineRunTime); const float BLEND_TIMESCALE = 0.3f; // sec const float safeDeltaTime = (deltaTime == 0.0f) ? 0.001f : deltaTime; - float blend = BLEND_TIMESCALE / deltaTimeSec; + float blend = BLEND_TIMESCALE / safeDeltaTime; if (blend > 1.0f) { blend = 1.0f; } From fe57a209792e06952da19999e3aeb277a13d3822 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 10 Oct 2017 16:22:49 -0700 Subject: [PATCH 018/171] div by zero fix --- libraries/animation/src/Rig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 83d258fb08..bd19dcc0e8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -42,7 +42,7 @@ static bool isEqual(const glm::vec3& u, const glm::vec3& v) { if (uLen == 0.0f) { return glm::length(v) <= EPSILON; } else { - return glm::length(u - v) / glm::length(u) <= EPSILON; + return (glm::length(u - v) / uLen) <= EPSILON; } } From cb01c5cada93ed0d4e02f250c7a9047efcc1d227 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 10 Oct 2017 16:30:11 -0700 Subject: [PATCH 019/171] compile fix --- interface/src/LODManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 4bdb13545e..8f01296e1c 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -54,7 +54,7 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET; float maxTime = glm::max(renderTime, engineRunTime); const float BLEND_TIMESCALE = 0.3f; // sec - const float safeDeltaTime = (deltaTime == 0.0f) ? 0.001f : deltaTime; + const float safeDeltaTime = (deltaTimeSec == 0.0f) ? 0.001f : deltaTimeSec; float blend = BLEND_TIMESCALE / safeDeltaTime; if (blend > 1.0f) { blend = 1.0f; From 055270df9c6bec1d20b97f4f9df0b2bee44d829b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 12 Oct 2017 19:26:05 +0200 Subject: [PATCH 020/171] Removed compilation warnings on Mac and Ubuntu --- libraries/render-utils/src/BloomEffect.cpp | 1 - libraries/render/src/render/BlurTask.cpp | 2 +- libraries/render/src/render/ResampleTask.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 239508cd50..69bc790c59 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -41,7 +41,6 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons assert(inputFrameBuffer->hasColor()); auto inputBuffer = inputFrameBuffer->getRenderBuffer(0); - auto sourceViewport = args->_viewport; auto bufferSize = glm::ivec2(inputBuffer->getDimensions()); if (!_outputBuffer || _outputBuffer->getSize() != inputFrameBuffer->getSize()) { diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index a200e0c8ec..5b759ca33c 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -82,7 +82,7 @@ void BlurParams::setFilterGaussianTaps(int numHalfTaps, float sigma) { const int numTaps = 2 * numHalfTaps + 1; assert(numTaps <= BLUR_MAX_NUM_TAPS); assert(sigma > 0.0f); - const float inverseTwoSigmaSquared = float(0.5 / (sigma*sigma)); + const float inverseTwoSigmaSquared = float(0.5 / double(sigma*sigma)); float totalWeight = 1.0f; float weight; float offset; diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index ef75b54094..929db50c31 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -61,7 +61,6 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F _pipeline = gpu::Pipeline::create(program, state); } - const auto sourceSize = sourceFramebuffer->getSize(); const auto bufferSize = resampledFrameBuffer->getSize(); glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; From 049e3d47b67802e99e0de9215374f08131873683 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 13 Oct 2017 10:23:42 +0200 Subject: [PATCH 021/171] Preparing for support of multiple concurrent outlines by adding mask id buffer --- libraries/gpu-gl/src/gpu/gl/GLShared.h | 1 + libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp | 7 ++ libraries/gpu/src/gpu/Format.cpp | 2 + libraries/gpu/src/gpu/Format.h | 2 + libraries/render-utils/src/OutlineEffect.cpp | 113 +++++++++++++----- libraries/render-utils/src/OutlineEffect.h | 29 +++-- 6 files changed, 110 insertions(+), 44 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h index 1b898e5c22..a1cf27afa6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h @@ -110,6 +110,7 @@ static const GLenum ELEMENT_TYPE_TO_GL[gpu::NUM_TYPES] = { GL_SHORT, GL_UNSIGNED_SHORT, GL_BYTE, + GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp index 192a82dafc..27319e1696 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp @@ -212,6 +212,9 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { case gpu::NUINT8: result = GL_RGBA8; break; + case gpu::NUINT2: + result = GL_RGBA2; + break; case gpu::NINT8: result = GL_RGBA8_SNORM; break; @@ -660,6 +663,10 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E texel.format = GL_RGBA; texel.internalFormat = GL_RGBA8_SNORM; break; + case gpu::NUINT2: + texel.format = GL_RGBA; + texel.internalFormat = GL_RGBA2; + break; case gpu::NUINT32: case gpu::NINT32: case gpu::COMPRESSED: diff --git a/libraries/gpu/src/gpu/Format.cpp b/libraries/gpu/src/gpu/Format.cpp index 7efe4d3ed6..3b153097cf 100644 --- a/libraries/gpu/src/gpu/Format.cpp +++ b/libraries/gpu/src/gpu/Format.cpp @@ -19,6 +19,8 @@ const Element Element::COLOR_SRGBA_32{ VEC4, NUINT8, SRGBA }; const Element Element::COLOR_BGRA_32{ VEC4, NUINT8, BGRA }; const Element Element::COLOR_SBGRA_32{ VEC4, NUINT8, SBGRA }; +const Element Element::COLOR_RGBA_2{ VEC4, NUINT2, RGBA }; + const Element Element::COLOR_COMPRESSED_RED{ TILE4x4, COMPRESSED, COMPRESSED_BC4_RED }; const Element Element::COLOR_COMPRESSED_SRGB { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGB }; const Element Element::COLOR_COMPRESSED_SRGBA_MASK { TILE4x4, COMPRESSED, COMPRESSED_BC1_SRGBA }; diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 0654b23581..9d5d2fc49d 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -38,6 +38,7 @@ enum Type : uint8_t { NUINT16, NINT8, NUINT8, + NUINT2, COMPRESSED, @@ -309,6 +310,7 @@ public: static const Element COLOR_SRGBA_32; static const Element COLOR_BGRA_32; static const Element COLOR_SBGRA_32; + static const Element COLOR_RGBA_2; static const Element COLOR_R11G11B10; static const Element COLOR_RGB9E5; static const Element COLOR_COMPRESSED_RED; diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index d5b3b1c3bb..375ba462b9 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -27,12 +27,10 @@ using namespace render; -extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state); - -OutlineFramebuffer::OutlineFramebuffer() { +OutlineRessources::OutlineRessources() { } -void OutlineFramebuffer::update(const gpu::TexturePointer& colorBuffer) { +void OutlineRessources::update(const gpu::TexturePointer& colorBuffer) { // If the depth buffer or size changed, we need to delete our FBOs and recreate them at the // new correct dimensions. if (_depthTexture) { @@ -44,37 +42,48 @@ void OutlineFramebuffer::update(const gpu::TexturePointer& colorBuffer) { } } -void OutlineFramebuffer::clear() { - _depthFramebuffer.reset(); +void OutlineRessources::clear() { + _frameBuffer.reset(); _depthTexture.reset(); + _idTexture.reset(); } -void OutlineFramebuffer::allocate() { +void OutlineRessources::allocate() { auto width = _frameSize.x; auto height = _frameSize.y; - auto format = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - _depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(format, width, height)); - _depthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); - _depthFramebuffer->setDepthStencilBuffer(_depthTexture, format); + _idTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_2, width, height)); + _depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height)); + + _frameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); + _frameBuffer->setDepthStencilBuffer(_depthTexture, depthFormat); + _frameBuffer->setRenderBuffer(0, _idTexture); } -gpu::FramebufferPointer OutlineFramebuffer::getDepthFramebuffer() { - if (!_depthFramebuffer) { +gpu::FramebufferPointer OutlineRessources::getFramebuffer() { + if (!_frameBuffer) { allocate(); } - return _depthFramebuffer; + return _frameBuffer; } -gpu::TexturePointer OutlineFramebuffer::getDepthTexture() { +gpu::TexturePointer OutlineRessources::getDepthTexture() { if (!_depthTexture) { allocate(); } return _depthTexture; } -void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { +gpu::TexturePointer OutlineRessources::getIDTexture() { + if (!_idTexture) { + allocate(); + } + return _idTexture; +} + +void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); auto& inShapes = inputs.get0(); @@ -84,19 +93,19 @@ void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, co RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; - if (!_outlineFramebuffer) { - _outlineFramebuffer = std::make_shared(); + if (!_outlineRessources) { + _outlineRessources = std::make_shared(); } - _outlineFramebuffer->update(deferredFrameBuffer->getDeferredColorTexture()); + _outlineRessources->update(deferredFrameBuffer->getDeferredColorTexture()); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; - batch.setFramebuffer(_outlineFramebuffer->getDepthFramebuffer()); + batch.setFramebuffer(_outlineRessources->getFramebuffer()); // Clear it batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_DEPTH, - vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, false); + gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, + vec4(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0, false); // Setup camera, projection and viewport for all items batch.setViewportTransform(args->_viewport); @@ -110,14 +119,14 @@ void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, co batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); - auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); - auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); + auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); + auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); std::vector skinnedShapeKeys{}; // Iterate through all inShapes and render the unskinned - args->_shapePipeline = shadowPipeline; - batch.setPipeline(shadowPipeline->pipeline); + args->_shapePipeline = maskPipeline; + batch.setPipeline(maskPipeline->pipeline); for (auto items : inShapes) { if (items.first.isSkinned()) { skinnedShapeKeys.push_back(items.first); @@ -128,8 +137,8 @@ void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, co } // Reiterate to render the skinned - args->_shapePipeline = shadowSkinnedPipeline; - batch.setPipeline(shadowSkinnedPipeline->pipeline); + args->_shapePipeline = maskSkinnedPipeline; + batch.setPipeline(maskSkinnedPipeline->pipeline); for (const auto& key : skinnedShapeKeys) { renderItems(renderContext, inShapes.at(key)); } @@ -138,7 +147,7 @@ void DrawOutlineDepth::run(const render::RenderContextPointer& renderContext, co args->_batch = nullptr; }); - output = _outlineFramebuffer; + output = _outlineRessources; } else { output = nullptr; } @@ -348,7 +357,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); - initZPassPipelines(*shapePlumberZPass, state); + initMaskPipelines(*shapePlumberZPass, state); } const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", selectedMetas); @@ -359,8 +368,8 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende const auto sortedShapes = task.addJob("OutlineDepthSort", sortedPipelines); // Draw depth of outlined objects in separate buffer - const auto drawOutlineDepthInputs = DrawOutlineDepth::Inputs(sortedShapes, sceneFrameBuffer).asVarying(); - const auto outlinedFrameBuffer = task.addJob("OutlineDepth", drawOutlineDepthInputs, shapePlumberZPass); + const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedShapes, sceneFrameBuffer).asVarying(); + const auto outlinedFrameBuffer = task.addJob("OutlineMask", drawMaskInputs, shapePlumberZPass); // Draw outline const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, primaryFramebuffer).asVarying(); @@ -369,3 +378,43 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende // Debug outline task.addJob("OutlineDebug", outlinedFrameBuffer); } + +#include "model_shadow_vert.h" +#include "model_shadow_fade_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_shadow_fade_vert.h" + +#include "model_shadow_frag.h" +#include "model_shadow_fade_frag.h" +#include "skin_model_shadow_frag.h" +#include "skin_model_shadow_fade_frag.h" + +void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { + auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutSkinned().withoutFade(), + modelProgram, state); + + auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag)); + gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withSkinned().withoutFade(), + skinProgram, state); + + auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); + auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); + gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutSkinned().withFade(), + modelFadeProgram, state); + + auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); + auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag)); + gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withSkinned().withFade(), + skinFadeProgram, state); +} diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index f88092429f..b04f102a83 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -16,11 +16,12 @@ #include "DeferredFramebuffer.h" #include "DeferredFrameTransform.h" -class OutlineFramebuffer { +class OutlineRessources { public: - OutlineFramebuffer(); + OutlineRessources(); - gpu::FramebufferPointer getDepthFramebuffer(); + gpu::FramebufferPointer getFramebuffer(); + gpu::TexturePointer getIDTexture(); gpu::TexturePointer getDepthTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. @@ -32,30 +33,31 @@ protected: void clear(); void allocate(); - gpu::FramebufferPointer _depthFramebuffer; + gpu::FramebufferPointer _frameBuffer; gpu::TexturePointer _depthTexture; + gpu::TexturePointer _idTexture; glm::ivec2 _frameSize; }; -using OutlineFramebufferPointer = std::shared_ptr; +using OutlineRessourcesPointer = std::shared_ptr; -class DrawOutlineDepth { +class DrawOutlineMask { public: using Inputs = render::VaryingSet2; // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer - using Outputs = OutlineFramebufferPointer; - using JobModel = render::Job::ModelIO; + using Outputs = OutlineRessourcesPointer; + using JobModel = render::Job::ModelIO; - DrawOutlineDepth(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); protected: render::ShapePlumberPointer _shapePlumber; - OutlineFramebufferPointer _outlineFramebuffer; + OutlineRessourcesPointer _outlineRessources; }; class DrawOutlineConfig : public render::Job::Config { @@ -93,7 +95,7 @@ signals: class DrawOutline { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = DrawOutlineConfig; using JobModel = render::Job::ModelI; @@ -146,7 +148,7 @@ signals: class DebugOutline { public: - using Inputs = OutlineFramebufferPointer; + using Inputs = OutlineRessourcesPointer; using Config = DebugOutlineConfig; using JobModel = render::Job::ModelI; @@ -176,6 +178,9 @@ public: void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); +private: + + static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); }; #endif // hifi_render_utils_OutlineEffect_h From 2658d658148ce359ebd9fd6903bafce0747dcc5d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 13 Oct 2017 12:02:21 +0200 Subject: [PATCH 022/171] Preparing for outline color mask --- libraries/render-utils/src/OutlineEffect.cpp | 145 ++++++++++++------ libraries/render-utils/src/OutlineEffect.h | 20 ++- .../render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/model_outline.slf | 21 +++ .../render-utils/src/model_outline_fade.slf | 31 ++++ .../developer/utilities/render/outline.qml | 6 +- 6 files changed, 166 insertions(+), 59 deletions(-) create mode 100644 libraries/render-utils/src/model_outline.slf create mode 100644 libraries/render-utils/src/model_outline_fade.slf diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 375ba462b9..68f1759437 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -76,7 +76,7 @@ gpu::TexturePointer OutlineRessources::getDepthTexture() { return _depthTexture; } -gpu::TexturePointer OutlineRessources::getIDTexture() { +gpu::TexturePointer OutlineRessources::getIdTexture() { if (!_idTexture) { allocate(); } @@ -123,10 +123,13 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); std::vector skinnedShapeKeys{}; + auto colorLoc = maskPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); + glm::vec4 idColor{ 1.0f, 0.0f, 0.0f, 0.0f }; // Iterate through all inShapes and render the unskinned args->_shapePipeline = maskPipeline; batch.setPipeline(maskPipeline->pipeline); + batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); for (auto items : inShapes) { if (items.first.isSkinned()) { skinnedShapeKeys.push_back(items.first); @@ -136,9 +139,11 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con } } + colorLoc = maskSkinnedPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); // Reiterate to render the skinned args->_shapePipeline = maskSkinnedPipeline; batch.setPipeline(maskSkinnedPipeline->pipeline); + batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); for (const auto& key : skinnedShapeKeys) { renderItems(renderContext, inShapes.at(key)); } @@ -250,24 +255,26 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) { } DebugOutline::DebugOutline() { - _geometryId = DependencyManager::get()->allocateID(); + _geometryDepthId = DependencyManager::get()->allocateID(); + _geometryColorId = DependencyManager::get()->allocateID(); } DebugOutline::~DebugOutline() { auto geometryCache = DependencyManager::get(); if (geometryCache) { - geometryCache->releaseID(_geometryId); + geometryCache->releaseID(_geometryDepthId); + geometryCache->releaseID(_geometryColorId); } } void DebugOutline::configure(const Config& config) { - _isDisplayDepthEnabled = config.viewOutlinedDepth; + _isDisplayEnabled = config.viewMask; } void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) { const auto outlineFramebuffer = input; - if (_isDisplayDepthEnabled && outlineFramebuffer) { + if (_isDisplayEnabled && outlineFramebuffer) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; @@ -286,52 +293,101 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const batch.setViewTransform(viewMat, true); batch.setModelTransform(Transform()); - batch.setPipeline(getDebugPipeline()); - batch.setResourceTexture(0, outlineFramebuffer->getDepthTexture()); + const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - const glm::vec4 color(1.0f, 0.5f, 0.2f, 1.0f); - const glm::vec2 bottomLeft(-1.0f, -1.0f); - const glm::vec2 topRight(1.0f, 1.0f); - geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryId); + batch.setPipeline(getDepthPipeline()); + batch.setResourceTexture(0, outlineFramebuffer->getDepthTexture()); + { + const glm::vec2 bottomLeft(-1.0f, -1.0f); + const glm::vec2 topRight(0.0f, 1.0f); + geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId); + } + + batch.setPipeline(getIdPipeline()); + batch.setResourceTexture(0, outlineFramebuffer->getIdTexture()); + { + const glm::vec2 bottomLeft(0.0f, -1.0f); + const glm::vec2 topRight(1.0f, 1.0f); + geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryColorId); + } batch.setResourceTexture(0, nullptr); }); } } -const gpu::PipelinePointer& DebugOutline::getDebugPipeline() { - if (!_debugPipeline) { - static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert }; - static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag }; - static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; - static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, - "Could not find source placeholder"); - static const std::string DEFAULT_DEPTH_SHADER{ +void DebugOutline::initializePipelines() { + static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert }; + static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag }; + static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; + static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); + Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, + "Could not find source placeholder"); + + auto state = std::make_shared(); + state->setDepthTest(gpu::State::DepthTest(false)); + + const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); + + // Depth shader + { + static const std::string DEPTH_SHADER{ "vec4 getFragmentColor() {" " float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x;" " Zdb = 1.0-(1.0-Zdb)*100;" - " return vec4(Zdb, Zdb, Zdb, 1.0);" - " }" + " return vec4(Zdb, Zdb, Zdb, 1.0); " + "}" }; - auto bakedFragmentShader = FRAGMENT_SHADER; - bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEFAULT_DEPTH_SHADER); + auto fragmentShader = FRAGMENT_SHADER; + fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEPTH_SHADER); - static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); - const auto ps = gpu::Shader::createPixel(bakedFragmentShader); + const auto ps = gpu::Shader::createPixel(fragmentShader); const auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding("depthMap", 0)); gpu::Shader::makeProgram(*program, slotBindings); - auto state = std::make_shared(); - state->setDepthTest(gpu::State::DepthTest(false)); - _debugPipeline = gpu::Pipeline::create(program, state); + _depthPipeline = gpu::Pipeline::create(program, state); } - return _debugPipeline; + // ID shader + { + static const std::string ID_SHADER{ + "vec4 getFragmentColor() {" + " return texelFetch(albedoMap, ivec2(gl_FragCoord.xy), 0); " + "}" + }; + + auto fragmentShader = FRAGMENT_SHADER; + fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), ID_SHADER); + + const auto ps = gpu::Shader::createPixel(fragmentShader); + const auto program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("albedoMap", 0)); + gpu::Shader::makeProgram(*program, slotBindings); + + _idPipeline = gpu::Pipeline::create(program, state); + } +} + +const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { + if (!_depthPipeline) { + initializePipelines(); + } + + return _depthPipeline; +} + +const gpu::PipelinePointer& DebugOutline::getIdPipeline() { + if (!_idPipeline) { + initializePipelines(); + } + + return _idPipeline; } DrawOutlineTask::DrawOutlineTask() { @@ -345,19 +401,18 @@ void DrawOutlineTask::configure(const Config& config) { void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { const auto input = inputs.get(); const auto selectedMetas = inputs.getN(0); - const auto shapePlumber = input.get1(); - const auto sceneFrameBuffer = inputs.getN(2); - const auto primaryFramebuffer = inputs.getN(3); - const auto deferredFrameTransform = inputs.getN(4); + const auto sceneFrameBuffer = inputs.getN(1); + const auto primaryFramebuffer = inputs.getN(2); + const auto deferredFrameTransform = inputs.getN(3); // Prepare the ShapePipeline - ShapePlumberPointer shapePlumberZPass = std::make_shared(); + ShapePlumberPointer shapePlumber = std::make_shared(); { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); - initMaskPipelines(*shapePlumberZPass, state); + initMaskPipelines(*shapePlumber, state); } const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", selectedMetas); @@ -369,7 +424,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende // Draw depth of outlined objects in separate buffer const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedShapes, sceneFrameBuffer).asVarying(); - const auto outlinedFrameBuffer = task.addJob("OutlineMask", drawMaskInputs, shapePlumberZPass); + const auto outlinedFrameBuffer = task.addJob("OutlineMask", drawMaskInputs, shapePlumber); // Draw outline const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, primaryFramebuffer).asVarying(); @@ -384,36 +439,32 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende #include "skin_model_shadow_vert.h" #include "skin_model_shadow_fade_vert.h" -#include "model_shadow_frag.h" -#include "model_shadow_fade_frag.h" -#include "skin_model_shadow_frag.h" -#include "skin_model_shadow_fade_frag.h" +#include "model_outline_frag.h" +#include "model_outline_fade_frag.h" void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelPixel = gpu::Shader::createPixel(std::string(model_outline_frag)); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withoutSkinned().withoutFade(), modelProgram, state); auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag)); - gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel); + gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withSkinned().withoutFade(), skinProgram, state); auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); - auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); + auto modelFadePixel = gpu::Shader::createPixel(std::string(model_outline_fade_frag)); gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withoutSkinned().withFade(), modelFadeProgram, state); auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); - auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag)); - gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel); + gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, modelFadePixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withSkinned().withFade(), skinFadeProgram, state); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index b04f102a83..511ed4a992 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -21,7 +21,7 @@ public: OutlineRessources(); gpu::FramebufferPointer getFramebuffer(); - gpu::TexturePointer getIDTexture(); + gpu::TexturePointer getIdTexture(); gpu::TexturePointer getDepthTexture(); // Update the source framebuffer size which will drive the allocation of all the other resources. @@ -136,11 +136,11 @@ private: class DebugOutlineConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(bool viewOutlinedDepth MEMBER viewOutlinedDepth NOTIFY dirty) + Q_PROPERTY(bool viewMask MEMBER viewMask NOTIFY dirty) public: - bool viewOutlinedDepth{ false }; + bool viewMask{ false }; signals: void dirty(); @@ -160,16 +160,20 @@ public: private: - const gpu::PipelinePointer& getDebugPipeline(); + gpu::PipelinePointer _depthPipeline; + gpu::PipelinePointer _idPipeline; + int _geometryDepthId{ 0 }; + int _geometryColorId{ 0 }; + bool _isDisplayEnabled{ false }; - gpu::PipelinePointer _debugPipeline; - int _geometryId{ 0 }; - bool _isDisplayDepthEnabled{ false }; + const gpu::PipelinePointer& getDepthPipeline(); + const gpu::PipelinePointer& getIdPipeline(); + void initializePipelines(); }; class DrawOutlineTask { public: - using Inputs = render::VaryingSet5; + using Inputs = render::VaryingSet4; using Config = render::Task::Config; using JobModel = render::Task::ModelI; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 45e6fd4ba4..1739f67748 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -173,7 +173,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("ToneMapping", toneMappingInputs); const auto outlineRangeTimer = task.addJob("BeginOutlineRangeTimer", "Outline"); - const auto outlineInputs = DrawOutlineTask::Inputs(selectedItems, shapePlumber, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); + const auto outlineInputs = DrawOutlineTask::Inputs(selectedItems, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); task.addJob("DrawOutline", outlineInputs); task.addJob("EndOutlineRangeTimer", outlineRangeTimer); diff --git a/libraries/render-utils/src/model_outline.slf b/libraries/render-utils/src/model_outline.slf new file mode 100644 index 0000000000..8c11b2b295 --- /dev/null +++ b/libraries/render-utils/src/model_outline.slf @@ -0,0 +1,21 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_outline.frag +// fragment shader +// +// Created by Olivier Prat on 10/13/17. +// 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 +// + +layout(location = 0) out vec4 _fragColor; + +uniform vec4 color; + +void main(void) { + _fragColor = color; +} diff --git a/libraries/render-utils/src/model_outline_fade.slf b/libraries/render-utils/src/model_outline_fade.slf new file mode 100644 index 0000000000..69ff54dea6 --- /dev/null +++ b/libraries/render-utils/src/model_outline_fade.slf @@ -0,0 +1,31 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_outline_fade.frag +// fragment shader +// +// Created by Olivier Prat on 10/13/17. +// 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 +// + +<@include Fade.slh@> +<$declareFadeFragment()$> + +layout(location = 0) out vec4 _fragColor; + +uniform vec4 color; + +in vec4 _worldPosition; + +void main(void) { + FadeObjectParams fadeParams; + + <$fetchFadeObjectParams(fadeParams)$> + applyFadeClip(fadeParams, _worldPosition.xyz); + + _fragColor = color; +} diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index e17f7c1f1c..1b5cbf6e1c 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -21,10 +21,10 @@ Item { spacing: 8 CheckBox { - text: "View Outlined Depth" - checked: root.debugConfig["viewOutlinedDepth"] + text: "View Mask" + checked: root.debugConfig["viewMask"] onCheckedChanged: { - root.debugConfig["viewOutlinedDepth"] = checked; + root.debugConfig["viewMask"] = checked; } } CheckBox { From 8d79313a9debcdcceebf0a6ebca5e2b849f0787a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 16 Oct 2017 09:42:58 +0200 Subject: [PATCH 023/171] Working mask rendering and debugging --- libraries/render-utils/src/OutlineEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 68f1759437..96a37eca6a 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -410,7 +410,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setColorWriteMask(false, false, false, false); + state->setColorWriteMask(true, true, true, true); initMaskPipelines(*shapePlumber, state); } From e42699c0ea615a47eee62c8281fd282b9542c3d6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 16 Oct 2017 10:57:06 +0200 Subject: [PATCH 024/171] Added multiple selections but still only first linked to outline --- .../ui/overlays/ContextOverlayInterface.cpp | 9 ++-- .../src/ui/overlays/ContextOverlayInterface.h | 7 ++- libraries/render-utils/src/OutlineEffect.cpp | 4 +- libraries/render-utils/src/OutlineEffect.h | 8 +++- .../render-utils/src/RenderDeferredTask.cpp | 43 +++++++++++++------ .../render-utils/src/RenderDeferredTask.h | 4 ++ 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 8cbb214857..f677dc6550 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -34,7 +34,12 @@ ContextOverlayInterface::ContextOverlayInterface() { _tabletScriptingInterface = DependencyManager::get(); _selectionScriptingInterface = DependencyManager::get(); - _selectionToSceneHandler.initialize("contextOverlayHighlightList"); + _selectionToSceneHandlers[0].initialize("contextOverlayHighlightList"); + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged); + for (auto i = 1; i < MAX_HIGHLIGHT_COUNT; i++) { + _selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i)); + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged); + } _entityPropertyFlags += PROP_POSITION; _entityPropertyFlags += PROP_ROTATION; @@ -61,8 +66,6 @@ ContextOverlayInterface::ContextOverlayInterface() { }); auto entityScriptingInterface = DependencyManager::get().data(); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); - - connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged); } static const uint32_t MOUSE_HW_ID = 0; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index b4d3ddc0c2..2a96ea3d3e 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -47,6 +47,11 @@ class ContextOverlayInterface : public QObject, public Dependency { OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID }; std::shared_ptr _contextOverlay { nullptr }; public: + + enum { + MAX_HIGHLIGHT_COUNT = 4 + }; + ContextOverlayInterface(); Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; } @@ -86,7 +91,7 @@ private: void deletingEntity(const EntityItemID& entityItemID); - SelectionToSceneHandler _selectionToSceneHandler; + SelectionToSceneHandler _selectionToSceneHandlers[MAX_HIGHLIGHT_COUNT]; }; #endif // hifi_ContextOverlayInterface_h diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 96a37eca6a..89cedf0676 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -399,8 +399,8 @@ void DrawOutlineTask::configure(const Config& config) { } void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto input = inputs.get(); - const auto selectedMetas = inputs.getN(0); + const auto groups = inputs.getN(0).get(); + const auto selectedMetas = groups[0]; const auto sceneFrameBuffer = inputs.getN(1); const auto primaryFramebuffer = inputs.getN(2); const auto deferredFrameTransform = inputs.getN(3); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index 511ed4a992..c32d352a01 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -173,7 +173,13 @@ private: class DrawOutlineTask { public: - using Inputs = render::VaryingSet4; + + enum { + MAX_GROUP_COUNT = 7 + }; + + using Groups = render::VaryingArray; + using Inputs = render::VaryingSet4; using Config = render::Task::Config; using JobModel = render::Task::ModelI; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1739f67748..c20eb10cf6 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -44,6 +44,7 @@ #include +#include using namespace render; extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); @@ -57,6 +58,18 @@ void RenderDeferredTask::configure(const Config& config) { } +const render::Varying RenderDeferredTask::addSelectItemJobs(JobModel& task, const char* selectionName, + const render::Varying& metas, + const render::Varying& opaques, + const render::Varying& transparents) { + const auto selectMetaInput = SelectItems::Inputs(metas, Varying()).asVarying(); + const auto selectedMetas = task.addJob("MetaSelection", selectMetaInput, selectionName); + const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas).asVarying(); + const auto selectedMetasAndOpaques = task.addJob("OpaqueSelection", selectMetaAndOpaqueInput, selectionName); + const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques).asVarying(); + return task.addJob("TransparentSelection", selectItemInput, selectionName); +} + void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { const auto& items = input.get(); auto fadeEffect = DependencyManager::get(); @@ -94,15 +107,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", primaryFramebuffer); - // Select items that need to be outlined - const auto selectionName = "contextOverlayHighlightList"; - const auto selectMetaInput = SelectItems::Inputs(metas, Varying()).asVarying(); - const auto selectedMetas = task.addJob("PassTestMetaSelection", selectMetaInput, selectionName); - const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas).asVarying(); - const auto selectedMetasAndOpaques = task.addJob("PassTestOpaqueSelection", selectMetaAndOpaqueInput, selectionName); - const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques).asVarying(); - const auto selectedItems = task.addJob("PassTestTransparentSelection", selectItemInput, selectionName); - // Render opaque objects in DeferredBuffer const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); @@ -172,9 +176,22 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying(); task.addJob("ToneMapping", toneMappingInputs); + // Select items that need to be outlined + const auto selectionBaseName = "contextOverlayHighlightList"; + const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); + DrawOutlineTask::Groups outlineGroups; + outlineGroups[0] = selectedItems; + for (auto i = 1; i < DrawOutlineTask::MAX_GROUP_COUNT; i++) { + std::ostringstream selectionName; + selectionName << selectionBaseName; + selectionName << i; + outlineGroups[i] = addSelectItemJobs(task, selectionName.str().c_str(), metas, opaques, transparents); + } const auto outlineRangeTimer = task.addJob("BeginOutlineRangeTimer", "Outline"); - const auto outlineInputs = DrawOutlineTask::Inputs(selectedItems, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); + + const auto outlineInputs = DrawOutlineTask::Inputs(outlineGroups, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); task.addJob("DrawOutline", outlineInputs); + task.addJob("EndOutlineRangeTimer", outlineRangeTimer); { // DEbug the bounds of the rendered items, still look at the zbuffer @@ -184,6 +201,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawLightBounds", lights); task.addJob("DrawZones", zones); + + // Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true + task.addJob("DrawSelectionBounds", selectedItems); } // Layered Overlays @@ -230,9 +250,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren } task.addJob("DrawZoneStack", deferredFrameTransform); - - // Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true - task.addJob("DrawSelectionBounds", selectedItems); } // AA job to be revisited diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 452420589b..567e7f6ccd 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -198,6 +198,10 @@ public: void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); +private: + + static const render::Varying addSelectItemJobs(JobModel& task, const char* selectionName, + const render::Varying& metas, const render::Varying& opaques, const render::Varying& transparents); }; #endif // hifi_RenderDeferredTask_h From 1b67223e0eaaff87363c7f18bf8a0e3c4255943a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 16 Oct 2017 12:38:44 +0200 Subject: [PATCH 025/171] Preparing for multiple outline groups in shader --- libraries/render-utils/src/Outline.slh | 8 +- libraries/render-utils/src/OutlineEffect.cpp | 221 +++++++++++------- libraries/render-utils/src/OutlineEffect.h | 92 +++++--- libraries/render-utils/src/Outline_shared.slh | 4 + .../render-utils/src/RenderDeferredTask.cpp | 2 +- 5 files changed, 210 insertions(+), 117 deletions(-) diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Outline.slh index ac56e4c95c..4e71116f79 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Outline.slh @@ -21,11 +21,13 @@ uniform outlineParamsBuffer { uniform sampler2D sceneDepthMap; uniform sampler2D outlinedDepthMap; +uniform sampler2D outlinedIdMap; in vec2 varTexCoord0; out vec4 outFragColor; const float FAR_Z = 1.0; +const float ID_THRESHOLD = 1.f/64.f; const float LINEAR_DEPTH_BIAS = 5e-3; const float OPACITY_EPSILON = 5e-3; @@ -37,10 +39,11 @@ void main(void) { // sides of the silhouette vec2 halfTexel = getInvWidthHeight() / 2; vec2 texCoord0 = varTexCoord0+halfTexel; + vec4 outlinedIdColor = texture(outlinedIdMap, texCoord0); float outlinedDepth = texture(outlinedDepthMap, texCoord0).x; float intensity = 0.0; - if (outlinedDepth < FAR_Z) { + if (outlinedDepth < FAR_Z && distance(outlinedIdColor, params._idColor) < ID_THRESHOLD) { // We're not on the far plane so we are on the outlined object, thus no outline to do! <@if IS_FILLED@> // But we need to fill the interior @@ -75,7 +78,8 @@ void main(void) { if (uv.x>=0.0 && uv.x<=1.0) { outlinedDepth = texture(outlinedDepthMap, uv).x; - intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0; + outlinedIdColor = texture(outlinedIdMap, uv); + intensity += (outlinedDepth < FAR_Z && distance(outlinedIdColor, params._idColor) < ID_THRESHOLD) ? 1.0 : 0.0; weight += 1.f; } uv.x += deltaUv.x; diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 89cedf0676..0ffd2581cf 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -83,81 +83,139 @@ gpu::TexturePointer OutlineRessources::getIdTexture() { return _idTexture; } +glm::vec4 encodeIdToColor(unsigned int id) { + union { + struct { + unsigned int r : 2; + unsigned int g : 2; + unsigned int b : 2; + unsigned int a : 2; + }; + unsigned char id; + } groupId; + + assert(id < 254); + groupId.id = id+1; + + glm::vec4 idColor{ groupId.r, groupId.g, groupId.b, groupId.a }; + + // Normalize. Since we put 2 bits into each color component, each component has a maximum + // value of 3. + idColor /= 3.f; + return idColor; +} + void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); - auto& inShapes = inputs.get0(); + auto& groups = inputs.get0(); auto& deferredFrameBuffer = inputs.get1(); - if (!inShapes.empty()) { - RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder; + RenderArgs* args = renderContext->args; + ShapeKey::Builder defaultKeyBuilder; + auto hasOutline = false; - if (!_outlineRessources) { - _outlineRessources = std::make_shared(); + if (!_outlineRessources) { + _outlineRessources = std::make_shared(); + } + _outlineRessources->update(deferredFrameBuffer->getDeferredColorTexture()); + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); + auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); + auto colorLoc = maskPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); + auto skinnedColorLoc = maskSkinnedPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); + unsigned int groupId = 0; + + for (auto& inShapeBounds : groups) { + if (!inShapeBounds.isNull()) { + auto& inShapes = inShapeBounds.get(); + + if (!inShapes.empty()) { + if (!hasOutline) { + batch.setFramebuffer(_outlineRessources->getFramebuffer()); + // Clear it only if it hasn't been done before + batch.clearFramebuffer( + gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, + vec4(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0, false); + + // Setup camera, projection and viewport for all items + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + hasOutline = true; + } + + std::vector skinnedShapeKeys{}; + // Encode group id in quantized color + glm::vec4 idColor = encodeIdToColor(groupId); + + // Iterate through all inShapes and render the unskinned + args->_shapePipeline = maskPipeline; + batch.setPipeline(maskPipeline->pipeline); + batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); + for (auto items : inShapes) { + if (items.first.isSkinned()) { + skinnedShapeKeys.push_back(items.first); + } else { + renderItems(renderContext, items.second); + } + } + + // Reiterate to render the skinned + args->_shapePipeline = maskSkinnedPipeline; + batch.setPipeline(maskSkinnedPipeline->pipeline); + batch._glUniform4f(skinnedColorLoc, idColor.r, idColor.g, idColor.b, idColor.a); + for (const auto& key : skinnedShapeKeys) { + renderItems(renderContext, inShapes.at(key)); + } + } + } + + ++groupId; } - _outlineRessources->update(deferredFrameBuffer->getDeferredColorTexture()); - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - batch.setFramebuffer(_outlineRessources->getFramebuffer()); - // Clear it - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, - vec4(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0, false); - - // Setup camera, projection and viewport for all items - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - - auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); - auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); - - std::vector skinnedShapeKeys{}; - auto colorLoc = maskPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); - glm::vec4 idColor{ 1.0f, 0.0f, 0.0f, 0.0f }; - - // Iterate through all inShapes and render the unskinned - args->_shapePipeline = maskPipeline; - batch.setPipeline(maskPipeline->pipeline); - batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); - for (auto items : inShapes) { - if (items.first.isSkinned()) { - skinnedShapeKeys.push_back(items.first); - } - else { - renderItems(renderContext, items.second); - } - } - - colorLoc = maskSkinnedPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); - // Reiterate to render the skinned - args->_shapePipeline = maskSkinnedPipeline; - batch.setPipeline(maskSkinnedPipeline->pipeline); - batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); - for (const auto& key : skinnedShapeKeys) { - renderItems(renderContext, inShapes.at(key)); - } - - args->_shapePipeline = nullptr; - args->_batch = nullptr; - }); + args->_shapePipeline = nullptr; + args->_batch = nullptr; + }); + if (hasOutline) { output = _outlineRessources; } else { output = nullptr; } } +PrepareDrawOutline::PrepareDrawOutline() { + +} + +void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + auto destinationFrameBuffer = inputs; + auto framebufferSize = destinationFrameBuffer->getSize(); + + if (!_primaryWithoutDepthBuffer || framebufferSize != _frameBufferSize) { + // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac + _primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); + _primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0)); + _frameBufferSize = framebufferSize; + } + + outputs = _primaryWithoutDepthBuffer; +} + +gpu::PipelinePointer DrawOutline::_pipeline; +gpu::PipelinePointer DrawOutline::_pipelineFilled; + DrawOutline::DrawOutline() { } @@ -170,6 +228,7 @@ void DrawOutline::configure(const Config& config) { _fillOpacityOccluded = config.fillOpacityOccluded; _threshold = config.glow ? 1.f : 1e-3f; _intensity = config.intensity * (config.glow ? 2.f : 1.f); + _hasConfigurationChanged = true; } void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { @@ -179,20 +238,16 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture(); + auto outlinedIdTexture = outlineFrameBuffer->getIdTexture(); auto destinationFrameBuffer = inputs.get3(); auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); - if (!_primaryWithoutDepthBuffer || framebufferSize!=_frameBufferSize) { - // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac - _primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); - _primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0)); - _frameBufferSize = framebufferSize; - } - if (sceneDepthBuffer) { const auto OPACITY_EPSILON = 5e-3f; auto pipeline = getPipeline(_fillOpacityUnoccluded>OPACITY_EPSILON || _fillOpacityOccluded>OPACITY_EPSILON); auto args = renderContext->args; + + if (_hasConfigurationChanged) { auto& configuration = _configuration.edit(); configuration._color = _color; @@ -201,24 +256,27 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I configuration._fillOpacityOccluded = _fillOpacityOccluded; configuration._threshold = _threshold; configuration._blurKernelSize = _blurKernelSize; - configuration._size.x = _size * _frameBufferSize.y / _frameBufferSize.x; + configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x; configuration._size.y = _size; + configuration._idColor = encodeIdToColor(0); + _hasConfigurationChanged = false; } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setFramebuffer(_primaryWithoutDepthBuffer); + batch.setFramebuffer(destinationFrameBuffer); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_frameBufferSize, args->_viewport)); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); + batch.setResourceTexture(OUTLINED_ID_SLOT, outlinedIdTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); // Restore previous frame buffer @@ -239,6 +297,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) { slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT)); slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT)); slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT)); + slotBindings.insert(gpu::Shader::Binding("outlinedIdMap", OUTLINED_ID_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -400,7 +459,6 @@ void DrawOutlineTask::configure(const Config& config) { void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { const auto groups = inputs.getN(0).get(); - const auto selectedMetas = groups[0]; const auto sceneFrameBuffer = inputs.getN(1); const auto primaryFramebuffer = inputs.getN(2); const auto deferredFrameTransform = inputs.getN(3); @@ -415,19 +473,26 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende initMaskPipelines(*shapePlumber, state); } - const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", selectedMetas); - const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs, true); + DrawOutlineMask::Groups sortedBounds; + for (auto i = 0; i < DrawOutline::MAX_GROUP_COUNT; i++) { + const auto groupItems = groups[i]; + const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); + const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs, true); - // Sort - const auto sortedPipelines = task.addJob("OutlinePipelineSort", outlinedItems); - const auto sortedShapes = task.addJob("OutlineDepthSort", sortedPipelines); + // Sort + const auto sortedPipelines = task.addJob("OutlinePipelineSort", outlinedItems); + sortedBounds[i] = task.addJob("OutlineDepthSort", sortedPipelines); + } // Draw depth of outlined objects in separate buffer - const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedShapes, sceneFrameBuffer).asVarying(); + const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, sceneFrameBuffer).asVarying(); const auto outlinedFrameBuffer = task.addJob("OutlineMask", drawMaskInputs, shapePlumber); + // Prepare for outline group rendering. + const auto destFrameBuffer = task.addJob("PrepareOutline", primaryFramebuffer); + // Draw outline - const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, primaryFramebuffer).asVarying(); + const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, destFrameBuffer).asVarying(); task.addJob("OutlineEffect", drawOutlineInputs); // Debug outline diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index c32d352a01..ce0b2917a4 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -42,22 +42,22 @@ protected: using OutlineRessourcesPointer = std::shared_ptr; -class DrawOutlineMask { +class PrepareDrawOutline { public: + using Inputs = gpu::FramebufferPointer; + using Outputs = gpu::FramebufferPointer; + using Config = render::Job::Config; + using JobModel = render::Job::ModelIO; - using Inputs = render::VaryingSet2; - // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer - using Outputs = OutlineRessourcesPointer; - using JobModel = render::Job::ModelIO; + PrepareDrawOutline(); - DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); +private: -protected: + gpu::FramebufferPointer _primaryWithoutDepthBuffer; + gpu::Vec2u _frameBufferSize{ 0, 0 }; - render::ShapePlumberPointer _shapePlumber; - OutlineRessourcesPointer _outlineRessources; }; class DrawOutlineConfig : public render::Job::Config { @@ -95,6 +95,10 @@ signals: class DrawOutline { public: + enum { + MAX_GROUP_COUNT = 7 + }; + using Inputs = render::VaryingSet4; using Config = DrawOutlineConfig; using JobModel = render::Job::ModelI; @@ -109,6 +113,7 @@ private: enum { SCENE_DEPTH_SLOT = 0, OUTLINED_DEPTH_SLOT, + OUTLINED_ID_SLOT, OUTLINE_PARAMS_SLOT = 0, FRAME_TRANSFORM_SLOT @@ -118,12 +123,10 @@ private: using OutlineConfigurationBuffer = gpu::StructBuffer; - const gpu::PipelinePointer& getPipeline(bool isFilled); + static const gpu::PipelinePointer& getPipeline(bool isFilled); - gpu::FramebufferPointer _primaryWithoutDepthBuffer; - glm::ivec2 _frameBufferSize {0, 0}; - gpu::PipelinePointer _pipeline; - gpu::PipelinePointer _pipelineFilled; + static gpu::PipelinePointer _pipeline; + static gpu::PipelinePointer _pipelineFilled; OutlineConfigurationBuffer _configuration; glm::vec3 _color; float _size; @@ -132,6 +135,44 @@ private: float _fillOpacityUnoccluded; float _fillOpacityOccluded; float _threshold; + bool _hasConfigurationChanged{ true }; +}; + +class DrawOutlineTask { +public: + + using Groups = render::VaryingArray; + using Inputs = render::VaryingSet4; + using Config = render::Task::Config; + using JobModel = render::Task::ModelI; + + DrawOutlineTask(); + + void configure(const Config& config); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); + +private: + + static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); +}; + +class DrawOutlineMask { +public: + + using Groups = render::VaryingArray; + using Inputs = render::VaryingSet2; + // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer + using Outputs = OutlineRessourcesPointer; + using JobModel = render::Job::ModelIO; + + DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); + +protected: + + render::ShapePlumberPointer _shapePlumber; + OutlineRessourcesPointer _outlineRessources; }; class DebugOutlineConfig : public render::Job::Config { @@ -171,27 +212,6 @@ private: void initializePipelines(); }; -class DrawOutlineTask { -public: - - enum { - MAX_GROUP_COUNT = 7 - }; - - using Groups = render::VaryingArray; - using Inputs = render::VaryingSet4; - using Config = render::Task::Config; - using JobModel = render::Task::ModelI; - - DrawOutlineTask(); - - void configure(const Config& config); - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); - -private: - - static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); -}; #endif // hifi_render_utils_OutlineEffect_h diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index 902bbd20ad..5ce21c85b4 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -2,9 +2,11 @@ #ifdef __cplusplus # define VEC2 glm::vec2 # define VEC3 glm::vec3 +# define VEC4 glm::vec4 #else # define VEC2 vec2 # define VEC3 vec3 +# define VEC4 vec4 #endif struct OutlineParameters @@ -16,6 +18,8 @@ struct OutlineParameters float _fillOpacityUnoccluded; float _fillOpacityOccluded; + VEC4 _idColor; + float _threshold; int _blurKernelSize; float padding2; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c20eb10cf6..73d8b93c07 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -181,7 +181,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); DrawOutlineTask::Groups outlineGroups; outlineGroups[0] = selectedItems; - for (auto i = 1; i < DrawOutlineTask::MAX_GROUP_COUNT; i++) { + for (auto i = 1; i < DrawOutline::MAX_GROUP_COUNT; i++) { std::ostringstream selectionName; selectionName << selectionBaseName; selectionName << i; From 70f892e67d47847c60268cfd0469b04f147fc986 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 16 Oct 2017 17:02:13 +0200 Subject: [PATCH 026/171] Ready to plug multiple selections javascript side --- libraries/render-utils/src/Outline.slh | 131 +++++++++++------- libraries/render-utils/src/OutlineEffect.cpp | 32 +++-- libraries/render-utils/src/OutlineEffect.h | 14 +- libraries/render-utils/src/Outline_shared.slh | 6 +- 4 files changed, 112 insertions(+), 71 deletions(-) diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Outline.slh index 4e71116f79..c58d1c7689 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Outline.slh @@ -16,23 +16,85 @@ <@include Outline_shared.slh@> uniform outlineParamsBuffer { - OutlineParameters params; + OutlineParameters groups[GROUP_COUNT]; }; uniform sampler2D sceneDepthMap; uniform sampler2D outlinedDepthMap; uniform sampler2D outlinedIdMap; +uniform int enabledGroupsMask; in vec2 varTexCoord0; out vec4 outFragColor; const float FAR_Z = 1.0; -const float ID_THRESHOLD = 1.f/64.f; const float LINEAR_DEPTH_BIAS = 5e-3; const float OPACITY_EPSILON = 5e-3; <@func main(IS_FILLED)@> +int getGroupIndexFromColor(vec4 color) { + ivec4 id = ivec4(color * GROUP_ID_COLOR_COMPONENT_MAX) << ivec4(0, GROUP_ID_COLOR_COMPONENT_BITS, GROUP_ID_COLOR_COMPONENT_BITS*2, GROUP_ID_COLOR_COMPONENT_BITS*3); + return (id.r | id.g | id.b | id.a) - 1; +} + +vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2 texCoord) { + float intensity = 0.0; + + if (centerGroupId==groupId && centerDepth < FAR_Z) { + // We're on the outlined object, thus no outline to do! +<@if IS_FILLED@> + OutlineParameters groupParams = groups[groupId]; + + // But we need to fill the interior + float sceneDepth = texture(sceneDepthMap, texCoord).x; + // Transform to linear depth for better precision + centerDepth = -evalZeyeFromZdb(centerDepth); + sceneDepth = -evalZeyeFromZdb(sceneDepth); + + // Are we occluded? + intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._fillOpacityOccluded : groupParams._fillOpacityUnoccluded; + return vec4(groupParams._color.rgb, intensity); +<@else@> + return vec4(0,0,0,0); +<@endif@> + } else { + OutlineParameters groupParams = groups[groupId]; + float weight = 0.0; + vec2 deltaUv = groupParams._size / groupParams._blurKernelSize; + vec2 lineStartUv = texCoord - groupParams._size / 2.0; + vec2 uv; + int x; + int y; + + for (y=0 ; y=0.0 && uv.y<=1.0) { + for (x=0 ; x=0.0 && uv.x<=1.0) + { + vec4 outlinedIdColor = texture(outlinedIdMap, uv); + float outlinedDepth = texture(outlinedDepthMap, uv).x; + int outlinedId = getGroupIndexFromColor(outlinedIdColor); + intensity += (outlinedDepth - // But we need to fill the interior - float sceneDepth = texture(sceneDepthMap, texCoord0).x; - // Transform to linear depth for better precision - outlinedDepth = -evalZeyeFromZdb(outlinedDepth); - sceneDepth = -evalZeyeFromZdb(sceneDepth); - - // Are we occluded? - if (sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS)) { - intensity = params._fillOpacityOccluded; - } else { - intensity = params._fillOpacityUnoccluded; + vec4 finalColor = vec4(0,0,0,0); + int groupMask = 1; + for (int i=0 ; i - discard; -<@endif@> - } else { - float weight = 0.0; - vec2 deltaUv = params._size / params._blurKernelSize; - vec2 lineStartUv = texCoord0 - params._size / 2.0; - vec2 uv; - int x; - int y; - - for (y=0 ; y=0.0 && uv.y<=1.0) { - for (x=0 ; x=0.0 && uv.x<=1.0) - { - outlinedDepth = texture(outlinedDepthMap, uv).x; - outlinedIdColor = texture(outlinedIdMap, uv); - intensity += (outlinedDepth < FAR_Z && distance(outlinedIdColor, params._idColor) < ID_THRESHOLD) ? 1.0 : 0.0; - weight += 1.f; - } - uv.x += deltaUv.x; - } - } - } - - intensity /= weight; - if (intensity < OPACITY_EPSILON) { - discard; - } - - intensity = min(1.0, intensity / params._threshold) * params._intensity; + groupMask <<= 1; } - outFragColor = vec4(params._color.rgb, intensity); + if (finalColor.a < OPACITY_EPSILON) { + discard; + } + outFragColor = finalColor; } <@endfunc@> diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 0ffd2581cf..2cb19826f4 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -94,6 +94,8 @@ glm::vec4 encodeIdToColor(unsigned int id) { unsigned char id; } groupId; + static_assert(GROUP_ID_COLOR_COMPONENT_BITS == 2, "Assuming two bits per component contrary to GLSL shader code. See Outline_shared.slh"); + assert(id < 254); groupId.id = id+1; @@ -101,7 +103,7 @@ glm::vec4 encodeIdToColor(unsigned int id) { // Normalize. Since we put 2 bits into each color component, each component has a maximum // value of 3. - idColor /= 3.f; + idColor /= GROUP_ID_COLOR_COMPONENT_MAX; return idColor; } @@ -250,15 +252,19 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I if (_hasConfigurationChanged) { auto& configuration = _configuration.edit(); - configuration._color = _color; - configuration._intensity = _intensity; - configuration._fillOpacityUnoccluded = _fillOpacityUnoccluded; - configuration._fillOpacityOccluded = _fillOpacityOccluded; - configuration._threshold = _threshold; - configuration._blurKernelSize = _blurKernelSize; - configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x; - configuration._size.y = _size; - configuration._idColor = encodeIdToColor(0); + + for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) { + auto& groupConfig = configuration._groups[groupId]; + + groupConfig._color = _color; + groupConfig._intensity = _intensity; + groupConfig._fillOpacityUnoccluded = _fillOpacityUnoccluded; + groupConfig._fillOpacityOccluded = _fillOpacityOccluded; + groupConfig._threshold = _threshold; + groupConfig._blurKernelSize = _blurKernelSize; + groupConfig._size.x = (_size * framebufferSize.y) / framebufferSize.x; + groupConfig._size.y = _size; + } _hasConfigurationChanged = false; } @@ -272,15 +278,15 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); + auto enabledGroupsLoc = pipeline->getProgram()->getUniforms().findLocation("enabledGroupsMask"); + batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); batch.setResourceTexture(OUTLINED_ID_SLOT, outlinedIdTexture); + batch._glUniform1i(enabledGroupsLoc, 1); batch.draw(gpu::TRIANGLE_STRIP, 4); - - // Restore previous frame buffer - batch.setFramebuffer(destinationFrameBuffer); }); } } diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index ce0b2917a4..6e4c0a18a8 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -94,9 +94,13 @@ signals: }; class DrawOutline { +private: + +#include "Outline_shared.slh" + public: enum { - MAX_GROUP_COUNT = 7 + MAX_GROUP_COUNT = GROUP_COUNT }; using Inputs = render::VaryingSet4; @@ -116,12 +120,14 @@ private: OUTLINED_ID_SLOT, OUTLINE_PARAMS_SLOT = 0, - FRAME_TRANSFORM_SLOT + FRAME_TRANSFORM_SLOT, }; -#include "Outline_shared.slh" + struct OutlineConfiguration { + OutlineParameters _groups[MAX_GROUP_COUNT]; + }; - using OutlineConfigurationBuffer = gpu::StructBuffer; + using OutlineConfigurationBuffer = gpu::StructBuffer; static const gpu::PipelinePointer& getPipeline(bool isFilled); diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index 5ce21c85b4..98d803c28b 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -9,6 +9,10 @@ # define VEC4 vec4 #endif +#define GROUP_COUNT 7 +#define GROUP_ID_COLOR_COMPONENT_BITS 2 +#define GROUP_ID_COLOR_COMPONENT_MAX 3 + struct OutlineParameters { VEC3 _color; @@ -18,8 +22,6 @@ struct OutlineParameters float _fillOpacityUnoccluded; float _fillOpacityOccluded; - VEC4 _idColor; - float _threshold; int _blurKernelSize; float padding2; From 9ed5185a3ea86e8be67dc3c5d698103694d1808d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 17 Oct 2017 10:01:06 +0200 Subject: [PATCH 027/171] Multiple outline group config working --- libraries/render-utils/src/Outline.slh | 2 +- libraries/render-utils/src/OutlineEffect.cpp | 71 ++++--- libraries/render-utils/src/OutlineEffect.h | 121 ++++++----- libraries/render-utils/src/Outline_shared.slh | 4 +- .../developer/utilities/render/outline.qml | 188 ++++++++++-------- 5 files changed, 234 insertions(+), 152 deletions(-) diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Outline.slh index c58d1c7689..bc71cabf1e 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Outline.slh @@ -53,7 +53,7 @@ vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2 sceneDepth = -evalZeyeFromZdb(sceneDepth); // Are we occluded? - intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._fillOpacityOccluded : groupParams._fillOpacityUnoccluded; + intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._occludedFillOpacity : groupParams._unoccludedFillOpacity; return vec4(groupParams._color.rgb, intensity); <@else@> return vec4(0,0,0,0); diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 2cb19826f4..74a29e8237 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -215,6 +215,17 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, outputs = _primaryWithoutDepthBuffer; } +int DrawOutlineConfig::getGroupCount() const { + return Outline::MAX_GROUP_COUNT; +} + +void DrawOutlineConfig::setGroup(int value) { + assert(value >= 0 && value < Outline::MAX_GROUP_COUNT); + group = std::min(value, Outline::MAX_GROUP_COUNT); + group = std::max(group, 0); + emit dirty(); +} + gpu::PipelinePointer DrawOutline::_pipeline; gpu::PipelinePointer DrawOutline::_pipelineFilled; @@ -222,15 +233,34 @@ DrawOutline::DrawOutline() { } void DrawOutline::configure(const Config& config) { - _color = config.color; - _blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width*2 + 0.5f))); - // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. - _size = config.width / 400.f; - _fillOpacityUnoccluded = config.fillOpacityUnoccluded; - _fillOpacityOccluded = config.fillOpacityOccluded; - _threshold = config.glow ? 1.f : 1e-3f; - _intensity = config.intensity * (config.glow ? 2.f : 1.f); - _hasConfigurationChanged = true; + auto& configuration = _configuration.edit(); + const auto OPACITY_EPSILON = 5e-3f; + + bool someFilled = false; + bool isFilled; + + for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) { + auto& dstGroupConfig = configuration._groups[groupId]; + auto& srcGroupConfig = config.groupParameters[groupId]; + + dstGroupConfig._color = srcGroupConfig.color; + dstGroupConfig._intensity = srcGroupConfig.intensity * (srcGroupConfig.glow ? 2.f : 1.f); + dstGroupConfig._unoccludedFillOpacity = srcGroupConfig.unoccludedFillOpacity; + dstGroupConfig._occludedFillOpacity = srcGroupConfig.occludedFillOpacity; + dstGroupConfig._threshold = srcGroupConfig.glow ? 1.f : 1e-3f; + dstGroupConfig._blurKernelSize = std::min(10, std::max(2, (int)floorf(srcGroupConfig.width * 2 + 0.5f))); + // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. + _sizes[groupId] = srcGroupConfig.width / 400.0f; + + isFilled = (srcGroupConfig.unoccludedFillOpacity > OPACITY_EPSILON || srcGroupConfig.occludedFillOpacity > OPACITY_EPSILON); + someFilled = someFilled || isFilled; + } + + if (someFilled) { + _mode = M_SOME_FILLED; + } else { + _mode = M_ALL_UNFILLED; + } } void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { @@ -245,27 +275,20 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); if (sceneDepthBuffer) { - const auto OPACITY_EPSILON = 5e-3f; - auto pipeline = getPipeline(_fillOpacityUnoccluded>OPACITY_EPSILON || _fillOpacityOccluded>OPACITY_EPSILON); + auto pipeline = getPipeline(); auto args = renderContext->args; - if (_hasConfigurationChanged) + if (_framebufferSize != framebufferSize) { auto& configuration = _configuration.edit(); for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) { auto& groupConfig = configuration._groups[groupId]; - groupConfig._color = _color; - groupConfig._intensity = _intensity; - groupConfig._fillOpacityUnoccluded = _fillOpacityUnoccluded; - groupConfig._fillOpacityOccluded = _fillOpacityOccluded; - groupConfig._threshold = _threshold; - groupConfig._blurKernelSize = _blurKernelSize; - groupConfig._size.x = (_size * framebufferSize.y) / framebufferSize.x; - groupConfig._size.y = _size; + groupConfig._size.x = (_sizes[groupId] * framebufferSize.y) / framebufferSize.x; + groupConfig._size.y = _sizes[groupId]; } - _hasConfigurationChanged = false; + _framebufferSize = framebufferSize; } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { @@ -292,7 +315,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I } } -const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) { +const gpu::PipelinePointer& DrawOutline::getPipeline() { if (!_pipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); @@ -316,7 +339,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(bool isFilled) { gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); } - return isFilled ? _pipelineFilled : _pipeline; + return _mode == M_SOME_FILLED ? _pipelineFilled : _pipeline; } DebugOutline::DebugOutline() { @@ -480,7 +503,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende } DrawOutlineMask::Groups sortedBounds; - for (auto i = 0; i < DrawOutline::MAX_GROUP_COUNT; i++) { + for (auto i = 0; i < Outline::MAX_GROUP_COUNT; i++) { const auto groupItems = groups[i]; const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs, true); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index 6e4c0a18a8..bc10fc5e41 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -60,41 +60,8 @@ private: }; -class DrawOutlineConfig : public render::Job::Config { - Q_OBJECT - Q_PROPERTY(bool glow MEMBER glow NOTIFY dirty) - Q_PROPERTY(float width MEMBER width NOTIFY dirty) - Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) - Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty) - Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty) - Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty) - Q_PROPERTY(float fillOpacityUnoccluded MEMBER fillOpacityUnoccluded NOTIFY dirty) - Q_PROPERTY(float fillOpacityOccluded MEMBER fillOpacityOccluded NOTIFY dirty) - -public: - - void setColorR(float value) { color.r = value; emit dirty(); } - float getColorR() const { return color.r; } - - void setColorG(float value) { color.g = value; emit dirty(); } - float getColorG() const { return color.g; } - - void setColorB(float value) { color.b = value; emit dirty(); } - float getColorB() const { return color.b; } - - glm::vec3 color{ 1.f, 0.7f, 0.2f }; - float width{ 2.0f }; - float intensity{ 0.9f }; - float fillOpacityUnoccluded{ 0.0f }; - float fillOpacityOccluded{ 0.0f }; - bool glow{ false }; - -signals: - void dirty(); -}; - -class DrawOutline { -private: +class Outline { +protected: #include "Outline_shared.slh" @@ -102,6 +69,68 @@ public: enum { MAX_GROUP_COUNT = GROUP_COUNT }; +}; + +class DrawOutlineConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int group MEMBER group WRITE setGroup NOTIFY dirty); + Q_PROPERTY(bool glow READ isGlow WRITE setGlow NOTIFY dirty) + Q_PROPERTY(float width READ getWidth WRITE setWidth NOTIFY dirty) + Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty) + Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty) + Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty) + Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty) + Q_PROPERTY(float unoccludedFillOpacity READ getUnoccludedFillOpacity WRITE setUnoccludedFillOpacity NOTIFY dirty) + Q_PROPERTY(float occludedFillOpacity READ getOccludedFillOpacity WRITE setOccludedFillOpacity NOTIFY dirty) + +public: + + struct GroupParameters { + glm::vec3 color{ 1.f, 0.7f, 0.2f }; + float width{ 2.0f }; + float intensity{ 0.9f }; + float unoccludedFillOpacity{ 0.0f }; + float occludedFillOpacity{ 0.0f }; + bool glow{ false }; + }; + + int getGroupCount() const; + + void setColorR(float value) { groupParameters[group].color.r = value; emit dirty(); } + float getColorR() const { return groupParameters[group].color.r; } + + void setColorG(float value) { groupParameters[group].color.g = value; emit dirty(); } + float getColorG() const { return groupParameters[group].color.g; } + + void setColorB(float value) { groupParameters[group].color.b = value; emit dirty(); } + float getColorB() const { return groupParameters[group].color.b; } + + void setGlow(bool value) { groupParameters[group].glow = value; emit dirty(); } + bool isGlow() const { return groupParameters[group].glow; } + + void setWidth(float value) { groupParameters[group].width = value; emit dirty(); } + float getWidth() const { return groupParameters[group].width; } + + void setIntensity(float value) { groupParameters[group].intensity = value; emit dirty(); } + float getIntensity() const { return groupParameters[group].intensity; } + + void setUnoccludedFillOpacity(float value) { groupParameters[group].unoccludedFillOpacity = value; emit dirty(); } + float getUnoccludedFillOpacity() const { return groupParameters[group].unoccludedFillOpacity; } + + void setOccludedFillOpacity(float value) { groupParameters[group].occludedFillOpacity = value; emit dirty(); } + float getOccludedFillOpacity() const { return groupParameters[group].occludedFillOpacity; } + + void setGroup(int value); + + int group{ 0 }; + GroupParameters groupParameters[Outline::MAX_GROUP_COUNT]; + +signals: + void dirty(); +}; + +class DrawOutline : public Outline { +public: using Inputs = render::VaryingSet4; using Config = DrawOutlineConfig; @@ -127,27 +156,27 @@ private: OutlineParameters _groups[MAX_GROUP_COUNT]; }; + enum Mode { + M_ALL_UNFILLED, + M_SOME_FILLED, + }; + using OutlineConfigurationBuffer = gpu::StructBuffer; - static const gpu::PipelinePointer& getPipeline(bool isFilled); + const gpu::PipelinePointer& getPipeline(); static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; OutlineConfigurationBuffer _configuration; - glm::vec3 _color; - float _size; - int _blurKernelSize; - float _intensity; - float _fillOpacityUnoccluded; - float _fillOpacityOccluded; - float _threshold; - bool _hasConfigurationChanged{ true }; + glm::ivec2 _framebufferSize{ 0,0 }; + Mode _mode{ M_ALL_UNFILLED }; + float _sizes[MAX_GROUP_COUNT]; }; class DrawOutlineTask { public: - using Groups = render::VaryingArray; + using Groups = render::VaryingArray; using Inputs = render::VaryingSet4; using Config = render::Task::Config; using JobModel = render::Task::ModelI; @@ -165,7 +194,7 @@ private: class DrawOutlineMask { public: - using Groups = render::VaryingArray; + using Groups = render::VaryingArray; using Inputs = render::VaryingSet2; // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer using Outputs = OutlineRessourcesPointer; diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index 98d803c28b..bda67c49d6 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -19,8 +19,8 @@ struct OutlineParameters float _intensity; VEC2 _size; - float _fillOpacityUnoccluded; - float _fillOpacityOccluded; + float _unoccludedFillOpacity; + float _occludedFillOpacity; float _threshold; int _blurKernelSize; diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 1b5cbf6e1c..1270c696d1 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -20,6 +20,24 @@ Item { Column { spacing: 8 + ComboBox { + id: groupBox + model: ["Group 0", "Group 1", "Group 2", "Group 3", "Group 4"] + Timer { + id: postpone + interval: 100; running: false; repeat: false + onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets } + } + onCurrentIndexChanged: { + // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // by setting the loader source to Null and then recreate it 100ms later + root.drawConfig["group"] = currentIndex + paramWidgetLoader.sourceComponent = undefined; + postpone.interval = 100 + postpone.start() + } + } + CheckBox { text: "View Mask" checked: root.debugConfig["viewMask"] @@ -27,93 +45,105 @@ Item { root.debugConfig["viewMask"] = checked; } } - CheckBox { - text: "Glow" - checked: root.drawConfig["glow"] - onCheckedChanged: { - root.drawConfig["glow"] = checked; - } - } - ConfigSlider { - label: "Width" - integral: false - config: root.drawConfig - property: "width" - max: 15.0 - min: 0.0 - width: 280 - } - ConfigSlider { - label: "Intensity" - integral: false - config: root.drawConfig - property: "intensity" - max: 1.0 - min: 0.0 - width: 280 - } - GroupBox { - title: "Color" - width: 280 + Component { + id: paramWidgets Column { spacing: 8 + CheckBox { + text: "Glow" + checked: root.drawConfig["glow"] + onCheckedChanged: { + drawConfig["glow"] = checked; + } + } + ConfigSlider { + label: "Width" + integral: false + config: root.drawConfig + property: "width" + max: 15.0 + min: 0.0 + width: 280 + } + ConfigSlider { + label: "Intensity" + integral: false + config: root.drawConfig + property: "intensity" + max: 1.0 + min: 0.0 + width: 280 + } - ConfigSlider { - label: "Red" - integral: false - config: root.drawConfig - property: "colorR" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Green" - integral: false - config: root.drawConfig - property: "colorG" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Blue" - integral: false - config: root.drawConfig - property: "colorB" - max: 1.0 - min: 0.0 - width: 270 + GroupBox { + title: "Color" + width: 280 + Column { + spacing: 8 + + ConfigSlider { + label: "Red" + integral: false + config: root.drawConfig + property: "colorR" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Green" + integral: false + config: root.drawConfig + property: "colorG" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Blue" + integral: false + config: root.drawConfig + property: "colorB" + max: 1.0 + min: 0.0 + width: 270 + } + } + } + + GroupBox { + title: "Fill Opacity" + width: 280 + Column { + spacing: 8 + + ConfigSlider { + label: "Unoccluded" + integral: false + config: root.drawConfig + property: "fillOpacityUnoccluded" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Occluded" + integral: false + config: root.drawConfig + property: "fillOpacityOccluded" + max: 1.0 + min: 0.0 + width: 270 + } + } } } } - GroupBox { - title: "Fill Opacity" - width: 280 - Column { - spacing: 8 - - ConfigSlider { - label: "Unoccluded" - integral: false - config: root.drawConfig - property: "fillOpacityUnoccluded" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Occluded" - integral: false - config: root.drawConfig - property: "fillOpacityOccluded" - max: 1.0 - min: 0.0 - width: 270 - } - } + Loader { + id: paramWidgetLoader + sourceComponent: paramWidgets } } } From 76589316dfef0f308355fc7a387ce6a4b20b7982 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 17 Oct 2017 10:24:05 +0200 Subject: [PATCH 028/171] Working debug script with multiple selection --- .../src/ui/overlays/ContextOverlayInterface.h | 2 +- .../utilities/render/debugOutline.js | 99 ++++++++++++++++++- .../developer/utilities/render/outline.qml | 4 +- 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index 2a96ea3d3e..28e3707f99 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -49,7 +49,7 @@ class ContextOverlayInterface : public QObject, public Dependency { public: enum { - MAX_HIGHLIGHT_COUNT = 4 + MAX_HIGHLIGHT_COUNT = 5 }; ContextOverlayInterface(); diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index e333ab5869..ac75197933 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -17,4 +17,101 @@ var window = new OverlayWindow({ width: 285, height: 370, }); -window.closed.connect(function() { Script.stop(); }); \ No newline at end of file +window.closed.connect(function() { Script.stop(); }); + +"use strict"; + +// Created by Sam Gondelman on 9/7/2017 +// 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 + +var END_DIMENSIONS = { + x: 0.15, + y: 0.15, + z: 0.15 +}; +var COLOR = {red: 97, green: 247, blue: 255}; +var end = { + type: "sphere", + dimensions: END_DIMENSIONS, + color: COLOR, + ignoreRayIntersection: true, + alpha: 1.0, + visible: true +} + +var COLOR2 = {red: 247, green: 97, blue: 255}; +var end2 = { + type: "sphere", + dimensions: END_DIMENSIONS, + color: COLOR2, + ignoreRayIntersection: true, + alpha: 1.0, + visible: true +} + +var renderStates = [{name: "test", end: end}]; +var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}]; + +var ray = LaserPointers.createLaserPointer({ + joint: "Mouse", + filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS | RayPick.PICK_AVATARS | RayPick.PICK_INVISIBLE | RayPick.PICK_NONCOLLIDABLE, + renderStates: renderStates, + defaultRenderStates: defaultRenderStates, + enabled: true +}); + +function cleanup() { + LaserPointers.removeLaserPointer(ray); +} +Script.scriptEnding.connect(cleanup); + +var prevID = 0; +var prevType = ""; +function update() { + // you have to do this repeatedly because there's a bug but I'll fix it + LaserPointers.setRenderState(ray, "test"); + + var result = LaserPointers.getPrevRayPickResult(ray); + var selectionName = "contextOverlayHighlightList" + var outlineGroupIndex = Render.getConfig("RenderMainView.OutlineEffect").group + + if (outlineGroupIndex>0) { + selectionName += outlineGroupIndex + } + + if (result.type != RayPick.INTERSECTED_NONE) { + if (result.objectID != prevID) { + if (prevID != 0) { + Selection.removeFromSelectedItemsList(selectionName, prevType, prevID) + } + + var typeName = "" + if (result.type == RayPick.INTERSECTED_ENTITY) { + typeName = "entity" + } else if (result.type == RayPick.INTERSECTED_OVERLAY) { + typeName = "overlay" + } else if (result.type == RayPick.INTERSECTED_AVATAR) { + typeName = "avatar" + } + + Selection.addToSelectedItemsList(selectionName, typeName, result.objectID) + //print("type: " + result.type + ", id: " + result.objectID); + + prevID = result.objectID; + prevType = typeName; + } + } else { + if (prevID != 0) { + Selection.removeFromSelectedItemsList(selectionName, prevType, prevID) + } + prevID = 0; + } +} +Script.update.connect(update); + +}()); // END LOCAL_SCOPE \ No newline at end of file diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 1270c696d1..d62e3b8899 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -122,7 +122,7 @@ Item { label: "Unoccluded" integral: false config: root.drawConfig - property: "fillOpacityUnoccluded" + property: "unoccludedFillOpacity" max: 1.0 min: 0.0 width: 270 @@ -131,7 +131,7 @@ Item { label: "Occluded" integral: false config: root.drawConfig - property: "fillOpacityOccluded" + property: "occludedFillOpacity" max: 1.0 min: 0.0 width: 270 From 25b3549e042f9e21438d0236c4610a641c4c5bb3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 18 Oct 2017 15:00:53 +0200 Subject: [PATCH 029/171] Working multiple outlines except debugging scripts which applies config to all outlines and graphics bug when filled --- .../ui/overlays/ContextOverlayInterface.cpp | 2 +- .../src/ui/overlays/ContextOverlayInterface.h | 6 +- libraries/render-utils/src/Outline.slh | 81 +--- libraries/render-utils/src/OutlineEffect.cpp | 423 ++++++------------ libraries/render-utils/src/OutlineEffect.h | 178 +++----- libraries/render-utils/src/Outline_shared.slh | 4 - .../render-utils/src/RenderDeferredTask.cpp | 2 +- libraries/render-utils/src/model_outline.slf | 21 - .../render-utils/src/model_outline_fade.slf | 31 -- libraries/render/src/render/Scene.h | 5 + .../utilities/render/debugOutline.js | 12 +- .../developer/utilities/render/outline.qml | 12 +- 12 files changed, 251 insertions(+), 526 deletions(-) delete mode 100644 libraries/render-utils/src/model_outline.slf delete mode 100644 libraries/render-utils/src/model_outline_fade.slf diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index f677dc6550..3a3026d5ae 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -36,7 +36,7 @@ ContextOverlayInterface::ContextOverlayInterface() { _selectionToSceneHandlers[0].initialize("contextOverlayHighlightList"); connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged); - for (auto i = 1; i < MAX_HIGHLIGHT_COUNT; i++) { + for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT ; i++) { _selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList")+QString::number(i)); connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged); } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index 28e3707f99..3d33d2a802 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -48,10 +48,6 @@ class ContextOverlayInterface : public QObject, public Dependency { std::shared_ptr _contextOverlay { nullptr }; public: - enum { - MAX_HIGHLIGHT_COUNT = 5 - }; - ContextOverlayInterface(); Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; } @@ -91,7 +87,7 @@ private: void deletingEntity(const EntityItemID& entityItemID); - SelectionToSceneHandler _selectionToSceneHandlers[MAX_HIGHLIGHT_COUNT]; + SelectionToSceneHandler _selectionToSceneHandlers[render::Scene::MAX_OUTLINE_COUNT]; }; #endif // hifi_ContextOverlayInterface_h diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Outline.slh index bc71cabf1e..fe9594cc12 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Outline.slh @@ -16,13 +16,11 @@ <@include Outline_shared.slh@> uniform outlineParamsBuffer { - OutlineParameters groups[GROUP_COUNT]; + OutlineParameters params; }; uniform sampler2D sceneDepthMap; uniform sampler2D outlinedDepthMap; -uniform sampler2D outlinedIdMap; -uniform int enabledGroupsMask; in vec2 varTexCoord0; out vec4 outFragColor; @@ -33,52 +31,47 @@ const float OPACITY_EPSILON = 5e-3; <@func main(IS_FILLED)@> -int getGroupIndexFromColor(vec4 color) { - ivec4 id = ivec4(color * GROUP_ID_COLOR_COMPONENT_MAX) << ivec4(0, GROUP_ID_COLOR_COMPONENT_BITS, GROUP_ID_COLOR_COMPONENT_BITS*2, GROUP_ID_COLOR_COMPONENT_BITS*3); - return (id.r | id.g | id.b | id.a) - 1; -} - -vec4 computeGroupOutline(int centerGroupId, float centerDepth, int groupId, vec2 texCoord) { +void main(void) { + // We offset by half a texel to be centered on the depth sample. If we don't do this + // the blur will have a different width between the left / right sides and top / bottom + // sides of the silhouette + vec2 halfTexel = getInvWidthHeight() / 2; + vec2 texCoord0 = varTexCoord0+halfTexel; + float outlinedDepth = texture(outlinedDepthMap, texCoord0).x; float intensity = 0.0; - if (centerGroupId==groupId && centerDepth < FAR_Z) { - // We're on the outlined object, thus no outline to do! + if (outlinedDepth < FAR_Z) { + // We're not on the far plane so we are on the outlined object, thus no outline to do! <@if IS_FILLED@> - OutlineParameters groupParams = groups[groupId]; - // But we need to fill the interior - float sceneDepth = texture(sceneDepthMap, texCoord).x; + float sceneDepth = texture(sceneDepthMap, texCoord0).x; // Transform to linear depth for better precision - centerDepth = -evalZeyeFromZdb(centerDepth); + outlinedDepth = -evalZeyeFromZdb(outlinedDepth); sceneDepth = -evalZeyeFromZdb(sceneDepth); // Are we occluded? - intensity = (sceneDepth < (centerDepth-LINEAR_DEPTH_BIAS)) ? groupParams._occludedFillOpacity : groupParams._unoccludedFillOpacity; - return vec4(groupParams._color.rgb, intensity); + intensity = sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity; <@else@> - return vec4(0,0,0,0); + discard; <@endif@> } else { - OutlineParameters groupParams = groups[groupId]; float weight = 0.0; - vec2 deltaUv = groupParams._size / groupParams._blurKernelSize; - vec2 lineStartUv = texCoord - groupParams._size / 2.0; + vec2 deltaUv = params._size / params._blurKernelSize; + vec2 lineStartUv = texCoord0 - params._size / 2.0; vec2 uv; int x; int y; - for (y=0 ; y=0.0 && uv.y<=1.0) { - for (x=0 ; x=0.0 && uv.x<=1.0) { - vec4 outlinedIdColor = texture(outlinedIdMap, uv); - float outlinedDepth = texture(outlinedDepthMap, uv).x; - int outlinedId = getGroupIndexFromColor(outlinedIdColor); - intensity += (outlinedDepth diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 74a29e8237..d00819d0f2 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -18,6 +18,7 @@ #include "gpu/Context.h" #include "gpu/StandardShaderLib.h" +#include #include "surfaceGeometry_copyDepth_frag.h" #include "debug_deferred_buffer_vert.h" @@ -30,22 +31,29 @@ using namespace render; OutlineRessources::OutlineRessources() { } -void OutlineRessources::update(const gpu::TexturePointer& colorBuffer) { +void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { + auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize()); + // If the depth buffer or size changed, we need to delete our FBOs and recreate them at the // new correct dimensions. - if (_depthTexture) { - auto newFrameSize = glm::ivec2(colorBuffer->getDimensions()); + if (_depthFrameBuffer) { if (_frameSize != newFrameSize) { _frameSize = newFrameSize; clear(); } } + if (!_colorFrameBuffer) { + if (_frameSize != newFrameSize) { + _frameSize = newFrameSize; + // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac + _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); + _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); + } + } } void OutlineRessources::clear() { - _frameBuffer.reset(); - _depthTexture.reset(); - _idTexture.reset(); + _depthFrameBuffer.reset(); } void OutlineRessources::allocate() { @@ -53,177 +61,95 @@ void OutlineRessources::allocate() { auto width = _frameSize.x; auto height = _frameSize.y; auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - - _idTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_2, width, height)); - _depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height)); + auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height)); - _frameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); - _frameBuffer->setDepthStencilBuffer(_depthTexture, depthFormat); - _frameBuffer->setRenderBuffer(0, _idTexture); + _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); + _depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat); } -gpu::FramebufferPointer OutlineRessources::getFramebuffer() { - if (!_frameBuffer) { +gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { + if (!_depthFrameBuffer) { allocate(); } - return _frameBuffer; + return _depthFrameBuffer; } gpu::TexturePointer OutlineRessources::getDepthTexture() { - if (!_depthTexture) { - allocate(); - } - return _depthTexture; -} - -gpu::TexturePointer OutlineRessources::getIdTexture() { - if (!_idTexture) { - allocate(); - } - return _idTexture; -} - -glm::vec4 encodeIdToColor(unsigned int id) { - union { - struct { - unsigned int r : 2; - unsigned int g : 2; - unsigned int b : 2; - unsigned int a : 2; - }; - unsigned char id; - } groupId; - - static_assert(GROUP_ID_COLOR_COMPONENT_BITS == 2, "Assuming two bits per component contrary to GLSL shader code. See Outline_shared.slh"); - - assert(id < 254); - groupId.id = id+1; - - glm::vec4 idColor{ groupId.r, groupId.g, groupId.b, groupId.a }; - - // Normalize. Since we put 2 bits into each color component, each component has a maximum - // value of 3. - idColor /= GROUP_ID_COLOR_COMPONENT_MAX; - return idColor; -} - -void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output) { - assert(renderContext->args); - assert(renderContext->args->hasViewFrustum()); - auto& groups = inputs.get0(); - auto& deferredFrameBuffer = inputs.get1(); - - RenderArgs* args = renderContext->args; - ShapeKey::Builder defaultKeyBuilder; - auto hasOutline = false; - - if (!_outlineRessources) { - _outlineRessources = std::make_shared(); - } - _outlineRessources->update(deferredFrameBuffer->getDeferredColorTexture()); - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - args->_batch = &batch; - - auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); - auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); - auto colorLoc = maskPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); - auto skinnedColorLoc = maskSkinnedPipeline.get()->pipeline->getProgram()->getUniforms().findLocation("color"); - unsigned int groupId = 0; - - for (auto& inShapeBounds : groups) { - if (!inShapeBounds.isNull()) { - auto& inShapes = inShapeBounds.get(); - - if (!inShapes.empty()) { - if (!hasOutline) { - batch.setFramebuffer(_outlineRessources->getFramebuffer()); - // Clear it only if it hasn't been done before - batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, - vec4(0.0f, 0.0f, 0.0f, 0.0f), 1.0f, 0, false); - - // Setup camera, projection and viewport for all items - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - hasOutline = true; - } - - std::vector skinnedShapeKeys{}; - // Encode group id in quantized color - glm::vec4 idColor = encodeIdToColor(groupId); - - // Iterate through all inShapes and render the unskinned - args->_shapePipeline = maskPipeline; - batch.setPipeline(maskPipeline->pipeline); - batch._glUniform4f(colorLoc, idColor.r, idColor.g, idColor.b, idColor.a); - for (auto items : inShapes) { - if (items.first.isSkinned()) { - skinnedShapeKeys.push_back(items.first); - } else { - renderItems(renderContext, items.second); - } - } - - // Reiterate to render the skinned - args->_shapePipeline = maskSkinnedPipeline; - batch.setPipeline(maskSkinnedPipeline->pipeline); - batch._glUniform4f(skinnedColorLoc, idColor.r, idColor.g, idColor.b, idColor.a); - for (const auto& key : skinnedShapeKeys) { - renderItems(renderContext, inShapes.at(key)); - } - } - } - - ++groupId; - } - - args->_shapePipeline = nullptr; - args->_batch = nullptr; - }); - - if (hasOutline) { - output = _outlineRessources; - } else { - output = nullptr; - } + return getDepthFramebuffer()->getDepthStencilBuffer(); } PrepareDrawOutline::PrepareDrawOutline() { - + _ressources = std::make_shared(); } void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto destinationFrameBuffer = inputs; - auto framebufferSize = destinationFrameBuffer->getSize(); - if (!_primaryWithoutDepthBuffer || framebufferSize != _frameBufferSize) { - // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac - _primaryWithoutDepthBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); - _primaryWithoutDepthBuffer->setRenderBuffer(0, destinationFrameBuffer->getRenderBuffer(0)); - _frameBufferSize = framebufferSize; + _ressources->update(destinationFrameBuffer); + outputs = _ressources; +} + +void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + auto& inShapes = inputs.get0(); + + if (!inShapes.empty()) { + auto ressources = inputs.get1(); + + RenderArgs* args = renderContext->args; + ShapeKey::Builder defaultKeyBuilder; + + outputs = args->_viewport; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); + auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); + + batch.setFramebuffer(ressources->getDepthFramebuffer()); + batch.clearDepthFramebuffer(1.0f); + + // Setup camera, projection and viewport for all items + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + std::vector skinnedShapeKeys{}; + + // Iterate through all inShapes and render the unskinned + args->_shapePipeline = maskPipeline; + batch.setPipeline(maskPipeline->pipeline); + for (auto items : inShapes) { + if (items.first.isSkinned()) { + skinnedShapeKeys.push_back(items.first); + } else { + renderItems(renderContext, items.second); + } + } + + // Reiterate to render the skinned + args->_shapePipeline = maskSkinnedPipeline; + batch.setPipeline(maskSkinnedPipeline->pipeline); + for (const auto& key : skinnedShapeKeys) { + renderItems(renderContext, inShapes.at(key)); + } + + args->_shapePipeline = nullptr; + args->_batch = nullptr; + }); + } else { + // Outline rect should be null as there are no outlined shapes + outputs = glm::ivec4(0, 0, 0, 0); } - - outputs = _primaryWithoutDepthBuffer; -} - -int DrawOutlineConfig::getGroupCount() const { - return Outline::MAX_GROUP_COUNT; -} - -void DrawOutlineConfig::setGroup(int value) { - assert(value >= 0 && value < Outline::MAX_GROUP_COUNT); - group = std::min(value, Outline::MAX_GROUP_COUNT); - group = std::max(group, 0); - emit dirty(); } gpu::PipelinePointer DrawOutline::_pipeline; @@ -236,41 +162,28 @@ void DrawOutline::configure(const Config& config) { auto& configuration = _configuration.edit(); const auto OPACITY_EPSILON = 5e-3f; - bool someFilled = false; - bool isFilled; + configuration._color = config.color; + configuration._intensity = config.intensity * (config.glow ? 2.f : 1.f); + configuration._unoccludedFillOpacity = config.unoccludedFillOpacity; + configuration._occludedFillOpacity = config.occludedFillOpacity; + configuration._threshold = config.glow ? 1.f : 1e-3f; + configuration._blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width * 3 + 0.5f))); + // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. + _size = config.width / 400.0f; + configuration._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; + configuration._size.y = _size; - for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) { - auto& dstGroupConfig = configuration._groups[groupId]; - auto& srcGroupConfig = config.groupParameters[groupId]; - - dstGroupConfig._color = srcGroupConfig.color; - dstGroupConfig._intensity = srcGroupConfig.intensity * (srcGroupConfig.glow ? 2.f : 1.f); - dstGroupConfig._unoccludedFillOpacity = srcGroupConfig.unoccludedFillOpacity; - dstGroupConfig._occludedFillOpacity = srcGroupConfig.occludedFillOpacity; - dstGroupConfig._threshold = srcGroupConfig.glow ? 1.f : 1e-3f; - dstGroupConfig._blurKernelSize = std::min(10, std::max(2, (int)floorf(srcGroupConfig.width * 2 + 0.5f))); - // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. - _sizes[groupId] = srcGroupConfig.width / 400.0f; - - isFilled = (srcGroupConfig.unoccludedFillOpacity > OPACITY_EPSILON || srcGroupConfig.occludedFillOpacity > OPACITY_EPSILON); - someFilled = someFilled || isFilled; - } - - if (someFilled) { - _mode = M_SOME_FILLED; - } else { - _mode = M_ALL_UNFILLED; - } + _isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON); } void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { auto outlineFrameBuffer = inputs.get1(); + auto outlineRect = inputs.get4(); - if (outlineFrameBuffer) { + if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture(); - auto outlinedIdTexture = outlineFrameBuffer->getIdTexture(); auto destinationFrameBuffer = inputs.get3(); auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); @@ -281,13 +194,8 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I if (_framebufferSize != framebufferSize) { auto& configuration = _configuration.edit(); - - for (auto groupId = 0; groupId < MAX_GROUP_COUNT; groupId++) { - auto& groupConfig = configuration._groups[groupId]; - - groupConfig._size.x = (_sizes[groupId] * framebufferSize.y) / framebufferSize.x; - groupConfig._size.y = _sizes[groupId]; - } + configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x; + configuration._size.y = _size; _framebufferSize = framebufferSize; } @@ -301,14 +209,10 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); - auto enabledGroupsLoc = pipeline->getProgram()->getUniforms().findLocation("enabledGroupsMask"); - batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); - batch.setResourceTexture(OUTLINED_ID_SLOT, outlinedIdTexture); - batch._glUniform1i(enabledGroupsLoc, 1); batch.draw(gpu::TRIANGLE_STRIP, 4); }); } @@ -326,7 +230,6 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT)); slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT)); slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT)); - slotBindings.insert(gpu::Shader::Binding("outlinedIdMap", OUTLINED_ID_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -339,19 +242,17 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); } - return _mode == M_SOME_FILLED ? _pipelineFilled : _pipeline; + return _isFilled ? _pipelineFilled : _pipeline; } DebugOutline::DebugOutline() { _geometryDepthId = DependencyManager::get()->allocateID(); - _geometryColorId = DependencyManager::get()->allocateID(); } DebugOutline::~DebugOutline() { auto geometryCache = DependencyManager::get(); if (geometryCache) { geometryCache->releaseID(_geometryDepthId); - geometryCache->releaseID(_geometryColorId); } } @@ -360,9 +261,9 @@ void DebugOutline::configure(const Config& config) { } void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) { - const auto outlineFramebuffer = input; + const auto outlineRessources = input; - if (_isDisplayEnabled && outlineFramebuffer) { + if (_isDisplayEnabled && outlineRessources) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; @@ -384,20 +285,10 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); batch.setPipeline(getDepthPipeline()); - batch.setResourceTexture(0, outlineFramebuffer->getDepthTexture()); - { - const glm::vec2 bottomLeft(-1.0f, -1.0f); - const glm::vec2 topRight(0.0f, 1.0f); - geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId); - } - - batch.setPipeline(getIdPipeline()); - batch.setResourceTexture(0, outlineFramebuffer->getIdTexture()); - { - const glm::vec2 bottomLeft(0.0f, -1.0f); - const glm::vec2 topRight(1.0f, 1.0f); - geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryColorId); - } + batch.setResourceTexture(0, outlineRessources->getDepthTexture()); + const glm::vec2 bottomLeft(-1.0f, -1.0f); + const glm::vec2 topRight(1.0f, 1.0f); + geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId); batch.setResourceTexture(0, nullptr); }); @@ -439,27 +330,6 @@ void DebugOutline::initializePipelines() { _depthPipeline = gpu::Pipeline::create(program, state); } - - // ID shader - { - static const std::string ID_SHADER{ - "vec4 getFragmentColor() {" - " return texelFetch(albedoMap, ivec2(gl_FragCoord.xy), 0); " - "}" - }; - - auto fragmentShader = FRAGMENT_SHADER; - fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), ID_SHADER); - - const auto ps = gpu::Shader::createPixel(fragmentShader); - const auto program = gpu::Shader::createProgram(vs, ps); - - gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding("albedoMap", 0)); - gpu::Shader::makeProgram(*program, slotBindings); - - _idPipeline = gpu::Pipeline::create(program, state); - } } const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { @@ -470,14 +340,6 @@ const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { return _depthPipeline; } -const gpu::PipelinePointer& DebugOutline::getIdPipeline() { - if (!_idPipeline) { - initializePipelines(); - } - - return _idPipeline; -} - DrawOutlineTask::DrawOutlineTask() { } @@ -496,70 +358,63 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende ShapePlumberPointer shapePlumber = std::make_shared(); { auto state = std::make_shared(); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setColorWriteMask(true, true, true, true); - + state->setDepthTest(true, true, gpu::LESS); + state->setColorWriteMask(false, false, false, false); initMaskPipelines(*shapePlumber, state); } - DrawOutlineMask::Groups sortedBounds; - for (auto i = 0; i < Outline::MAX_GROUP_COUNT; i++) { + // Prepare for outline group rendering. + const auto outlineRessources = task.addJob("PrepareOutline", primaryFramebuffer); + + for (auto i = 0; i < render::Scene::MAX_OUTLINE_COUNT; i++) { const auto groupItems = groups[i]; const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs, true); // Sort const auto sortedPipelines = task.addJob("OutlinePipelineSort", outlinedItems); - sortedBounds[i] = task.addJob("OutlineDepthSort", sortedPipelines); + const auto sortedBounds = task.addJob("OutlineDepthSort", sortedPipelines); + + // Draw depth of outlined objects in separate buffer + std::string name; + { + std::ostringstream stream; + stream << "OutlineMask" << i; + name = stream.str(); + } + const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, outlineRessources).asVarying(); + const auto outlinedRect = task.addJob(name, drawMaskInputs, shapePlumber); + + // Draw outline + { + std::ostringstream stream; + stream << "OutlineEffect" << i; + name = stream.str(); + } + const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, primaryFramebuffer, outlinedRect).asVarying(); + task.addJob(name, drawOutlineInputs); } - // Draw depth of outlined objects in separate buffer - const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, sceneFrameBuffer).asVarying(); - const auto outlinedFrameBuffer = task.addJob("OutlineMask", drawMaskInputs, shapePlumber); - - // Prepare for outline group rendering. - const auto destFrameBuffer = task.addJob("PrepareOutline", primaryFramebuffer); - - // Draw outline - const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlinedFrameBuffer, sceneFrameBuffer, destFrameBuffer).asVarying(); - task.addJob("OutlineEffect", drawOutlineInputs); - // Debug outline - task.addJob("OutlineDebug", outlinedFrameBuffer); + task.addJob("OutlineDebug", outlineRessources); } #include "model_shadow_vert.h" -#include "model_shadow_fade_vert.h" #include "skin_model_shadow_vert.h" -#include "skin_model_shadow_fade_vert.h" -#include "model_outline_frag.h" -#include "model_outline_fade_frag.h" +#include "model_shadow_frag.h" void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto modelPixel = gpu::Shader::createPixel(std::string(model_outline_frag)); + auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withoutSkinned().withoutFade(), + ShapeKey::Filter::Builder().withoutSkinned(), modelProgram, state); auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel); shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withSkinned().withoutFade(), + ShapeKey::Filter::Builder().withSkinned(), skinProgram, state); - - auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); - auto modelFadePixel = gpu::Shader::createPixel(std::string(model_outline_fade_frag)); - gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel); - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withoutSkinned().withFade(), - modelFadeProgram, state); - - auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); - gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, modelFadePixel); - shapePlumber.addPipeline( - ShapeKey::Filter::Builder().withSkinned().withFade(), - skinFadeProgram, state); } diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index bc10fc5e41..b1c2e3c3dd 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -20,12 +20,13 @@ class OutlineRessources { public: OutlineRessources(); - gpu::FramebufferPointer getFramebuffer(); - gpu::TexturePointer getIdTexture(); + gpu::FramebufferPointer getDepthFramebuffer(); gpu::TexturePointer getDepthTexture(); + gpu::FramebufferPointer getColorFramebuffer() { return _colorFrameBuffer; } + // Update the source framebuffer size which will drive the allocation of all the other resources. - void update(const gpu::TexturePointer& colorBuffer); + void update(const gpu::FramebufferPointer& primaryFrameBuffer); const glm::ivec2& getSourceFrameSize() const { return _frameSize; } protected: @@ -33,9 +34,8 @@ protected: void clear(); void allocate(); - gpu::FramebufferPointer _frameBuffer; - gpu::TexturePointer _depthTexture; - gpu::TexturePointer _idTexture; + gpu::FramebufferPointer _depthFrameBuffer; + gpu::FramebufferPointer _colorFrameBuffer; glm::ivec2 _frameSize; }; @@ -45,9 +45,8 @@ using OutlineRessourcesPointer = std::shared_ptr; class PrepareDrawOutline { public: using Inputs = gpu::FramebufferPointer; - using Outputs = gpu::FramebufferPointer; - using Config = render::Job::Config; - using JobModel = render::Job::ModelIO; + using Outputs = OutlineRessourcesPointer; + using JobModel = render::Job::ModelIO; PrepareDrawOutline(); @@ -55,84 +54,63 @@ public: private: - gpu::FramebufferPointer _primaryWithoutDepthBuffer; - gpu::Vec2u _frameBufferSize{ 0, 0 }; + OutlineRessourcesPointer _ressources; }; -class Outline { +class DrawOutlineMask { +public: + + using Inputs = render::VaryingSet2; + using Outputs = glm::ivec4; + using JobModel = render::Job::ModelIO; + + DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + protected: -#include "Outline_shared.slh" - -public: - enum { - MAX_GROUP_COUNT = GROUP_COUNT - }; + render::ShapePlumberPointer _shapePlumber; }; class DrawOutlineConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int group MEMBER group WRITE setGroup NOTIFY dirty); - Q_PROPERTY(bool glow READ isGlow WRITE setGlow NOTIFY dirty) - Q_PROPERTY(float width READ getWidth WRITE setWidth NOTIFY dirty) - Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty) + Q_PROPERTY(bool glow MEMBER glow NOTIFY dirty) + Q_PROPERTY(float width MEMBER width NOTIFY dirty) + Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty) Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty) Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty) - Q_PROPERTY(float unoccludedFillOpacity READ getUnoccludedFillOpacity WRITE setUnoccludedFillOpacity NOTIFY dirty) - Q_PROPERTY(float occludedFillOpacity READ getOccludedFillOpacity WRITE setOccludedFillOpacity NOTIFY dirty) + Q_PROPERTY(float unoccludedFillOpacity MEMBER unoccludedFillOpacity NOTIFY dirty) + Q_PROPERTY(float occludedFillOpacity MEMBER occludedFillOpacity NOTIFY dirty) public: - struct GroupParameters { - glm::vec3 color{ 1.f, 0.7f, 0.2f }; - float width{ 2.0f }; - float intensity{ 0.9f }; - float unoccludedFillOpacity{ 0.0f }; - float occludedFillOpacity{ 0.0f }; - bool glow{ false }; - }; + void setColorR(float value) { color.r = value; emit dirty(); } + float getColorR() const { return color.r; } - int getGroupCount() const; + void setColorG(float value) { color.g = value; emit dirty(); } + float getColorG() const { return color.g; } - void setColorR(float value) { groupParameters[group].color.r = value; emit dirty(); } - float getColorR() const { return groupParameters[group].color.r; } + void setColorB(float value) { color.b = value; emit dirty(); } + float getColorB() const { return color.b; } - void setColorG(float value) { groupParameters[group].color.g = value; emit dirty(); } - float getColorG() const { return groupParameters[group].color.g; } - - void setColorB(float value) { groupParameters[group].color.b = value; emit dirty(); } - float getColorB() const { return groupParameters[group].color.b; } - - void setGlow(bool value) { groupParameters[group].glow = value; emit dirty(); } - bool isGlow() const { return groupParameters[group].glow; } - - void setWidth(float value) { groupParameters[group].width = value; emit dirty(); } - float getWidth() const { return groupParameters[group].width; } - - void setIntensity(float value) { groupParameters[group].intensity = value; emit dirty(); } - float getIntensity() const { return groupParameters[group].intensity; } - - void setUnoccludedFillOpacity(float value) { groupParameters[group].unoccludedFillOpacity = value; emit dirty(); } - float getUnoccludedFillOpacity() const { return groupParameters[group].unoccludedFillOpacity; } - - void setOccludedFillOpacity(float value) { groupParameters[group].occludedFillOpacity = value; emit dirty(); } - float getOccludedFillOpacity() const { return groupParameters[group].occludedFillOpacity; } - - void setGroup(int value); - - int group{ 0 }; - GroupParameters groupParameters[Outline::MAX_GROUP_COUNT]; + glm::vec3 color{ 1.f, 0.7f, 0.2f }; + float width{ 2.0f }; + float intensity{ 0.9f }; + float unoccludedFillOpacity{ 0.0f }; + float occludedFillOpacity{ 0.0f }; + bool glow{ false }; signals: void dirty(); }; -class DrawOutline : public Outline { +class DrawOutline { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet5; using Config = DrawOutlineConfig; using JobModel = render::Job::ModelI; @@ -143,71 +121,27 @@ public: private: +#include "Outline_shared.slh" + enum { SCENE_DEPTH_SLOT = 0, OUTLINED_DEPTH_SLOT, - OUTLINED_ID_SLOT, OUTLINE_PARAMS_SLOT = 0, FRAME_TRANSFORM_SLOT, }; - struct OutlineConfiguration { - OutlineParameters _groups[MAX_GROUP_COUNT]; - }; - - enum Mode { - M_ALL_UNFILLED, - M_SOME_FILLED, - }; - - using OutlineConfigurationBuffer = gpu::StructBuffer; + using OutlineConfigurationBuffer = gpu::StructBuffer; const gpu::PipelinePointer& getPipeline(); static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; + OutlineConfigurationBuffer _configuration; glm::ivec2 _framebufferSize{ 0,0 }; - Mode _mode{ M_ALL_UNFILLED }; - float _sizes[MAX_GROUP_COUNT]; -}; - -class DrawOutlineTask { -public: - - using Groups = render::VaryingArray; - using Inputs = render::VaryingSet4; - using Config = render::Task::Config; - using JobModel = render::Task::ModelI; - - DrawOutlineTask(); - - void configure(const Config& config); - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); - -private: - - static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); -}; - -class DrawOutlineMask { -public: - - using Groups = render::VaryingArray; - using Inputs = render::VaryingSet2; - // Output will contain outlined objects only z-depth texture and the input primary buffer but without the primary depth buffer - using Outputs = OutlineRessourcesPointer; - using JobModel = render::Job::ModelIO; - - DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - - void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& output); - -protected: - - render::ShapePlumberPointer _shapePlumber; - OutlineRessourcesPointer _outlineRessources; + bool _isFilled{ false }; + float _size; }; class DebugOutlineConfig : public render::Job::Config { @@ -237,16 +171,30 @@ public: private: gpu::PipelinePointer _depthPipeline; - gpu::PipelinePointer _idPipeline; int _geometryDepthId{ 0 }; - int _geometryColorId{ 0 }; bool _isDisplayEnabled{ false }; const gpu::PipelinePointer& getDepthPipeline(); - const gpu::PipelinePointer& getIdPipeline(); void initializePipelines(); }; +class DrawOutlineTask { +public: + + using Groups = render::VaryingArray; + using Inputs = render::VaryingSet4; + using Config = render::Task::Config; + using JobModel = render::Task::ModelI; + + DrawOutlineTask(); + + void configure(const Config& config); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); + +private: + + static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); +}; #endif // hifi_render_utils_OutlineEffect_h diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index bda67c49d6..2ebece8903 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -9,10 +9,6 @@ # define VEC4 vec4 #endif -#define GROUP_COUNT 7 -#define GROUP_ID_COLOR_COMPONENT_BITS 2 -#define GROUP_ID_COLOR_COMPONENT_MAX 3 - struct OutlineParameters { VEC3 _color; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 73d8b93c07..54c2248d8b 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -181,7 +181,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); DrawOutlineTask::Groups outlineGroups; outlineGroups[0] = selectedItems; - for (auto i = 1; i < DrawOutline::MAX_GROUP_COUNT; i++) { + for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) { std::ostringstream selectionName; selectionName << selectionBaseName; selectionName << i; diff --git a/libraries/render-utils/src/model_outline.slf b/libraries/render-utils/src/model_outline.slf deleted file mode 100644 index 8c11b2b295..0000000000 --- a/libraries/render-utils/src/model_outline.slf +++ /dev/null @@ -1,21 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// model_outline.frag -// fragment shader -// -// Created by Olivier Prat on 10/13/17. -// 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 -// - -layout(location = 0) out vec4 _fragColor; - -uniform vec4 color; - -void main(void) { - _fragColor = color; -} diff --git a/libraries/render-utils/src/model_outline_fade.slf b/libraries/render-utils/src/model_outline_fade.slf deleted file mode 100644 index 69ff54dea6..0000000000 --- a/libraries/render-utils/src/model_outline_fade.slf +++ /dev/null @@ -1,31 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// model_outline_fade.frag -// fragment shader -// -// Created by Olivier Prat on 10/13/17. -// 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 -// - -<@include Fade.slh@> -<$declareFadeFragment()$> - -layout(location = 0) out vec4 _fragColor; - -uniform vec4 color; - -in vec4 _worldPosition; - -void main(void) { - FadeObjectParams fadeParams; - - <$fetchFadeObjectParams(fadeParams)$> - applyFadeClip(fadeParams, _worldPosition.xyz); - - _fragColor = color; -} diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index fef2077897..04a285bcd1 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -102,6 +102,11 @@ typedef std::queue TransactionQueue; // Items are notified accordingly on any update message happening class Scene { public: + + enum { + MAX_OUTLINE_COUNT = 16 + }; + Scene(glm::vec3 origin, float size); ~Scene(); diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index ac75197933..8e8a00f912 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -54,6 +54,15 @@ var end2 = { visible: true } +var outlineGroupIndex = 0 + +function setOutlineGroupIndex(index) { + print("Switching to outline group "+index) + outlineGroupIndex = index +} + +window.fromQml.connect(setOutlineGroupIndex); + var renderStates = [{name: "test", end: end}]; var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}]; @@ -78,7 +87,6 @@ function update() { var result = LaserPointers.getPrevRayPickResult(ray); var selectionName = "contextOverlayHighlightList" - var outlineGroupIndex = Render.getConfig("RenderMainView.OutlineEffect").group if (outlineGroupIndex>0) { selectionName += outlineGroupIndex @@ -100,7 +108,7 @@ function update() { } Selection.addToSelectedItemsList(selectionName, typeName, result.objectID) - //print("type: " + result.type + ", id: " + result.objectID); + print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); prevID = result.objectID; prevType = typeName; diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index d62e3b8899..1e19b2cac9 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -15,7 +15,8 @@ import "configSlider" Item { id: root property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug") - property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect") + property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect0") + signal sendToScript(var message); Column { spacing: 8 @@ -26,12 +27,15 @@ Item { Timer { id: postpone interval: 100; running: false; repeat: false - onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets } + onTriggered: { + paramWidgetLoader.sourceComponent = paramWidgets; + sendToScript(currentIndex) + } } onCurrentIndexChanged: { - // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // This is a hack to be sure the widgets below properly reflect the change of index: delete the Component // by setting the loader source to Null and then recreate it 100ms later - root.drawConfig["group"] = currentIndex + root.drawConfig = Render.getConfig("RenderMainView.OutlineEffect"+currentIndex) paramWidgetLoader.sourceComponent = undefined; postpone.interval = 100 postpone.start() From 8cabd1c9530c2395053df294ea76546a180c0837 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 18 Oct 2017 15:06:54 +0200 Subject: [PATCH 030/171] Fixed graphics bug with filled --- libraries/render-utils/src/OutlineEffect.cpp | 6 +++--- libraries/render-utils/src/OutlineEffect.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index d00819d0f2..d028e028d4 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -178,13 +178,13 @@ void DrawOutline::configure(const Config& config) { void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { auto outlineFrameBuffer = inputs.get1(); - auto outlineRect = inputs.get4(); + auto outlineRect = inputs.get3(); if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture(); - auto destinationFrameBuffer = inputs.get3(); + auto destinationFrameBuffer = outlineFrameBuffer->getColorFramebuffer(); auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); if (sceneDepthBuffer) { @@ -391,7 +391,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende stream << "OutlineEffect" << i; name = stream.str(); } - const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, primaryFramebuffer, outlinedRect).asVarying(); + const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, outlinedRect).asVarying(); task.addJob(name, drawOutlineInputs); } diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index b1c2e3c3dd..a099166267 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -110,7 +110,7 @@ signals: class DrawOutline { public: - using Inputs = render::VaryingSet5; + using Inputs = render::VaryingSet4; using Config = DrawOutlineConfig; using JobModel = render::Job::ModelI; From f63b4a64b050ded997e33b577565903cfbd019bc Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 18 Oct 2017 16:02:38 +0200 Subject: [PATCH 031/171] Working debugging script with tabs --- .../utilities/render/debugOutline.js | 6 +- .../developer/utilities/render/outline.qml | 211 +++++++++--------- 2 files changed, 106 insertions(+), 111 deletions(-) diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index 8e8a00f912..5ac7bcd6aa 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -14,8 +14,8 @@ var qml = Script.resolvePath('outline.qml'); var window = new OverlayWindow({ title: 'Outline', source: qml, - width: 285, - height: 370, + width: 400, + height: 400, }); window.closed.connect(function() { Script.stop(); }); @@ -108,7 +108,7 @@ function update() { } Selection.addToSelectedItemsList(selectionName, typeName, result.objectID) - print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); + //print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); prevID = result.objectID; prevType = typeName; diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 1e19b2cac9..c686af33c6 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -15,34 +15,14 @@ import "configSlider" Item { id: root property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug") - property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect0") signal sendToScript(var message); Column { spacing: 8 - - ComboBox { - id: groupBox - model: ["Group 0", "Group 1", "Group 2", "Group 3", "Group 4"] - Timer { - id: postpone - interval: 100; running: false; repeat: false - onTriggered: { - paramWidgetLoader.sourceComponent = paramWidgets; - sendToScript(currentIndex) - } - } - onCurrentIndexChanged: { - // This is a hack to be sure the widgets below properly reflect the change of index: delete the Component - // by setting the loader source to Null and then recreate it 100ms later - root.drawConfig = Render.getConfig("RenderMainView.OutlineEffect"+currentIndex) - paramWidgetLoader.sourceComponent = undefined; - postpone.interval = 100 - postpone.start() - } - } + anchors.fill: parent CheckBox { + id: debug text: "View Mask" checked: root.debugConfig["viewMask"] onCheckedChanged: { @@ -50,104 +30,119 @@ Item { } } - Component { - id: paramWidgets - Column { - spacing: 8 - CheckBox { - text: "Glow" - checked: root.drawConfig["glow"] - onCheckedChanged: { - drawConfig["glow"] = checked; - } - } - ConfigSlider { - label: "Width" - integral: false - config: root.drawConfig - property: "width" - max: 15.0 - min: 0.0 - width: 280 - } - ConfigSlider { - label: "Intensity" - integral: false - config: root.drawConfig - property: "intensity" - max: 1.0 - min: 0.0 - width: 280 - } + TabView { + id: tabs + width: 384 + height: 400 - GroupBox { - title: "Color" - width: 280 - Column { - spacing: 8 + onCurrentIndexChanged: { + sendToScript(currentIndex) + } - ConfigSlider { - label: "Red" - integral: false - config: root.drawConfig - property: "colorR" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Green" - integral: false - config: root.drawConfig - property: "colorG" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Blue" - integral: false - config: root.drawConfig - property: "colorB" - max: 1.0 - min: 0.0 - width: 270 + Component { + id: paramWidgets + + Column { + spacing: 8 + + CheckBox { + id: glow + text: "Glow" + checked: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex)["glow"] + onCheckedChanged: { + Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex)["glow"] = checked; } } - } + ConfigSlider { + label: "Width" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "width" + max: 15.0 + min: 0.0 + width: 280 + } + ConfigSlider { + label: "Intensity" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "intensity" + max: 1.0 + min: 0.0 + width: 280 + } - GroupBox { - title: "Fill Opacity" - width: 280 - Column { - spacing: 8 + GroupBox { + title: "Color" + width: 280 + Column { + spacing: 8 - ConfigSlider { - label: "Unoccluded" - integral: false - config: root.drawConfig - property: "unoccludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Occluded" - integral: false - config: root.drawConfig - property: "occludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 + ConfigSlider { + label: "Red" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "colorR" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Green" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "colorG" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Blue" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "colorB" + max: 1.0 + min: 0.0 + width: 270 + } + } + } + + GroupBox { + title: "Fill Opacity" + width: 280 + Column { + spacing: 8 + + ConfigSlider { + label: "Unoccluded" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "unoccludedFillOpacity" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Occluded" + integral: false + config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) + property: "occludedFillOpacity" + max: 1.0 + min: 0.0 + width: 270 + } } } } } } + } - Loader { - id: paramWidgetLoader - sourceComponent: paramWidgets + Component.onCompleted: { + for (var i=0 ; i<4 ; i++) { + var outlinePage = tabs.addTab("Outl. "+i, paramWidgets) + outlinePage.active = true } } } From f890c5bb8cac7e5cd28726088058791b85a55131 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 18 Oct 2017 19:40:03 +0200 Subject: [PATCH 032/171] Added project rect and scissor test. Need to increase bounds to take into account blur width --- libraries/render-utils/src/OutlineEffect.cpp | 83 +++++++++++++++++--- libraries/render-utils/src/OutlineEffect.h | 4 +- libraries/shared/src/ViewFrustum.cpp | 55 +++++++------ libraries/shared/src/ViewFrustum.h | 5 ++ 4 files changed, 112 insertions(+), 35 deletions(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index d028e028d4..36faee8119 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -11,6 +11,9 @@ #include "OutlineEffect.h" #include "GeometryCache.h" +#include "RenderUtilsLogging.h" + +#include "CubeProjectedPolygon.h" #include #include @@ -99,8 +102,13 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; + auto framebufferSize = ressources->getSourceFrameSize(); - outputs = args->_viewport; + // First thing we do is determine the projected bounding rect of all the outlined items + auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize); + qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w; + + outputs = outlinedRect; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -108,18 +116,17 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); - batch.setFramebuffer(ressources->getDepthFramebuffer()); - batch.clearDepthFramebuffer(1.0f); - - // Setup camera, projection and viewport for all items - batch.setViewportTransform(args->_viewport); - batch.setStateScissorRect(args->_viewport); - glm::mat4 projMat; Transform viewMat; args->getViewFrustum().evalProjectionMatrix(projMat); args->getViewFrustum().evalViewTransform(viewMat); + batch.setStateScissorRect(outlinedRect); + batch.setFramebuffer(ressources->getDepthFramebuffer()); + batch.clearDepthFramebuffer(1.0f, true); + + // Setup camera, projection and viewport for all items + batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); @@ -152,6 +159,49 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con } } +glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes, + const ViewFrustum& viewFrustum, glm::ivec2 frameSize) { + glm::vec4 minMaxBounds{ + std::numeric_limits::max(), + std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max(), + }; + + for (const auto& keyShapes : shapes) { + const auto& items = keyShapes.second; + + for (const auto& item : items) { + const auto& aabb = item.bound; + const auto projectedCube = viewFrustum.getProjectedPolygon(aabb); + + if (projectedCube.getAnyInView()) { + minMaxBounds.x = std::min(minMaxBounds.x, projectedCube.getMinX()); + minMaxBounds.y = std::min(minMaxBounds.y, projectedCube.getMinY()); + minMaxBounds.z = std::max(minMaxBounds.z, projectedCube.getMaxX()); + minMaxBounds.w = std::max(minMaxBounds.w, projectedCube.getMaxY()); + } + } + } + + if (minMaxBounds.x != std::numeric_limits::max()) { + const glm::vec2 halfFrameSize{ frameSize.x*0.5f, frameSize.y*0.5f }; + glm::ivec4 rect; + + minMaxBounds += 1.0f; + rect.x = glm::clamp((int)floorf(minMaxBounds.x * halfFrameSize.x), 0, frameSize.x); + rect.y = glm::clamp((int)floorf(minMaxBounds.y * halfFrameSize.y), 0, frameSize.y); + rect.z = glm::clamp((int)ceilf(minMaxBounds.z * halfFrameSize.x), 0, frameSize.x); + rect.w = glm::clamp((int)ceilf(minMaxBounds.w * halfFrameSize.y), 0, frameSize.y); + + rect.z -= rect.x; + rect.w -= rect.y; + return rect; + } else { + return glm::ivec4(0, 0, 0, 0); + } +} + gpu::PipelinePointer DrawOutline::_pipeline; gpu::PipelinePointer DrawOutline::_pipelineFilled; @@ -203,6 +253,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.enableStereo(false); batch.setFramebuffer(destinationFrameBuffer); + batch.setStateScissorRect(outlineRect); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); @@ -235,6 +286,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false, false)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + state->setScissorEnable(true); _pipeline = gpu::Pipeline::create(program, state); ps = gpu::Shader::createPixel(std::string(Outline_filled_frag)); @@ -261,7 +313,8 @@ void DebugOutline::configure(const Config& config) { } void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) { - const auto outlineRessources = input; + const auto outlineRessources = input.get0(); + const auto outlineRect = input.get1(); if (_isDisplayEnabled && outlineRessources) { assert(renderContext->args); @@ -271,6 +324,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(outlineRect); const auto geometryBuffer = DependencyManager::get(); @@ -305,6 +359,7 @@ void DebugOutline::initializePipelines() { auto state = std::make_shared(); state->setDepthTest(gpu::State::DepthTest(false)); + state->setScissorEnable(true); const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); @@ -360,16 +415,18 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS); state->setColorWriteMask(false, false, false, false); + state->setScissorEnable(true); initMaskPipelines(*shapePlumber, state); } // Prepare for outline group rendering. const auto outlineRessources = task.addJob("PrepareOutline", primaryFramebuffer); + render::Varying outline0Rect; for (auto i = 0; i < render::Scene::MAX_OUTLINE_COUNT; i++) { const auto groupItems = groups[i]; const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); - const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs, true); + const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs); // Sort const auto sortedPipelines = task.addJob("OutlinePipelineSort", outlinedItems); @@ -384,6 +441,9 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende } const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, outlineRessources).asVarying(); const auto outlinedRect = task.addJob(name, drawMaskInputs, shapePlumber); + if (i == 0) { + outline0Rect = outlinedRect; + } // Draw outline { @@ -396,7 +456,8 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende } // Debug outline - task.addJob("OutlineDebug", outlineRessources); + const auto debugInputs = DebugOutline::Inputs(outlineRessources, const_cast(outline0Rect)).asVarying(); + task.addJob("OutlineDebug", debugInputs); } #include "model_shadow_vert.h" diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index a099166267..878bdf2c04 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -72,6 +72,8 @@ public: protected: render::ShapePlumberPointer _shapePlumber; + + static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize); }; class DrawOutlineConfig : public render::Job::Config { @@ -158,7 +160,7 @@ signals: class DebugOutline { public: - using Inputs = OutlineRessourcesPointer; + using Inputs = render::VaryingSet2; using Config = DebugOutlineConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 978221e167..f08c85a38a 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -504,16 +504,17 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left }; -CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const { +template +CubeProjectedPolygon ViewFrustum::computeProjectedPolygon(const TBOX& box) const { const glm::vec3& bottomNearRight = box.getCorner(); glm::vec3 topFarLeft = box.calcTopFarLeft(); - int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit - + ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to - + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera - + ((_position.y > topFarLeft.y ) << 3) // 8 = top | with respect to - + ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining - + ((_position.z > topFarLeft.z ) << 5); // 32 = back/far | planes + int lookUp = ((_position.x < bottomNearRight.x)) // 1 = right | compute 6-bit + + ((_position.x > topFarLeft.x) << 1) // 2 = left | code to + + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera + + ((_position.y > topFarLeft.y) << 3) // 8 = top | with respect to + + ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining + + ((_position.z > topFarLeft.z) << 5); // 32 = back/far | planes int vertexCount = hullVertexLookup[lookUp][0]; //look up number of vertices @@ -524,8 +525,8 @@ CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const { bool anyPointsInView = false; // assume the worst! if (vertexCount) { allPointsInView = true; // assume the best! - for(int i = 0; i < vertexCount; i++) { - int vertexNum = hullVertexLookup[lookUp][i+1]; + for (int i = 0; i < vertexCount; i++) { + int vertexNum = hullVertexLookup[lookUp][i + 1]; glm::vec3 point = box.getVertex((BoxVertex)vertexNum); glm::vec2 projectedPoint = projectPoint(point, pointInView); allPointsInView = allPointsInView && pointInView; @@ -538,24 +539,24 @@ CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const { // NOTE: This clipping does not improve our overall performance. It basically causes more polygons to // end up in the same quad/half and so the polygon lists get longer, and that's more calls to polygon.occludes() if ( (projectedPolygon.getMaxX() > PolygonClip::RIGHT_OF_CLIPPING_WINDOW ) || - (projectedPolygon.getMaxY() > PolygonClip::TOP_OF_CLIPPING_WINDOW ) || - (projectedPolygon.getMaxX() < PolygonClip::LEFT_OF_CLIPPING_WINDOW ) || - (projectedPolygon.getMaxY() < PolygonClip::BOTTOM_OF_CLIPPING_WINDOW) ) { + (projectedPolygon.getMaxY() > PolygonClip::TOP_OF_CLIPPING_WINDOW ) || + (projectedPolygon.getMaxX() < PolygonClip::LEFT_OF_CLIPPING_WINDOW ) || + (projectedPolygon.getMaxY() < PolygonClip::BOTTOM_OF_CLIPPING_WINDOW) ) { - CoverageRegion::_clippedPolygons++; + CoverageRegion::_clippedPolygons++; - glm::vec2* clippedVertices; - int clippedVertexCount; - PolygonClip::clipToScreen(projectedPolygon.getVertices(), vertexCount, clippedVertices, clippedVertexCount); + glm::vec2* clippedVertices; + int clippedVertexCount; + PolygonClip::clipToScreen(projectedPolygon.getVertices(), vertexCount, clippedVertices, clippedVertexCount); - // Now reset the vertices of our projectedPolygon object - projectedPolygon.setVertexCount(clippedVertexCount); - for(int i = 0; i < clippedVertexCount; i++) { - projectedPolygon.setVertex(i, clippedVertices[i]); - } - delete[] clippedVertices; + // Now reset the vertices of our projectedPolygon object + projectedPolygon.setVertexCount(clippedVertexCount); + for(int i = 0; i < clippedVertexCount; i++) { + projectedPolygon.setVertex(i, clippedVertices[i]); + } + delete[] clippedVertices; - lookUp += PROJECTION_CLIPPED; + lookUp += PROJECTION_CLIPPED; } ***/ } @@ -568,6 +569,14 @@ CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const { return projectedPolygon; } +CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const { + return computeProjectedPolygon(box); +} + +CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { + return computeProjectedPolygon(box); +} + // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index d1b88fb2a5..c428e83397 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -119,6 +119,7 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; CubeProjectedPolygon getProjectedPolygon(const AACube& box) const; + CubeProjectedPolygon getProjectedPolygon(const AABox& box) const; void getFurthestPointFromCamera(const AACube& box, glm::vec3& furthestPoint) const; float distanceToCamera(const glm::vec3& point) const; @@ -169,6 +170,10 @@ private: // Used to project points glm::mat4 _ourModelViewProjectionMatrix; + + template + CubeProjectedPolygon computeProjectedPolygon(const TBOX& box) const; + }; using ViewFrustumPointer = std::shared_ptr; From cc30c0b841dd5a6baef7fe61411870d3b509f8c8 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 11:35:26 +0200 Subject: [PATCH 033/171] Expanded scissor rect with outline blur width --- libraries/render-utils/src/OutlineEffect.cpp | 48 +++++++++++++++++--- libraries/render-utils/src/OutlineEffect.h | 19 +++++++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 36faee8119..918f769277 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -81,6 +81,10 @@ gpu::TexturePointer OutlineRessources::getDepthTexture() { return getDepthFramebuffer()->getDepthStencilBuffer(); } +OutlineSharedParameters::OutlineSharedParameters() { + std::fill(_blurPixelWidths.begin(), _blurPixelWidths.end(), 0); +} + PrepareDrawOutline::PrepareDrawOutline() { _ressources = std::make_shared(); } @@ -92,6 +96,13 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, outputs = _ressources; } +DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, + render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : + _outlineIndex{ outlineIndex }, + _shapePlumber { shapePlumber }, + _parameters{ parameters } { +} + void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -106,9 +117,12 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // First thing we do is determine the projected bounding rect of all the outlined items auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize); + auto blurPixelWidth = _parameters->_blurPixelWidths[_outlineIndex]; qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w; - outputs = outlinedRect; + // Add 1 pixel of extra margin to be on the safe side + outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize); + outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -202,10 +216,28 @@ glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes } } +glm::ivec4 DrawOutlineMask::expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize) { + // Go bo back to min max values + rect.z += rect.x; + rect.w += rect.y; + + rect.x = std::max(0, rect.x - amount); + rect.y = std::max(0, rect.y - amount); + rect.z = std::min(frameSize.x, rect.z + amount); + rect.w = std::min(frameSize.y, rect.w + amount); + + // Back to width height + rect.z -= rect.x; + rect.w -= rect.y; + return rect; +} + gpu::PipelinePointer DrawOutline::_pipeline; gpu::PipelinePointer DrawOutline::_pipelineFilled; -DrawOutline::DrawOutline() { +DrawOutline::DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters) : + _outlineIndex{ outlineIndex }, + _parameters{ parameters } { } void DrawOutline::configure(const Config& config) { @@ -222,7 +254,7 @@ void DrawOutline::configure(const Config& config) { _size = config.width / 400.0f; configuration._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; configuration._size.y = _size; - + _parameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); _isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON); } @@ -247,18 +279,19 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x; configuration._size.y = _size; _framebufferSize = framebufferSize; + _parameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setFramebuffer(destinationFrameBuffer); - batch.setStateScissorRect(outlineRect); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); + batch.setStateScissorRect(outlineRect); batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); @@ -410,7 +443,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende const auto deferredFrameTransform = inputs.getN(3); // Prepare the ShapePipeline - ShapePlumberPointer shapePlumber = std::make_shared(); + auto shapePlumber = std::make_shared(); { auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS); @@ -418,6 +451,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende state->setScissorEnable(true); initMaskPipelines(*shapePlumber, state); } + auto sharedParameters = std::make_shared(); // Prepare for outline group rendering. const auto outlineRessources = task.addJob("PrepareOutline", primaryFramebuffer); @@ -440,7 +474,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende name = stream.str(); } const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, outlineRessources).asVarying(); - const auto outlinedRect = task.addJob(name, drawMaskInputs, shapePlumber); + const auto outlinedRect = task.addJob(name, drawMaskInputs, i, shapePlumber, sharedParameters); if (i == 0) { outline0Rect = outlinedRect; } @@ -452,7 +486,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende name = stream.str(); } const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, outlinedRect).asVarying(); - task.addJob(name, drawOutlineInputs); + task.addJob(name, drawOutlineInputs, i, sharedParameters); } // Debug outline diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index 878bdf2c04..ab603ecab6 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -42,6 +42,16 @@ protected: using OutlineRessourcesPointer = std::shared_ptr; +class OutlineSharedParameters { +public: + + OutlineSharedParameters(); + + std::array _blurPixelWidths; +}; + +using OutlineSharedParametersPointer = std::shared_ptr; + class PrepareDrawOutline { public: using Inputs = gpu::FramebufferPointer; @@ -65,15 +75,18 @@ public: using Outputs = glm::ivec4; using JobModel = render::Job::ModelIO; - DrawOutlineMask(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); protected: + unsigned int _outlineIndex; render::ShapePlumberPointer _shapePlumber; + OutlineSharedParametersPointer _parameters; static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize); + static glm::ivec4 expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize); }; class DrawOutlineConfig : public render::Job::Config { @@ -116,7 +129,7 @@ public: using Config = DrawOutlineConfig; using JobModel = render::Job::ModelI; - DrawOutline(); + DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); @@ -140,6 +153,8 @@ private: static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; + unsigned int _outlineIndex; + OutlineSharedParametersPointer _parameters; OutlineConfigurationBuffer _configuration; glm::ivec2 _framebufferSize{ 0,0 }; bool _isFilled{ false }; From 111966b987bc5115628a83a623475b8c2117456d Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 12:39:34 +0200 Subject: [PATCH 034/171] Fixed potential bug with outline frame buffer allocations. Still problems with avatar outline rect --- libraries/render-utils/src/OutlineEffect.cpp | 53 ++++++++++---------- libraries/render-utils/src/OutlineEffect.h | 8 +-- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 918f769277..6e313d262a 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -37,43 +37,36 @@ OutlineRessources::OutlineRessources() { void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize()); - // If the depth buffer or size changed, we need to delete our FBOs and recreate them at the + // If the buffer size changed, we need to delete our FBOs and recreate them at the // new correct dimensions. - if (_depthFrameBuffer) { - if (_frameSize != newFrameSize) { - _frameSize = newFrameSize; - clear(); + if (_frameSize != newFrameSize) { + _frameSize = newFrameSize; + allocateDepthBuffer(primaryFrameBuffer); + allocateColorBuffer(primaryFrameBuffer); + } else { + if (!_depthFrameBuffer) { + allocateDepthBuffer(primaryFrameBuffer); } - } - if (!_colorFrameBuffer) { - if (_frameSize != newFrameSize) { - _frameSize = newFrameSize; - // Failing to recreate this frame buffer when the screen has been resized creates a bug on Mac - _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); - _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); + if (!_colorFrameBuffer) { + allocateColorBuffer(primaryFrameBuffer); } } } -void OutlineRessources::clear() { - _depthFrameBuffer.reset(); +void OutlineRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { + _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); + _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); } -void OutlineRessources::allocate() { - - auto width = _frameSize.x; - auto height = _frameSize.y; +void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, width, height)); - + auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); _depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat); } gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { - if (!_depthFrameBuffer) { - allocate(); - } + assert(_depthFrameBuffer); return _depthFrameBuffer; } @@ -81,6 +74,11 @@ gpu::TexturePointer OutlineRessources::getDepthTexture() { return getDepthFramebuffer()->getDepthStencilBuffer(); } +gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { + assert(_colorFrameBuffer); + return _colorFrameBuffer; +} + OutlineSharedParameters::OutlineSharedParameters() { std::fill(_blurPixelWidths.begin(), _blurPixelWidths.end(), 0); } @@ -305,6 +303,11 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I const gpu::PipelinePointer& DrawOutline::getPipeline() { if (!_pipeline) { + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + state->setScissorEnable(true); + auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); @@ -316,10 +319,6 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false, false)); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - state->setScissorEnable(true); _pipeline = gpu::Pipeline::create(program, state); ps = gpu::Shader::createPixel(std::string(Outline_filled_frag)); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index ab603ecab6..b4be75484e 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -23,7 +23,7 @@ public: gpu::FramebufferPointer getDepthFramebuffer(); gpu::TexturePointer getDepthTexture(); - gpu::FramebufferPointer getColorFramebuffer() { return _colorFrameBuffer; } + gpu::FramebufferPointer getColorFramebuffer(); // Update the source framebuffer size which will drive the allocation of all the other resources. void update(const gpu::FramebufferPointer& primaryFrameBuffer); @@ -31,13 +31,13 @@ public: protected: - void clear(); - void allocate(); - gpu::FramebufferPointer _depthFrameBuffer; gpu::FramebufferPointer _colorFrameBuffer; glm::ivec2 _frameSize; + + void allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer); + void allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer); }; using OutlineRessourcesPointer = std::shared_ptr; From 382262da3db5d47d0d21c03e8e9ee8d96633c19c Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 16:23:13 +0200 Subject: [PATCH 035/171] Working scissor with correct projected bounding box rect --- libraries/render-utils/src/OutlineEffect.cpp | 13 +-- libraries/shared/src/ViewFrustum.cpp | 96 ++++++++++++++++++-- libraries/shared/src/ViewFrustum.h | 1 + 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 6e313d262a..19d3847e50 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -185,13 +185,14 @@ glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes for (const auto& item : items) { const auto& aabb = item.bound; - const auto projectedCube = viewFrustum.getProjectedPolygon(aabb); + glm::vec2 bottomLeft; + glm::vec2 topRight; - if (projectedCube.getAnyInView()) { - minMaxBounds.x = std::min(minMaxBounds.x, projectedCube.getMinX()); - minMaxBounds.y = std::min(minMaxBounds.y, projectedCube.getMinY()); - minMaxBounds.z = std::max(minMaxBounds.z, projectedCube.getMaxX()); - minMaxBounds.w = std::max(minMaxBounds.w, projectedCube.getMaxY()); + if (viewFrustum.getProjectedRect(aabb, bottomLeft, topRight)) { + minMaxBounds.x = std::min(minMaxBounds.x, bottomLeft.x); + minMaxBounds.y = std::min(minMaxBounds.y, bottomLeft.y); + minMaxBounds.z = std::max(minMaxBounds.z, topRight.x); + minMaxBounds.w = std::max(minMaxBounds.w, topRight.y); } } } diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index f08c85a38a..747b39f79e 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -509,12 +510,12 @@ CubeProjectedPolygon ViewFrustum::computeProjectedPolygon(const TBOX& box) const const glm::vec3& bottomNearRight = box.getCorner(); glm::vec3 topFarLeft = box.calcTopFarLeft(); - int lookUp = ((_position.x < bottomNearRight.x)) // 1 = right | compute 6-bit - + ((_position.x > topFarLeft.x) << 1) // 2 = left | code to - + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera - + ((_position.y > topFarLeft.y) << 3) // 8 = top | with respect to - + ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining - + ((_position.z > topFarLeft.z) << 5); // 32 = back/far | planes + int lookUp = ((_position.x < bottomNearRight.x)) // 1 = right | compute 6-bit + + ((_position.x > topFarLeft.x) << 1) // 2 = left | code to + + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera + + ((_position.y > topFarLeft.y) << 3) // 8 = top | with respect to + + ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining + + ((_position.z > topFarLeft.z) << 5); // 32 = back/far | planes int vertexCount = hullVertexLookup[lookUp][0]; //look up number of vertices @@ -577,6 +578,89 @@ CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const { return computeProjectedPolygon(box); } +bool ViewFrustum::getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm::vec2& topRight) const { + using Edge = std::pair; + + const int VERTEX_COUNT = 8; + const int EDGE_COUNT = 12; + // In theory, after clipping a box with a plane, only 4 new vertices at max + // should be created but due to potential imprecisions (edge almost parallel to + // near plane for instance) there might be more + const int MAX_VERTEX_COUNT = VERTEX_COUNT + 4 + 2; + + std::array vertices; + std::array boxEdges{ + Edge(BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR), + Edge(TOP_LEFT_NEAR, TOP_RIGHT_NEAR), + Edge(BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR), + Edge(TOP_LEFT_FAR, TOP_RIGHT_FAR), + Edge(BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR), + Edge(BOTTOM_LEFT_FAR, TOP_LEFT_FAR), + Edge(BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR), + Edge(BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR), + Edge(BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR), + Edge(TOP_LEFT_NEAR, TOP_LEFT_FAR), + Edge(BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR), + Edge(TOP_RIGHT_NEAR, TOP_RIGHT_FAR) + }; + std::array distancesToNearPlane; + std::bitset areVerticesInside; + int vertexCount = VERTEX_COUNT; + int i; + + // Clip the hull with the near plane. + const auto& nearPlane = _planes[NEAR_PLANE]; + + for (i = 0; i < VERTEX_COUNT; i++) { + vertices[i] = box.getVertex(static_cast(i)); + distancesToNearPlane[i] = nearPlane.distance(vertices[i]); + } + + for (i = 0; i < EDGE_COUNT; i++) { + const auto& edgeVertexIndices = boxEdges[i]; + const auto& startVertex = vertices[edgeVertexIndices.first]; + const auto& endVertex = vertices[edgeVertexIndices.second]; + float startVertexDistance = distancesToNearPlane[edgeVertexIndices.first]; + float endVertexDistance = distancesToNearPlane[edgeVertexIndices.second]; + bool isStartPointInside = startVertexDistance >= 0.0f; + bool isEndPointInside = endVertexDistance >= 0.0f; + + areVerticesInside.set(edgeVertexIndices.first, isStartPointInside); + areVerticesInside.set(edgeVertexIndices.second, isEndPointInside); + + if (isStartPointInside != isEndPointInside) { + // One of the two vertices is behind the near plane so add a new clipped vertex + // add tag it as projectable. + vertices[vertexCount] = startVertex + (endVertex - startVertex) * (startVertexDistance / (startVertexDistance - endVertexDistance)); + areVerticesInside.set(vertexCount); + vertexCount++; + } + } + + // Project points that are inside + bottomLeft.x = std::numeric_limits::max(); + bottomLeft.y = std::numeric_limits::max(); + topRight.x = -std::numeric_limits::max(); + topRight.y = -std::numeric_limits::max(); + for (i = 0; i < vertexCount; i++) { + if (areVerticesInside[i]) { + bool isPointInside; + auto projectedPoint = projectPoint(vertices[i], isPointInside); + bottomLeft.x = std::min(bottomLeft.x, projectedPoint.x); + bottomLeft.y = std::min(bottomLeft.y, projectedPoint.y); + topRight.x = std::max(topRight.x, projectedPoint.x); + topRight.y = std::max(topRight.y, projectedPoint.y); + } + } + + bottomLeft.x = glm::clamp(bottomLeft.x, -1.0f, 1.0f); + bottomLeft.y = glm::clamp(bottomLeft.y, -1.0f, 1.0f); + topRight.x = glm::clamp(topRight.x, -1.0f, 1.0f); + topRight.y = glm::clamp(topRight.y, -1.0f, 1.0f); + + return areVerticesInside.any(); +} + // Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the // axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for // squares and square-roots. Just compares. diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index c428e83397..98f666d666 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -120,6 +120,7 @@ public: glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; CubeProjectedPolygon getProjectedPolygon(const AACube& box) const; CubeProjectedPolygon getProjectedPolygon(const AABox& box) const; + bool getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm::vec2& topRight) const; void getFurthestPointFromCamera(const AACube& box, glm::vec3& furthestPoint) const; float distanceToCamera(const glm::vec3& point) const; From fc66dcfdea154849606a90354806f156da05fea4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 16:52:29 +0200 Subject: [PATCH 036/171] Added outline to statsGPU script --- libraries/render-utils/src/RenderDeferredTask.cpp | 4 ++-- scripts/developer/utilities/render/statsGPU.qml | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 54c2248d8b..dc4bdd14cc 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -176,6 +176,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying(); task.addJob("ToneMapping", toneMappingInputs); + const auto outlineRangeTimer = task.addJob("BeginOutlineRangeTimer", "Outline"); // Select items that need to be outlined const auto selectionBaseName = "contextOverlayHighlightList"; const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); @@ -187,12 +188,11 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren selectionName << i; outlineGroups[i] = addSelectItemJobs(task, selectionName.str().c_str(), metas, opaques, transparents); } - const auto outlineRangeTimer = task.addJob("BeginOutlineRangeTimer", "Outline"); const auto outlineInputs = DrawOutlineTask::Inputs(outlineGroups, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); task.addJob("DrawOutline", outlineInputs); - task.addJob("EndOutlineRangeTimer", outlineRangeTimer); + task.addJob("OutlineRangeTimer", outlineRangeTimer); { // DEbug the bounds of the rendered items, still look at the zbuffer task.addJob("DrawMetaBounds", metas); diff --git a/scripts/developer/utilities/render/statsGPU.qml b/scripts/developer/utilities/render/statsGPU.qml index 6b80f00af3..8d284c11ca 100644 --- a/scripts/developer/utilities/render/statsGPU.qml +++ b/scripts/developer/utilities/render/statsGPU.qml @@ -65,6 +65,13 @@ Item { label: "tone and post", color: "#FF0000" } + , + { + object: Render.getConfig("RenderMainView.OutlineRangeTimer"), + prop: "gpuRunTime", + label: "outline", + color: "#FFFF00" + } ] } PlotPerf { @@ -105,6 +112,13 @@ Item { label: "tone and post", color: "#FF0000" } + , + { + object: Render.getConfig("RenderMainView.OutlineRangeTimer"), + prop: "batchRunTime", + label: "outline", + color: "#FFFF00" + } ] } } From 410b1904cdb230c9f4bc079ced67f674ef1793d3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 17:36:16 +0200 Subject: [PATCH 037/171] Fixed bug in outline.qml that associated outline tab to wrong outline job config --- libraries/render-utils/src/OutlineEffect.cpp | 36 ++--- libraries/render-utils/src/OutlineEffect.h | 5 +- libraries/render/src/render/Scene.h | 2 +- .../developer/utilities/render/outline.qml | 126 ++++-------------- .../render/outlinePage/OutlinePage.qml | 113 ++++++++++++++++ .../utilities/render/outlinePage/qmldir | 1 + 6 files changed, 159 insertions(+), 124 deletions(-) create mode 100644 scripts/developer/utilities/render/outlinePage/OutlinePage.qml create mode 100644 scripts/developer/utilities/render/outlinePage/qmldir diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 19d3847e50..a4286474f9 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -98,7 +98,7 @@ DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : _outlineIndex{ outlineIndex }, _shapePlumber { shapePlumber }, - _parameters{ parameters } { + _sharedParameters{ parameters } { } void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { @@ -115,8 +115,8 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // First thing we do is determine the projected bounding rect of all the outlined items auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize); - auto blurPixelWidth = _parameters->_blurPixelWidths[_outlineIndex]; - qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w; + auto blurPixelWidth = _sharedParameters->_blurPixelWidths[_outlineIndex]; + //qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w; // Add 1 pixel of extra margin to be on the safe side outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize); @@ -236,25 +236,25 @@ gpu::PipelinePointer DrawOutline::_pipelineFilled; DrawOutline::DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters) : _outlineIndex{ outlineIndex }, - _parameters{ parameters } { + _sharedParameters{ parameters } { } void DrawOutline::configure(const Config& config) { - auto& configuration = _configuration.edit(); const auto OPACITY_EPSILON = 5e-3f; - configuration._color = config.color; - configuration._intensity = config.intensity * (config.glow ? 2.f : 1.f); - configuration._unoccludedFillOpacity = config.unoccludedFillOpacity; - configuration._occludedFillOpacity = config.occludedFillOpacity; - configuration._threshold = config.glow ? 1.f : 1e-3f; - configuration._blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width * 3 + 0.5f))); + _parameters._color = config.color; + _parameters._intensity = config.intensity * (config.glow ? 2.0f : 1.0f); + _parameters._unoccludedFillOpacity = config.unoccludedFillOpacity; + _parameters._occludedFillOpacity = config.occludedFillOpacity; + _parameters._threshold = config.glow ? 1.0f : 1e-3f; + _parameters._blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width * 3 + 0.5f))); // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. _size = config.width / 400.0f; - configuration._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; - configuration._size.y = _size; - _parameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); + _parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; + _parameters._size.y = _size; + _sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); _isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON); + _configuration.edit() = _parameters; } void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { @@ -274,11 +274,11 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I if (_framebufferSize != framebufferSize) { - auto& configuration = _configuration.edit(); - configuration._size.x = (_size * framebufferSize.y) / framebufferSize.x; - configuration._size.y = _size; + _parameters._size.x = (_size * framebufferSize.y) / framebufferSize.x; + _parameters._size.y = _size; _framebufferSize = framebufferSize; - _parameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); + _sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); + _configuration.edit() = _parameters; } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index b4be75484e..ee5e503de9 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -83,7 +83,7 @@ protected: unsigned int _outlineIndex; render::ShapePlumberPointer _shapePlumber; - OutlineSharedParametersPointer _parameters; + OutlineSharedParametersPointer _sharedParameters; static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize); static glm::ivec4 expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize); @@ -154,7 +154,8 @@ private: static gpu::PipelinePointer _pipelineFilled; unsigned int _outlineIndex; - OutlineSharedParametersPointer _parameters; + OutlineParameters _parameters; + OutlineSharedParametersPointer _sharedParameters; OutlineConfigurationBuffer _configuration; glm::ivec2 _framebufferSize{ 0,0 }; bool _isFilled{ false }; diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 04a285bcd1..1f3b9a72c3 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -104,7 +104,7 @@ class Scene { public: enum { - MAX_OUTLINE_COUNT = 16 + MAX_OUTLINE_COUNT = 8 }; Scene(glm::vec3 origin, float size); diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index c686af33c6..578f0857dc 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 -import "configSlider" +import "outlinePage" Item { id: root @@ -39,110 +39,30 @@ Item { sendToScript(currentIndex) } - Component { - id: paramWidgets - - Column { - spacing: 8 - - CheckBox { - id: glow - text: "Glow" - checked: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex)["glow"] - onCheckedChanged: { - Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex)["glow"] = checked; - } - } - ConfigSlider { - label: "Width" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "width" - max: 15.0 - min: 0.0 - width: 280 - } - ConfigSlider { - label: "Intensity" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "intensity" - max: 1.0 - min: 0.0 - width: 280 - } - - GroupBox { - title: "Color" - width: 280 - Column { - spacing: 8 - - ConfigSlider { - label: "Red" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "colorR" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Green" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "colorG" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Blue" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "colorB" - max: 1.0 - min: 0.0 - width: 270 - } - } - } - - GroupBox { - title: "Fill Opacity" - width: 280 - Column { - spacing: 8 - - ConfigSlider { - label: "Unoccluded" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "unoccludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Occluded" - integral: false - config: Render.getConfig("RenderMainView.OutlineEffect"+tabs.currentIndex) - property: "occludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 - } - } - } + Tab { + title: "Outl.0" + OutlinePage { + outlineIndex: 0 + } + } + Tab { + title: "Outl.1" + OutlinePage { + outlineIndex: 1 + } + } + Tab { + title: "Outl.2" + OutlinePage { + outlineIndex: 2 + } + } + Tab { + title: "Outl.3" + OutlinePage { + outlineIndex: 3 } } } } - - Component.onCompleted: { - for (var i=0 ; i<4 ; i++) { - var outlinePage = tabs.addTab("Outl. "+i, paramWidgets) - outlinePage.active = true - } - } } diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml new file mode 100644 index 0000000000..849f71bdb4 --- /dev/null +++ b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml @@ -0,0 +1,113 @@ +// +// outlinePage.qml +// developer/utilities/render +// +// Olivier Prat, created on 08/08/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../configSlider" + +Item { + id: root + property var outlineIndex: 0 + property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex) + + Column { + spacing: 8 + + CheckBox { + id: glow + text: "Glow" + checked: root.drawConfig["glow"] + onCheckedChanged: { + paramWidgets.drawConfig["glow"] = checked; + } + } + ConfigSlider { + label: "Width" + integral: false + config: root.drawConfig + property: "width" + max: 15.0 + min: 0.0 + width: 280 + } + ConfigSlider { + label: "Intensity" + integral: false + config: root.drawConfig + property: "intensity" + max: 1.0 + min: 0.0 + width: 280 + } + + GroupBox { + title: "Color" + width: 280 + Column { + spacing: 8 + + ConfigSlider { + label: "Red" + integral: false + config: root.drawConfig + property: "colorR" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Green" + integral: false + config: root.drawConfig + property: "colorG" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Blue" + integral: false + config: root.drawConfig + property: "colorB" + max: 1.0 + min: 0.0 + width: 270 + } + } + } + + GroupBox { + title: "Fill Opacity" + width: 280 + Column { + spacing: 8 + + ConfigSlider { + label: "Unoccluded" + integral: false + config: root.drawConfig + property: "unoccludedFillOpacity" + max: 1.0 + min: 0.0 + width: 270 + } + ConfigSlider { + label: "Occluded" + integral: false + config: root.drawConfig + property: "occludedFillOpacity" + max: 1.0 + min: 0.0 + width: 270 + } + } + } + } +} diff --git a/scripts/developer/utilities/render/outlinePage/qmldir b/scripts/developer/utilities/render/outlinePage/qmldir new file mode 100644 index 0000000000..56f5d45414 --- /dev/null +++ b/scripts/developer/utilities/render/outlinePage/qmldir @@ -0,0 +1 @@ +OutlinePage 1.0 OutlinePage.qml \ No newline at end of file From 6acff216d919ab1c7976cb1b17367cb525128f5a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 19 Oct 2017 19:00:09 +0200 Subject: [PATCH 038/171] Reduced blur tap for slightly better performance --- libraries/render-utils/src/OutlineEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index a4286474f9..8822bcc649 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -247,7 +247,7 @@ void DrawOutline::configure(const Config& config) { _parameters._unoccludedFillOpacity = config.unoccludedFillOpacity; _parameters._occludedFillOpacity = config.occludedFillOpacity; _parameters._threshold = config.glow ? 1.0f : 1e-3f; - _parameters._blurKernelSize = std::min(10, std::max(2, (int)floorf(config.width * 3 + 0.5f))); + _parameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(config.width * 3 + 0.5f))); // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. _size = config.width / 400.0f; _parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; From 3227b9d64ad37e557ad38da4bccba2143f867327 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 20 Oct 2017 09:50:37 +0200 Subject: [PATCH 039/171] Fixed potential bug when item doesn't have a payload --- libraries/render/src/render/FilterTask.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 49a9ada91e..f60f5895b7 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -118,8 +118,9 @@ void MetaToSubItems::run(const RenderContextPointer& renderContext, const ItemBo for (auto idBound : inItems) { auto& item = scene->getItem(idBound.id); - - item.fetchMetaSubItems(outItems); + if (item.exist()) { + item.fetchMetaSubItems(outItems); + } } } @@ -132,8 +133,9 @@ void IDsToBounds::run(const RenderContextPointer& renderContext, const ItemIDs& if (!_disableAABBs) { for (auto id : inItems) { auto& item = scene->getItem(id); - - outItems.emplace_back(ItemBound{ id, item.getBound() }); + if (item.exist()) { + outItems.emplace_back(ItemBound{ id, item.getBound() }); + } } } else { for (auto id : inItems) { From 732fe3b8dbc1e4f23cede8a319c2360f2b4d6151 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 20 Oct 2017 11:32:43 +0200 Subject: [PATCH 040/171] Improved outline debugging script for easier test plan --- .../scripting/SelectionScriptingInterface.cpp | 6 ++ .../scripting/SelectionScriptingInterface.h | 1 + .../utilities/render/debugOutline.js | 85 +++++++++++++------ .../developer/utilities/render/outline.qml | 31 +++++-- 4 files changed, 90 insertions(+), 33 deletions(-) diff --git a/interface/src/scripting/SelectionScriptingInterface.cpp b/interface/src/scripting/SelectionScriptingInterface.cpp index 808396c901..1adf5650dd 100644 --- a/interface/src/scripting/SelectionScriptingInterface.cpp +++ b/interface/src/scripting/SelectionScriptingInterface.cpp @@ -71,6 +71,12 @@ bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& lis return false; } +bool SelectionScriptingInterface::clearSelectedItemsList(const QString& listName) { + _selectedItemsListMap.insert(listName, GameplayObjects()); + emit selectedItemsListChanged(listName); + return true; +} + template bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) { GameplayObjects currentList = _selectedItemsListMap.value(listName); currentList.addToGameplayObjects(idToAdd); diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h index d1a372c5c4..28c1713050 100644 --- a/interface/src/scripting/SelectionScriptingInterface.h +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -61,6 +61,7 @@ public: Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); + Q_INVOKABLE bool clearSelectedItemsList(const QString& listName); signals: void selectedItemsListChanged(const QString& listName); diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index 5ac7bcd6aa..c01fbd3c76 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -55,14 +55,7 @@ var end2 = { } var outlineGroupIndex = 0 - -function setOutlineGroupIndex(index) { - print("Switching to outline group "+index) - outlineGroupIndex = index -} - -window.fromQml.connect(setOutlineGroupIndex); - +var isSelectionAddEnabled = false var renderStates = [{name: "test", end: end}]; var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}]; @@ -71,33 +64,64 @@ var ray = LaserPointers.createLaserPointer({ filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS | RayPick.PICK_AVATARS | RayPick.PICK_INVISIBLE | RayPick.PICK_NONCOLLIDABLE, renderStates: renderStates, defaultRenderStates: defaultRenderStates, - enabled: true + enabled: false }); +function getSelectionName() { + var selectionName = "contextOverlayHighlightList" + + if (outlineGroupIndex>0) { + selectionName += outlineGroupIndex + } + return selectionName +} + +function fromQml(message) { + tokens = message.split(' ') + print("Received '"+message+"' from outline.qml") + if (tokens[0]=="outline") { + outlineGroupIndex = parseInt(tokens[1]) + print("Switching to outline group "+outlineGroupIndex) + } else if (tokens[0]=="pick") { + var isPickingEnabled = tokens[1]=='true' + print("Ray picking set to "+isPickingEnabled.toString()) + if (isPickingEnabled) { + LaserPointers.enableLaserPointer(ray) + } else { + LaserPointers.disableLaserPointer(ray) + } + } else if (tokens[0]=="add") { + isSelectionAddEnabled = tokens[1]=='true' + print("Add to selection set to "+isSelectionAddEnabled.toString()) + if (!isSelectionAddEnabled) { + Selection.clearSelectedItemsList(getSelectionName()) + } + } +} + +window.fromQml.connect(fromQml); + function cleanup() { LaserPointers.removeLaserPointer(ray); } Script.scriptEnding.connect(cleanup); -var prevID = 0; -var prevType = ""; -function update() { +var prevID = 0 +var prevType = "" +var selectedID = 0 +var selectedType = "" +var time = 0 +function update(deltaTime) { + // you have to do this repeatedly because there's a bug but I'll fix it LaserPointers.setRenderState(ray, "test"); var result = LaserPointers.getPrevRayPickResult(ray); - var selectionName = "contextOverlayHighlightList" - - if (outlineGroupIndex>0) { - selectionName += outlineGroupIndex - } + var selectionName = getSelectionName() if (result.type != RayPick.INTERSECTED_NONE) { + time += deltaTime if (result.objectID != prevID) { - if (prevID != 0) { - Selection.removeFromSelectedItemsList(selectionName, prevType, prevID) - } - var typeName = "" if (result.type == RayPick.INTERSECTED_ENTITY) { typeName = "entity" @@ -107,19 +131,28 @@ function update() { typeName = "avatar" } - Selection.addToSelectedItemsList(selectionName, typeName, result.objectID) - //print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); - prevID = result.objectID; prevType = typeName; + time = 0 + } else if (time>1.0 && prevID!=selectedID) { + if (prevID != 0 && !isSelectionAddEnabled) { + Selection.removeFromSelectedItemsList(selectionName, selectedType, selectedID) + } + selectedID = prevID + selectedType = prevType + Selection.addToSelectedItemsList(selectionName, selectedType, selectedID) + //print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); } } else { - if (prevID != 0) { + if (prevID != 0 && !isSelectionAddEnabled) { Selection.removeFromSelectedItemsList(selectionName, prevType, prevID) } - prevID = 0; + prevID = 0 + selectedID = 0 + time = 0 } } + Script.update.connect(update); }()); // END LOCAL_SCOPE \ No newline at end of file diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 578f0857dc..39acd854ac 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -21,12 +21,29 @@ Item { spacing: 8 anchors.fill: parent - CheckBox { - id: debug - text: "View Mask" - checked: root.debugConfig["viewMask"] - onCheckedChanged: { - root.debugConfig["viewMask"] = checked; + Row { + spacing: 8 + CheckBox { + id: debug + text: "View Mask" + checked: root.debugConfig["viewMask"] + onCheckedChanged: { + root.debugConfig["viewMask"] = checked; + } + } + CheckBox { + text: "Hover select" + checked: false + onCheckedChanged: { + sendToScript("pick "+checked.toString()) + } + } + CheckBox { + text: "Add to selection" + checked: false + onCheckedChanged: { + sendToScript("add "+checked.toString()) + } } } @@ -36,7 +53,7 @@ Item { height: 400 onCurrentIndexChanged: { - sendToScript(currentIndex) + sendToScript("outline "+currentIndex) } Tab { From 2d49cc1a7561db478730e131243c8aa9f11cd479 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 20 Oct 2017 12:04:20 +0200 Subject: [PATCH 041/171] Fixed bug in debugOutline script --- scripts/developer/utilities/render/debugOutline.js | 12 +++++++----- .../utilities/render/outlinePage/OutlinePage.qml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index c01fbd3c76..72585e07fb 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -56,8 +56,10 @@ var end2 = { var outlineGroupIndex = 0 var isSelectionAddEnabled = false +var isSelectionEnabled = false var renderStates = [{name: "test", end: end}]; var defaultRenderStates = [{name: "test", distance: 20.0, end: end2}]; +var time = 0 var ray = LaserPointers.createLaserPointer({ joint: "Mouse", @@ -83,13 +85,14 @@ function fromQml(message) { outlineGroupIndex = parseInt(tokens[1]) print("Switching to outline group "+outlineGroupIndex) } else if (tokens[0]=="pick") { - var isPickingEnabled = tokens[1]=='true' - print("Ray picking set to "+isPickingEnabled.toString()) - if (isPickingEnabled) { + isSelectionEnabled = tokens[1]=='true' + print("Ray picking set to "+isSelectionEnabled.toString()) + if (isSelectionEnabled) { LaserPointers.enableLaserPointer(ray) } else { LaserPointers.disableLaserPointer(ray) } + time = 0 } else if (tokens[0]=="add") { isSelectionAddEnabled = tokens[1]=='true' print("Add to selection set to "+isSelectionAddEnabled.toString()) @@ -110,7 +113,6 @@ var prevID = 0 var prevType = "" var selectedID = 0 var selectedType = "" -var time = 0 function update(deltaTime) { // you have to do this repeatedly because there's a bug but I'll fix it @@ -119,7 +121,7 @@ function update(deltaTime) { var result = LaserPointers.getPrevRayPickResult(ray); var selectionName = getSelectionName() - if (result.type != RayPick.INTERSECTED_NONE) { + if (isSelectionEnabled && result.type != RayPick.INTERSECTED_NONE) { time += deltaTime if (result.objectID != prevID) { var typeName = "" diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml index 849f71bdb4..f8976162ab 100644 --- a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml +++ b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml @@ -25,7 +25,7 @@ Item { text: "Glow" checked: root.drawConfig["glow"] onCheckedChanged: { - paramWidgets.drawConfig["glow"] = checked; + root.drawConfig["glow"] = checked; } } ConfigSlider { From 43f9db5b70ea2aa025948ee1e9e693984f09d2e4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 23 Oct 2017 11:08:13 +0200 Subject: [PATCH 042/171] Fixed small bug due to half texel offset in outline shader --- libraries/render-utils/src/Outline.slh | 10 +++++----- libraries/render-utils/src/OutlineEffect.cpp | 2 +- .../utilities/render/outlinePage/OutlinePage.qml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Outline.slh index fe9594cc12..aeaf20a24a 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Outline.slh @@ -35,16 +35,14 @@ void main(void) { // We offset by half a texel to be centered on the depth sample. If we don't do this // the blur will have a different width between the left / right sides and top / bottom // sides of the silhouette - vec2 halfTexel = getInvWidthHeight() / 2; - vec2 texCoord0 = varTexCoord0+halfTexel; - float outlinedDepth = texture(outlinedDepthMap, texCoord0).x; + float outlinedDepth = texture(outlinedDepthMap, varTexCoord0).x; float intensity = 0.0; if (outlinedDepth < FAR_Z) { // We're not on the far plane so we are on the outlined object, thus no outline to do! <@if IS_FILLED@> // But we need to fill the interior - float sceneDepth = texture(sceneDepthMap, texCoord0).x; + float sceneDepth = texture(sceneDepthMap, varTexCoord0).x; // Transform to linear depth for better precision outlinedDepth = -evalZeyeFromZdb(outlinedDepth); sceneDepth = -evalZeyeFromZdb(sceneDepth); @@ -55,6 +53,8 @@ void main(void) { discard; <@endif@> } else { + vec2 halfTexel = getInvWidthHeight() / 2; + vec2 texCoord0 = varTexCoord0+halfTexel; float weight = 0.0; vec2 deltaUv = params._size / params._blurKernelSize; vec2 lineStartUv = texCoord0 - params._size / 2.0; @@ -72,7 +72,7 @@ void main(void) { { outlinedDepth = texture(outlinedDepthMap, uv).x; intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0; - weight += 1.f; + weight += 1.0; } uv.x += deltaUv.x; } diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index 8822bcc649..ca67347ecf 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -446,7 +446,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende auto shapePlumber = std::make_shared(); { auto state = std::make_shared(); - state->setDepthTest(true, true, gpu::LESS); + state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); state->setScissorEnable(true); initMaskPipelines(*shapePlumber, state); diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml index f8976162ab..a78bf02d3e 100644 --- a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml +++ b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml @@ -33,7 +33,7 @@ Item { integral: false config: root.drawConfig property: "width" - max: 15.0 + max: 5.0 min: 0.0 width: 280 } From 7011fd3731ef9bf10217deac219604bf1d2314f6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 23 Oct 2017 15:46:11 +0200 Subject: [PATCH 043/171] Removed Mac and Ubuntu warnings --- libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp | 2 ++ libraries/shared/src/ViewFrustum.cpp | 24 +++++++++---------- .../utilities/render/debugOutline.js | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp index 27319e1696..528a2b524b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp @@ -501,6 +501,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E break; } case gpu::COMPRESSED: + case gpu::NUINT2: case gpu::NUM_TYPES: { // quiet compiler Q_UNREACHABLE(); } @@ -551,6 +552,7 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E break; } case gpu::COMPRESSED: + case gpu::NUINT2: case gpu::NUM_TYPES: { // quiet compiler Q_UNREACHABLE(); } diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 747b39f79e..f3eb165c51 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -590,18 +590,18 @@ bool ViewFrustum::getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm: std::array vertices; std::array boxEdges{ - Edge(BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR), - Edge(TOP_LEFT_NEAR, TOP_RIGHT_NEAR), - Edge(BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR), - Edge(TOP_LEFT_FAR, TOP_RIGHT_FAR), - Edge(BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR), - Edge(BOTTOM_LEFT_FAR, TOP_LEFT_FAR), - Edge(BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR), - Edge(BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR), - Edge(BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR), - Edge(TOP_LEFT_NEAR, TOP_LEFT_FAR), - Edge(BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR), - Edge(TOP_RIGHT_NEAR, TOP_RIGHT_FAR) + Edge{BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR}, + Edge{TOP_LEFT_NEAR, TOP_RIGHT_NEAR}, + Edge{BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR}, + Edge{TOP_LEFT_FAR, TOP_RIGHT_FAR}, + Edge{BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, + Edge{BOTTOM_LEFT_FAR, TOP_LEFT_FAR}, + Edge{BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR}, + Edge{BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR}, + Edge{BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR}, + Edge{TOP_LEFT_NEAR, TOP_LEFT_FAR}, + Edge{BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR}, + Edge{TOP_RIGHT_NEAR, TOP_RIGHT_FAR} }; std::array distancesToNearPlane; std::bitset areVerticesInside; diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugOutline.js index 72585e07fb..ce32d61e1b 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugOutline.js @@ -143,7 +143,7 @@ function update(deltaTime) { selectedID = prevID selectedType = prevType Selection.addToSelectedItemsList(selectionName, selectedType, selectedID) - //print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); + print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); } } else { if (prevID != 0 && !isSelectionAddEnabled) { From 68ed061ce59ae59a5c88444b7f3349ae02967b40 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 23 Oct 2017 16:49:42 +0200 Subject: [PATCH 044/171] Again, fix for Mac warning --- libraries/shared/src/ViewFrustum.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index f3eb165c51..dcbfd83ec7 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -589,7 +589,7 @@ bool ViewFrustum::getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm: const int MAX_VERTEX_COUNT = VERTEX_COUNT + 4 + 2; std::array vertices; - std::array boxEdges{ + std::array boxEdges{ { Edge{BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR}, Edge{TOP_LEFT_NEAR, TOP_RIGHT_NEAR}, Edge{BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR}, @@ -602,7 +602,7 @@ bool ViewFrustum::getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm: Edge{TOP_LEFT_NEAR, TOP_LEFT_FAR}, Edge{BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR}, Edge{TOP_RIGHT_NEAR, TOP_RIGHT_FAR} - }; + } }; std::array distancesToNearPlane; std::bitset areVerticesInside; int vertexCount = VERTEX_COUNT; From 99ec2aec4a8c63a4d59525fe3e718562d9ec6ca5 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 23 Oct 2017 20:44:13 +0200 Subject: [PATCH 045/171] Prevent scripts log window open several times --- interface/src/Application.cpp | 18 ++++++++++++++---- interface/src/Application.h | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b99ce5004..d03ff8f1da 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5800,6 +5800,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); + connect(scriptEngine.data(), &ScriptEngine::finished, this, &Application::cleanupRunningScripts); scriptEngine->registerGlobalObject("Overlays", &_overlays); qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); @@ -6213,10 +6214,15 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const } void Application::showScriptLogs() { - auto scriptEngines = DependencyManager::get(); - QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); - defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); - scriptEngines->loadScript(defaultScriptsLoc.toString()); + if (!_runningScripts.contains("debugWindow.js")) { + auto scriptEngines = DependencyManager::get(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); + defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); + ScriptEnginePointer sePointer = scriptEngines->loadScript(defaultScriptsLoc.toString()); + _runningScripts["debugWindow.js"] = sePointer; + } else { + qWarning() << "Scripts Log already running"; + } } void Application::showAssetServerWidget(QString filePath) { @@ -7311,6 +7317,10 @@ void Application::switchDisplayMode() { _previousHMDWornStatus = currentHMDWornStatus; } +void Application::cleanupRunningScripts(const QString &fileNameString, ScriptEnginePointer) { + _runningScripts.remove(QUrl(fileNameString).fileName()); +} + void Application::startHMDStandBySession() { _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index b6c09bbd87..65b6dd2c9e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -451,6 +451,8 @@ private slots: void handleSandboxStatus(QNetworkReply* reply); void switchDisplayMode(); + + void cleanupRunningScripts(const QString& fileNameString, ScriptEnginePointer); private: static void initDisplay(); void init(); @@ -720,5 +722,7 @@ private: std::atomic _pendingIdleEvent { false }; std::atomic _pendingRenderEvent { false }; + + QHash _runningScripts; }; #endif // hifi_Application_h From c55f93813237d2a3010237b0e5dcc6ded12f1f82 Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 24 Oct 2017 22:09:00 +0200 Subject: [PATCH 046/171] Code style fix --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d03ff8f1da..05ec8a5df1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7317,7 +7317,7 @@ void Application::switchDisplayMode() { _previousHMDWornStatus = currentHMDWornStatus; } -void Application::cleanupRunningScripts(const QString &fileNameString, ScriptEnginePointer) { +void Application::cleanupRunningScripts(const QString& fileNameString, ScriptEnginePointer) { _runningScripts.remove(QUrl(fileNameString).fileName()); } From ae8a9e68c8229c48645dd96f5a9424b217526dd1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 25 Oct 2017 11:58:16 +0200 Subject: [PATCH 047/171] Added debug tool to view shadow & view frustums --- .gitignore | 3 + libraries/gpu/src/gpu/DrawColor.slf | 19 ++++ libraries/gpu/src/gpu/StandardShaderLib.cpp | 9 ++ libraries/gpu/src/gpu/StandardShaderLib.h | 2 + .../render-utils/src/RenderDeferredTask.cpp | 86 +++++++++++++++++++ .../render-utils/src/RenderDeferredTask.h | 34 ++++++++ .../developer/utilities/render/debugShadow.js | 20 +++++ scripts/developer/utilities/render/shadow.qml | 46 ++++++++++ 8 files changed, 219 insertions(+) create mode 100644 libraries/gpu/src/gpu/DrawColor.slf create mode 100644 scripts/developer/utilities/render/debugShadow.js create mode 100644 scripts/developer/utilities/render/shadow.qml diff --git a/.gitignore b/.gitignore index 072e6001da..f085b676e4 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,9 @@ gvr-interface/libs/* TAGS *.sw[po] +# ignore QML compilation output +*.qmlc + # ignore node files for the console node_modules npm-debug.log diff --git a/libraries/gpu/src/gpu/DrawColor.slf b/libraries/gpu/src/gpu/DrawColor.slf new file mode 100644 index 0000000000..c24d69d29f --- /dev/null +++ b/libraries/gpu/src/gpu/DrawColor.slf @@ -0,0 +1,19 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Draw with color uniform +// +// Created by Olivier Prat on 25/10/2017 +// 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 +// +uniform vec4 color; + +out vec4 outFragColor; + +void main(void) { + outFragColor = color; +} diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 7143242618..0d8d131e0b 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -22,6 +22,7 @@ const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple... #include "DrawWhite_frag.h" +#include "DrawColor_frag.h" #include "DrawTexture_frag.h" #include "DrawTextureMirroredX_frag.h" #include "DrawTextureOpaque_frag.h" @@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawVertexPositionVS; ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS; ShaderPointer StandardShaderLib::_drawNadaPS; ShaderPointer StandardShaderLib::_drawWhitePS; +ShaderPointer StandardShaderLib::_drawColorPS; ShaderPointer StandardShaderLib::_drawTexturePS; ShaderPointer StandardShaderLib::_drawTextureMirroredXPS; ShaderPointer StandardShaderLib::_drawTextureOpaquePS; @@ -125,6 +127,13 @@ ShaderPointer StandardShaderLib::getDrawWhitePS() { return _drawWhitePS; } +ShaderPointer StandardShaderLib::getDrawColorPS() { + if (!_drawColorPS) { + _drawColorPS = gpu::Shader::createPixel(std::string(DrawColor_frag)); + } + return _drawColorPS; +} + ShaderPointer StandardShaderLib::getDrawTexturePS() { if (!_drawTexturePS) { _drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag)); diff --git a/libraries/gpu/src/gpu/StandardShaderLib.h b/libraries/gpu/src/gpu/StandardShaderLib.h index 94885b8ca0..9c11f6cc3a 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.h +++ b/libraries/gpu/src/gpu/StandardShaderLib.h @@ -46,6 +46,7 @@ public: static ShaderPointer getDrawNadaPS(); static ShaderPointer getDrawWhitePS(); + static ShaderPointer getDrawColorPS(); static ShaderPointer getDrawTexturePS(); static ShaderPointer getDrawTextureMirroredXPS(); static ShaderPointer getDrawTextureOpaquePS(); @@ -67,6 +68,7 @@ protected: static ShaderPointer _drawNadaPS; static ShaderPointer _drawWhitePS; + static ShaderPointer _drawColorPS; static ShaderPointer _drawTexturePS; static ShaderPointer _drawTextureMirroredXPS; static ShaderPointer _drawTextureOpaquePS; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 6a3b560167..75af8506a2 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -190,6 +190,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawLightBounds", lights); task.addJob("DrawZones", zones); + task.addJob("DrawFrustums"); } // Layered Overlays @@ -516,3 +517,88 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer }); } +void DrawFrustums::configure(const Config& configuration) { + _updateFrustums = !configuration.isFrozen; +} + +void DrawFrustums::run(const render::RenderContextPointer& renderContext) { + assert(renderContext->args); + assert(renderContext->args->_context); + + RenderArgs* args = renderContext->args; + static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 }; + + if (!_frustumMeshIndices._buffer) { + auto indices = std::make_shared(sizeof(indexData), indexData); + _frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX)); + _viewFrustumMeshVertices = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); + _viewFrustumMeshStream.addBuffer(_viewFrustumMeshVertices._buffer, _viewFrustumMeshVertices._offset, _viewFrustumMeshVertices._stride); + _shadowFrustumMeshVertices = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); + _shadowFrustumMeshStream.addBuffer(_shadowFrustumMeshVertices._buffer, _shadowFrustumMeshVertices._offset, _shadowFrustumMeshVertices._stride); + } + + if (_updateFrustums) { + updateFrustum(args->getViewFrustum(), _viewFrustumMeshVertices); + + auto lightStage = renderContext->_scene->getStage(); + assert(lightStage); + + const auto globalShadow = lightStage->getCurrentKeyShadow(); + if (globalShadow) { + updateFrustum(*globalShadow->getFrustum(), _shadowFrustumMeshVertices); + } + } + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS(); + auto ps = gpu::StandardShaderLib::getDrawColorPS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding("color", 0)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(true, false)); + _pipeline = gpu::Pipeline::create(program, state); + } + + // Render the frustums in wireframe + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setPipeline(_pipeline); + batch.setIndexBuffer(_frustumMeshIndices); + + batch._glUniform4f(0, 1.0f, 1.0f, 0.0f, 1.0f); + batch.setInputStream(0, _viewFrustumMeshStream); + batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U); + + batch._glUniform4f(0, 1.0f, 0.0f, 0.0f, 1.0f); + batch.setInputStream(0, _shadowFrustumMeshStream); + batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U); + + args->_batch = nullptr; + }); +} + +void DrawFrustums::updateFrustum(const ViewFrustum& frustum, gpu::BufferView& vertexBuffer) { + auto& vertices = vertexBuffer.edit >(); + vertices[0] = frustum.getNearTopLeft(); + vertices[1] = frustum.getNearTopRight(); + vertices[2] = frustum.getNearBottomRight(); + vertices[3] = frustum.getNearBottomLeft(); + vertices[4] = frustum.getFarTopLeft(); + vertices[5] = frustum.getFarTopRight(); + vertices[6] = frustum.getFarBottomRight(); + vertices[7] = frustum.getFarBottomLeft(); +} diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 452420589b..e8dd22359d 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -170,6 +170,40 @@ public: void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer); }; +class DrawFrustumsConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty) +public: + + DrawFrustumsConfig(bool enabled = false) : JobConfig(enabled) {} + + bool isFrozen{ false }; +signals: + void dirty(); + +}; + +class DrawFrustums { +public: + using Config = DrawFrustumsConfig; + using JobModel = render::Job::Model; + + void configure(const Config& configuration); + void run(const render::RenderContextPointer& renderContext); + +private: + + bool _updateFrustums{ true }; + gpu::PipelinePointer _pipeline; + gpu::BufferView _frustumMeshIndices; + gpu::BufferView _viewFrustumMeshVertices; + gpu::BufferView _shadowFrustumMeshVertices; + gpu::BufferStream _viewFrustumMeshStream; + gpu::BufferStream _shadowFrustumMeshStream; + + static void updateFrustum(const ViewFrustum& frustum, gpu::BufferView& vertexBuffer); +}; + class RenderDeferredTaskConfig : public render::Task::Config { Q_OBJECT Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty) diff --git a/scripts/developer/utilities/render/debugShadow.js b/scripts/developer/utilities/render/debugShadow.js new file mode 100644 index 0000000000..a0d2142258 --- /dev/null +++ b/scripts/developer/utilities/render/debugShadow.js @@ -0,0 +1,20 @@ +// +// debugShadow.js +// developer/utilities/render +// +// Olivier Prat, created on 10/25/2017. +// 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 +// + +// Set up the qml ui +var qml = Script.resolvePath('shadow.qml'); +var window = new OverlayWindow({ + title: 'Shadow Debug', + source: qml, + width: 200, + height: 90 +}); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml new file mode 100644 index 0000000000..1b4e647c77 --- /dev/null +++ b/scripts/developer/utilities/render/shadow.qml @@ -0,0 +1,46 @@ +// +// shadow.qml +// developer/utilities/render +// +// Olivier Prat, created on 10/25/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Column { + id: root + spacing: 8 + property var config: Render.getConfig("RenderMainView.DrawFrustums"); + + Component.onCompleted: { + config.enabled = true; + } + Component.onDestruction: { + config.enabled = false; + } + + CheckBox { + text: "Freeze Frustums" + checked: false + onCheckedChanged: { + config.isFrozen = checked; + } + } + Row { + spacing: 8 + Label { + text: "View" + color: "yellow" + font.italic: true + } + Label { + text: "Shadow" + color: "red" + font.italic: true + } + } +} From 6cf689a3853679c5661eb9e48f1a1b23948029cc Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 26 Oct 2017 12:42:36 +0200 Subject: [PATCH 048/171] First draft version of tighter shadow frustum --- libraries/render-utils/src/LightStage.cpp | 21 ++- libraries/render-utils/src/LightStage.h | 3 +- .../render-utils/src/RenderShadowTask.cpp | 129 +++++++++++++++-- libraries/render-utils/src/RenderShadowTask.h | 6 +- libraries/render/src/render/SortTask.cpp | 36 ++++- libraries/render/src/render/SortTask.h | 13 +- libraries/shared/src/AABox.h | 3 +- libraries/shared/src/GeometryUtil.cpp | 130 ++++++++++++++++++ libraries/shared/src/GeometryUtil.h | 4 + libraries/shared/src/Plane.h | 4 +- libraries/shared/src/Transform.h | 8 ++ 11 files changed, 335 insertions(+), 22 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 079c63f367..945bb3b9e6 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -25,7 +25,10 @@ LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); } -void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth) { +void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, + float viewMinShadowDistance, float viewMaxShadowDistance, + float nearDepth, float farDepth) { + assert(viewMinShadowDistance < viewMaxShadowDistance); assert(nearDepth < farDepth); // Orient the keylight frustum @@ -48,8 +51,8 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa const Transform view{ _frustum->getView()}; const Transform viewInverse{ view.getInverseMatrix() }; - auto nearCorners = viewFrustum.getCorners(nearDepth); - auto farCorners = viewFrustum.getCorners(farDepth); + auto nearCorners = viewFrustum.getCorners(viewMinShadowDistance); + auto farCorners = viewFrustum.getCorners(viewMaxShadowDistance); vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; vec3 max{ min }; @@ -73,6 +76,8 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa fitFrustum(farCorners.topLeft); fitFrustum(farCorners.topRight); + // Re-adjust near shadow distance to + max.z = glm::max(max.z, -nearDepth); glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); _frustum->setProjection(ortho); @@ -84,6 +89,16 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa _schemaBuffer.edit().viewInverse = viewInverse.getMatrix(); } +void LightStage::Shadow::setFrustum(const ViewFrustum& shadowFrustum) { + const Transform view{ shadowFrustum.getView() }; + const Transform viewInverse{ view.getInverseMatrix() }; + + *_frustum = shadowFrustum; + // Update the buffer + _schemaBuffer.edit().projection = shadowFrustum.getProjection(); + _schemaBuffer.edit().viewInverse = viewInverse.getMatrix(); +} + const glm::mat4& LightStage::Shadow::getView() const { return _frustum->getView(); } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 66d73c9a6e..a6e369c2f4 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -48,8 +48,9 @@ public: Shadow(model::LightPointer light); - void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth); + void setKeylightFrustum(const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f); + void setFrustum(const ViewFrustum& shadowFrustum); const std::shared_ptr getFrustum() const { return _frustum; } const glm::mat4& getView() const; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 7171543abc..80b988d055 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -22,25 +22,131 @@ #include "DeferredLightingEffect.h" #include "FramebufferCache.h" +#define SHADOW_FRUSTUM_NEAR 1.0f +#define SHADOW_FRUSTUM_FAR 100.0f + using namespace render; extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state); -void RenderShadowMap::run(const render::RenderContextPointer& renderContext, - const render::ShapeBounds& inShapes) { +static void computeNearFar(const Triangle& triangle, const Plane shadowClipPlanes[4], float& near, float& far) { + static const int MAX_TRIANGLE_COUNT = 16; + Triangle clippedTriangles[MAX_TRIANGLE_COUNT]; + auto clippedTriangleCount = clipTriangleWithPlanes(triangle, shadowClipPlanes, 4, clippedTriangles, MAX_TRIANGLE_COUNT); + + for (auto i = 0; i < clippedTriangleCount; i++) { + const auto& clippedTriangle = clippedTriangles[i]; + + near = glm::min(near, -clippedTriangle.v0.z); + near = glm::min(near, -clippedTriangle.v1.z); + near = glm::min(near, -clippedTriangle.v2.z); + + far = glm::max(far, -clippedTriangle.v0.z); + far = glm::max(far, -clippedTriangle.v1.z); + far = glm::max(far, -clippedTriangle.v2.z); + } +} + +static void computeNearFar(const glm::vec3 sceneBoundVertices[8], const Plane shadowClipPlanes[4], float& near, float& far) { + // This code is inspired from Microsoft's CascadedShadowMaps11 sample which is under MIT licence. + // See https://code.msdn.microsoft.com/windowsdesktop/Direct3D-Shadow-Win32-2d72a4f2/sourcecode?fileId=121915&pathId=1645833187 + // Basically it decomposes the object bounding box in triangles and clips each triangle with the shadow + // frustum planes. Finally it computes the minimum and maximum depth of the clipped triangle vertices + // in shadow space to extract the near and far distances of the shadow frustum. + static const std::array boxQuadVertexIndices = { { + { TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR }, + { TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR }, + { TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR }, + { TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR }, + { BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, BOTTOM_LEFT_NEAR }, + { TOP_LEFT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR } + } }; + Triangle triangle; + + for (auto quadVertexIndices : boxQuadVertexIndices) { + triangle.v0 = sceneBoundVertices[quadVertexIndices[0]]; + triangle.v1 = sceneBoundVertices[quadVertexIndices[1]]; + triangle.v2 = sceneBoundVertices[quadVertexIndices[2]]; + computeNearFar(triangle, shadowClipPlanes, near, far); + triangle.v1 = sceneBoundVertices[quadVertexIndices[3]]; + computeNearFar(triangle, shadowClipPlanes, near, far); + } +} + +static void adjustNearFar(const AABox& inShapeBounds, ViewFrustum& shadowFrustum) { + const Transform shadowView{ shadowFrustum.getView() }; + const Transform shadowViewInverse{ shadowView.getInverseMatrix() }; + + glm::vec3 sceneBoundVertices[8]; + // Keep only the left, right, top and bottom shadow frustum planes as we wish to determine + // the near and far + Plane shadowClipPlanes[4]; + int i; + + // The vertices of the scene bounding box are expressed in the shadow frustum's local space + for (i = 0; i < 8; i++) { + sceneBoundVertices[i] = shadowViewInverse.transform(inShapeBounds.getVertex(static_cast(i))); + } + // This indirection array is just a protection in case the ViewFrustum::PlaneIndex enum + // changes order especially as we don't need to test the NEAR and FAR planes. + static const ViewFrustum::PlaneIndex planeIndices[4] = { + ViewFrustum::TOP_PLANE, + ViewFrustum::BOTTOM_PLANE, + ViewFrustum::LEFT_PLANE, + ViewFrustum::RIGHT_PLANE + }; + // Same goes for the shadow frustum planes. + for (i = 0; i < 4; i++) { + const auto& worldPlane = shadowFrustum.getPlanes()[planeIndices[i]]; + // We assume the transform doesn't have a non uniform scale component to apply the + // transform to the normal without using the correct transpose of inverse, which should be the + // case for a view matrix. + auto planeNormal = shadowViewInverse.transformDirection(worldPlane.getNormal()); + auto planePoint = shadowViewInverse.transform(worldPlane.getPoint()); + shadowClipPlanes[i].setNormalAndPoint(planeNormal, planePoint); + } + + float near = std::numeric_limits::max(); + float far = 0.0f; + + computeNearFar(sceneBoundVertices, shadowClipPlanes, near, far); + + const auto depthEpsilon = 0.25f; + auto projMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, near - depthEpsilon, far + depthEpsilon); + auto shadowProjection = shadowFrustum.getProjection(); + + shadowProjection[2][2] = projMatrix[2][2]; + shadowProjection[3][2] = projMatrix[3][2]; + shadowFrustum.setProjection(shadowProjection); + shadowFrustum.calculate(); +} + +void RenderShadowMap::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); + const auto& inShapes = inputs.get0(); + const auto& inShapeBounds = inputs.get1(); + auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - const auto shadow = lightStage->getCurrentKeyShadow(); + auto shadow = lightStage->getCurrentKeyShadow(); if (!shadow) return; const auto& fbo = shadow->framebuffer; RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; + auto adjustedShadowFrustum = args->getViewFrustum(); + + // Adjust the frustum near and far depths based on the rendered items bounding box to have + // the minimal Z range. + adjustNearFar(inShapeBounds, adjustedShadowFrustum); + // Reapply the frustum as it has been adjusted + shadow->setFrustum(adjustedShadowFrustum); + args->popViewFrustum(); + args->pushViewFrustum(adjustedShadowFrustum); gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -55,8 +161,13 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true); - batch.setProjectionTransform(shadow->getProjection()); - batch.setViewTransform(shadow->getView(), false); + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat, false); auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); @@ -109,10 +220,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende // Sort const auto sortedPipelines = task.addJob("PipelineSortShadowSort", culledShadowSelection); - const auto sortedShapes = task.addJob("DepthSortShadowMap", sortedPipelines); + const auto sortedShapesAndBounds = task.addJob("DepthSortShadowMap", sortedPipelines, true); // GPU jobs: Render to shadow map - task.addJob("RenderShadowMap", sortedShapes, shapePlumber); + task.addJob("RenderShadowMap", sortedShapesAndBounds, shapePlumber); task.addJob("ShadowTeardown", cachedMode); } @@ -135,8 +246,8 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O auto nearClip = args->getViewFrustum().getNearClip(); float nearDepth = -args->_boomOffset.z; - const int SHADOW_FAR_DEPTH = 20; - globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); + const float SHADOW_MAX_DISTANCE = 20.0f; + globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); // Set the keylight render args args->pushViewFrustum(*(globalShadow->getFrustum())); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 031f44a42d..7b2bbeb306 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -21,11 +21,11 @@ class ViewFrustum; class RenderShadowMap { public: - using JobModel = render::Job::ModelI; + using Inputs = render::VaryingSet2; + using JobModel = render::Job::ModelI; RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} - void run(const render::RenderContextPointer& renderContext, - const render::ShapeBounds& inShapes); + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; diff --git a/libraries/render/src/render/SortTask.cpp b/libraries/render/src/render/SortTask.cpp index 5b7ead4b6a..f789f8c5c6 100644 --- a/libraries/render/src/render/SortTask.cpp +++ b/libraries/render/src/render/SortTask.cpp @@ -40,7 +40,8 @@ struct BackToFrontSort { } }; -void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) { +void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, + const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); @@ -75,8 +76,18 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron } // Finally once sorted result to a list of itemID - for (auto& item : itemBoundSorts) { - outItems.emplace_back(ItemBound(item._id, item._bounds)); + if (!bounds) { + for (auto& item : itemBoundSorts) { + outItems.emplace_back(ItemBound(item._id, item._bounds)); + } + } else if (!itemBoundSorts.empty()) { + if (bounds->isNull()) { + *bounds = itemBoundSorts.front()._bounds; + } + for (auto& item : itemBoundSorts) { + *bounds += item._bounds; + outItems.emplace_back(ItemBound(item._id, item._bounds)); + } } } @@ -115,6 +126,25 @@ void DepthSortShapes::run(const RenderContextPointer& renderContext, const Shape } } +void DepthSortShapesAndComputeBounds::run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs) { + auto& outShapes = outputs.edit0(); + auto& outBounds = outputs.edit1(); + + outShapes.clear(); + outShapes.reserve(inShapes.size()); + outBounds = AABox(); + + for (auto& pipeline : inShapes) { + auto& inItems = pipeline.second; + auto outItems = outShapes.find(pipeline.first); + if (outItems == outShapes.end()) { + outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first; + } + + depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &outBounds); + } +} + void DepthSortItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { depthSortItems(renderContext, _frontToBack, inItems, outItems); } diff --git a/libraries/render/src/render/SortTask.h b/libraries/render/src/render/SortTask.h index dfeb22d540..de670b1676 100644 --- a/libraries/render/src/render/SortTask.h +++ b/libraries/render/src/render/SortTask.h @@ -15,7 +15,7 @@ #include "Engine.h" namespace render { - void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems); + void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds = nullptr); class PipelineSortShapes { public: @@ -33,6 +33,17 @@ namespace render { void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes); }; + class DepthSortShapesAndComputeBounds { + public: + using Outputs = VaryingSet2; + using JobModel = Job::ModelIO; + + bool _frontToBack; + DepthSortShapesAndComputeBounds(bool frontToBack = true) : _frontToBack(frontToBack) {} + + void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs); + }; + class DepthSortItems { public: using JobModel = Job::ModelIO; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index eef83974ea..24485eaad6 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -127,10 +127,11 @@ public: AABox getOctreeChild(OctreeChild child) const; // returns the AABox of the would be octree child of this AABox + glm::vec4 getPlane(BoxFace face) const; + private: glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; - glm::vec4 getPlane(BoxFace face) const; static BoxFace getOppositeFace(BoxFace face); diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 6b9718fbb8..e502d44a08 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -14,10 +14,12 @@ #include #include #include +#include #include #include "NumericalConstants.h" #include "GLMHelpers.h" +#include "Plane.h" glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) { // compute the projection of the point vector onto the segment vector @@ -314,6 +316,134 @@ bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direc return false; } +static void getTrianglePlaneIntersectionPoints(const glm::vec3 trianglePoints[3], const float pointPlaneDistances[3], + const int clippedPointIndex, const int keptPointIndices[2], + glm::vec3 points[2]) { + assert(clippedPointIndex >= 0 && clippedPointIndex < 3); + const auto& clippedPoint = trianglePoints[clippedPointIndex]; + const float clippedPointPlaneDistance = pointPlaneDistances[clippedPointIndex]; + for (auto i = 0; i < 2; i++) { + assert(keptPointIndices[i] >= 0 && keptPointIndices[i] < 3); + const auto& keptPoint = trianglePoints[keptPointIndices[i]]; + const float keptPointPlaneDistance = pointPlaneDistances[keptPointIndices[i]]; + auto intersectionEdgeRatio = clippedPointPlaneDistance / (clippedPointPlaneDistance - keptPointPlaneDistance); + points[i] = clippedPoint + (keptPoint - clippedPoint) * intersectionEdgeRatio; + } +} + +int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount) { + float pointDistanceToPlane[3]; + std::bitset<3> arePointsClipped; + glm::vec3 triangleVertices[3] = { triangle.v0, triangle.v1, triangle.v2 }; + int clippedTriangleCount = 0; + int i; + + assert(clippedTriangleCount > 0); + + for (i = 0; i < 3; i++) { + pointDistanceToPlane[i] = plane.distance(triangleVertices[i]); + arePointsClipped.set(i, pointDistanceToPlane[i] < 0.0f); + } + + switch (arePointsClipped.count()) { + case 0: + // Easy, the entire triangle is kept as is. + *clippedTriangles = triangle; + clippedTriangleCount = 1; + break; + + case 1: + { + int clippedPointIndex = 2; + int keptPointIndices[2] = { 0, 1 }; + glm::vec3 newVertices[2]; + + // Determine which point was clipped. + if (arePointsClipped.test(0)) { + clippedPointIndex = 0; + keptPointIndices[0] = 2; + } else if (arePointsClipped.test(1)) { + clippedPointIndex = 1; + keptPointIndices[1] = 2; + } + // We have a quad now, so we need to create two triangles. + getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, clippedPointIndex, keptPointIndices, newVertices); + clippedTriangles->v0 = triangleVertices[keptPointIndices[0]]; + clippedTriangles->v1 = triangleVertices[keptPointIndices[1]]; + clippedTriangles->v2 = newVertices[1]; + clippedTriangles++; + clippedTriangleCount++; + + if (clippedTriangleCount < maxClippedTriangleCount) { + clippedTriangles->v0 = triangleVertices[keptPointIndices[0]]; + clippedTriangles->v1 = newVertices[0]; + clippedTriangles->v2 = newVertices[1]; + clippedTriangles++; + clippedTriangleCount++; + } + } + break; + + case 2: + { + int keptPointIndex = 2; + int clippedPointIndices[2] = { 0, 1 }; + glm::vec3 newVertices[2]; + + // Determine which point was NOT clipped. + if (!arePointsClipped.test(0)) { + keptPointIndex = 0; + clippedPointIndices[0] = 2; + } else if (!arePointsClipped.test(1)) { + keptPointIndex = 1; + clippedPointIndices[1] = 2; + } + // We have a single triangle + getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, keptPointIndex, clippedPointIndices, newVertices); + clippedTriangles->v0 = triangleVertices[keptPointIndex]; + clippedTriangles->v1 = newVertices[0]; + clippedTriangles->v2 = newVertices[1]; + clippedTriangleCount = 1; + } + break; + + default: + // Entire triangle is clipped. + break; + } + + return clippedTriangleCount; +} + +int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount) { + auto planesEnd = planes + planeCount; + int triangleCount = 1; + std::vector trianglesToTest; + + assert(maxClippedTriangleCount > 0); + + *clippedTriangles = triangle; + + while (planes < planesEnd) { + int clippedSubTriangleCount; + + trianglesToTest.clear(); + trianglesToTest.insert(trianglesToTest.begin(), clippedTriangles, clippedTriangles + triangleCount); + triangleCount = 0; + + for (const auto& triangleToTest : trianglesToTest) { + clippedSubTriangleCount = clipTriangleWithPlane(triangleToTest, *planes, + clippedTriangles + triangleCount, maxClippedTriangleCount - triangleCount); + triangleCount += clippedSubTriangleCount; + if (triangleCount >= maxClippedTriangleCount) { + return triangleCount; + } + } + ++planes; + } + return triangleCount; +} + // Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect? // from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) { diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index eb9424d938..dcb90643b6 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -15,6 +15,8 @@ #include #include +class Plane; + glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end); /// Computes the penetration between a point and a sphere (centered at the origin) @@ -109,6 +111,8 @@ inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3 return findRayTriangleIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance, allowBackface); } +int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount); +int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount); bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2); bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk); diff --git a/libraries/shared/src/Plane.h b/libraries/shared/src/Plane.h index c903ad9db7..cf17ca7201 100644 --- a/libraries/shared/src/Plane.h +++ b/libraries/shared/src/Plane.h @@ -19,7 +19,9 @@ class Plane { public: - Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1,v2,v3); } + Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1, v2, v3); } + Plane(const glm::vec3 &normal, const glm::vec3 &point) { setNormalAndPoint(normal, point); } + Plane(float a, float b, float c, float d) { setCoefficients(a, b, c, d); } Plane() : _normal(0.0f), _point(0.0f), _dCoefficient(0.0f) {}; ~Plane() {} ; diff --git a/libraries/shared/src/Transform.h b/libraries/shared/src/Transform.h index 316fcb2f04..71d8b6c915 100644 --- a/libraries/shared/src/Transform.h +++ b/libraries/shared/src/Transform.h @@ -149,6 +149,7 @@ public: Vec4 transform(const Vec4& pos) const; Vec3 transform(const Vec3& pos) const; + Vec3 transformDirection(const Vec3& pos) const; bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); } @@ -541,6 +542,13 @@ inline Transform::Vec3 Transform::transform(const Vec3& pos) const { return Vec3(result.x / result.w, result.y / result.w, result.z / result.w); } +inline Transform::Vec3 Transform::transformDirection(const Vec3& pos) const { + Mat4 m; + getMatrix(m); + Vec4 result = m * Vec4(pos, 0.0f); + return Vec3(result.x, result.y, result.z); +} + inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const { updateCache(); result = (*_matrix); From 9eed69d7ef39c0a8475dbbeae4037519993eed65 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 26 Oct 2017 15:11:42 +0200 Subject: [PATCH 049/171] Trying to pin point a zone bug --- .../src/RenderableZoneEntityItem.cpp | 6 +++- .../src/DeferredLightingEffect.cpp | 8 ++--- libraries/render-utils/src/DrawHaze.cpp | 6 ++-- libraries/render-utils/src/LightStage.cpp | 32 +++++++++++++++++++ libraries/render-utils/src/LightStage.h | 28 +++------------- .../render-utils/src/RenderShadowTask.cpp | 9 ++++-- 6 files changed, 56 insertions(+), 33 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 0235f1b7a3..7a30414360 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -40,22 +40,26 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity if (_stage) { if (!LightStage::isIndexInvalid(_sunIndex)) { _stage->removeLight(_sunIndex); + _sunIndex = INVALID_INDEX; + _shadowIndex = INVALID_INDEX; } if (!LightStage::isIndexInvalid(_ambientIndex)) { _stage->removeLight(_ambientIndex); - + _ambientIndex = INVALID_INDEX; } } if (_backgroundStage) { if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) { _backgroundStage->removeBackground(_backgroundIndex); + _backgroundIndex = INVALID_INDEX; } } if (_hazeStage) { if (!HazeStage::isIndexInvalid(_hazeIndex)) { _hazeStage->removeHaze(_hazeIndex); + _hazeIndex = INVALID_INDEX; } } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index b6a91888a1..5068047d20 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -105,13 +105,13 @@ void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Bat PerformanceTimer perfTimer("DLE->setupBatch()"); model::LightPointer keySunLight; auto lightStage = args->_scene->getStage(); - if (lightStage && lightStage->_currentFrame._sunLights.size()) { - keySunLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); + if (lightStage) { + keySunLight = lightStage->getCurrentKeyLight(); } model::LightPointer keyAmbiLight; - if (lightStage && lightStage->_currentFrame._ambientLights.size()) { - keyAmbiLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front()); + if (lightStage) { + keyAmbiLight = lightStage->getCurrentAmbientLight(); } if (keySunLight) { diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index bf254ce80e..fc751e9dc1 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -191,9 +191,9 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer()); auto lightStage = args->_scene->getStage(); - if (lightStage && lightStage->_currentFrame._sunLights.size() > 0) { - model::LightPointer keyLight; - keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front()); + if (lightStage) { + model::LightPointer keyLight; + keyLight = lightStage->getCurrentKeyLight(); if (keyLight != nullptr) { batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer()); } diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 945bb3b9e6..0a18c19698 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -168,6 +168,38 @@ LightStage::LightPointer LightStage::removeLight(Index index) { return removed; } +LightStage::LightPointer LightStage::getCurrentKeyLight() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return _lights.get(keyLightId); +} + +LightStage::LightPointer LightStage::getCurrentAmbientLight() const { + Index keyLightId{ 0 }; + if (!_currentFrame._ambientLights.empty()) { + keyLightId = _currentFrame._ambientLights.front(); + } + return _lights.get(keyLightId); +} + +LightStage::ShadowPointer LightStage::getCurrentKeyShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return getShadow(keyLightId); +} + +LightStage::LightAndShadow LightStage::getCurrentKeyLightAndShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return LightAndShadow(getLight(keyLightId), getShadow(keyLightId)); +} + void LightStage::updateLightArrayBuffer(Index lightId) { auto lightSize = sizeof(model::Light::LightSchema); if (!_lightArrayBuffer) { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index a6e369c2f4..cb310ce54d 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -117,31 +117,13 @@ public: return LightAndShadow(getLight(lightId), getShadow(lightId)); } - LightPointer getCurrentKeyLight() const { - Index keyLightId{ 0 }; - if (!_currentFrame._sunLights.empty()) { - keyLightId = _currentFrame._sunLights.front(); - } - return _lights.get(keyLightId); - } - - ShadowPointer getCurrentKeyShadow() const { - Index keyLightId{ 0 }; - if (!_currentFrame._sunLights.empty()) { - keyLightId = _currentFrame._sunLights.front(); - } - return getShadow(keyLightId); - } - - LightAndShadow getCurrentKeyLightAndShadow() const { - Index keyLightId{ 0 }; - if (!_currentFrame._sunLights.empty()) { - keyLightId = _currentFrame._sunLights.front(); - } - return LightAndShadow(getLight(keyLightId), getShadow(keyLightId)); - } + LightPointer getCurrentKeyLight() const; + LightPointer getCurrentAmbientLight() const; + ShadowPointer getCurrentKeyShadow() const; + LightAndShadow getCurrentKeyLightAndShadow() const; LightStage(); + Lights _lights; LightMap _lightMap; Descs _descs; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 80b988d055..9bf915b33e 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -22,8 +22,10 @@ #include "DeferredLightingEffect.h" #include "FramebufferCache.h" +// These values are used for culling the objects rendered in the shadow map +// but are readjusted afterwards #define SHADOW_FRUSTUM_NEAR 1.0f -#define SHADOW_FRUSTUM_FAR 100.0f +#define SHADOW_FRUSTUM_FAR 500.0f using namespace render; @@ -110,8 +112,11 @@ static void adjustNearFar(const AABox& inShapeBounds, ViewFrustum& shadowFrustum float far = 0.0f; computeNearFar(sceneBoundVertices, shadowClipPlanes, near, far); + // Limit the far range to the one used originally. There's no point in rendering objects + // that are not in the view frustum. + far = glm::min(far, shadowFrustum.getFarClip()); - const auto depthEpsilon = 0.25f; + const auto depthEpsilon = 0.1f; auto projMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, near - depthEpsilon, far + depthEpsilon); auto shadowProjection = shadowFrustum.getProjection(); From 5d83284ac59ae680408285ae05c0cc1f67999772 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 26 Oct 2017 16:47:20 +0200 Subject: [PATCH 050/171] Fixed small bug in shadow bounds computation --- libraries/render/src/render/SortTask.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/render/src/render/SortTask.cpp b/libraries/render/src/render/SortTask.cpp index f789f8c5c6..987b25358a 100644 --- a/libraries/render/src/render/SortTask.cpp +++ b/libraries/render/src/render/SortTask.cpp @@ -140,8 +140,14 @@ void DepthSortShapesAndComputeBounds::run(const RenderContextPointer& renderCont if (outItems == outShapes.end()) { outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first; } + AABox bounds; - depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &outBounds); + depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &bounds); + if (!outBounds.isNull()) { + outBounds += bounds; + } else { + outBounds = bounds; + } } } From 44393f12d9409f9ed556ba934d4cf105ca6241cf Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 26 Oct 2017 17:41:54 +0200 Subject: [PATCH 051/171] Adjusted bias --- libraries/render-utils/src/LightStage.cpp | 7 ++++--- libraries/render-utils/src/LightStage.h | 2 +- libraries/render-utils/src/RenderShadowTask.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 0a18c19698..b13e46788d 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -76,9 +76,10 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, fitFrustum(farCorners.topLeft); fitFrustum(farCorners.topRight); - // Re-adjust near shadow distance to - max.z = glm::max(max.z, -nearDepth); - glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, -max.z, -min.z); + // Re-adjust near shadow distance + auto near = glm::max(max.z, -nearDepth); + auto far = -min.z; + glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, near, far); _frustum->setProjection(ortho); // Calculate the frustum's internal state diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index cb310ce54d..706caec9d6 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -69,7 +69,7 @@ public: glm::mat4 projection; glm::mat4 viewInverse; - glm::float32 bias = 0.005f; + glm::float32 bias = 0.003f; glm::float32 scale = 1 / MAP_SIZE; }; UniformBufferView _schemaBuffer = nullptr; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 9bf915b33e..7a6e3dc74f 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -203,7 +203,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con } void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { - cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; + cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; }; // Prepare the ShapePipeline ShapePlumberPointer shapePlumber = std::make_shared(); From 0044759196656a08ffadfeae09ffe3b4e3a9e3d5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 26 Oct 2017 18:29:29 +0200 Subject: [PATCH 052/171] Disabled broken PCF and reset back to previous bias --- libraries/render-utils/src/LightStage.cpp | 6 ++++++ libraries/render-utils/src/LightStage.h | 8 ++++++-- libraries/render-utils/src/Shadow.slh | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index b13e46788d..411f179d49 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -18,6 +18,12 @@ std::string LightStage::_stageName { "LIGHT_STAGE"}; LightStage::LightStage() { } +LightStage::Shadow::Schema::Schema() : + bias{ 0.005f }, + scale{ 1.0f / MAP_SIZE } { + +} + LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); map = framebuffer->getDepthStencilBuffer(); diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 706caec9d6..3a2a77055f 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -60,17 +60,21 @@ public: gpu::FramebufferPointer framebuffer; gpu::TexturePointer map; + protected: model::LightPointer _light; std::shared_ptr _frustum; class Schema { public: + + Schema(); + glm::mat4 projection; glm::mat4 viewInverse; - glm::float32 bias = 0.003f; - glm::float32 scale = 1 / MAP_SIZE; + glm::float32 bias; + glm::float32 scale; }; UniformBufferView _schemaBuffer = nullptr; diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 7b86b9b660..e844db43dd 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -68,6 +68,8 @@ vec2 PCFkernel[4] = vec2[4]( ); float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) { + // PCF is buggy so disable it for the time being +#if 0 float pcfRadius = 3.0; float shadowScale = getShadowScale(); @@ -80,6 +82,9 @@ float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) { fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[2], 0.0)) + fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[3], 0.0)) )); +#else + float shadowAttenuation = fetchShadow(shadowTexcoord.xyz); +#endif return shadowAttenuation; } From 45e571dd02cfed91b8a4c7e954b7693fd1b11617 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Oct 2017 08:16:41 -0700 Subject: [PATCH 053/171] cleanup ShapeInfo::getHash() --- libraries/physics/src/ShapeManager.cpp | 8 +- libraries/physics/src/ShapeManager.h | 10 +- libraries/shared/src/HashKey.cpp | 67 +++++++++++++ libraries/shared/src/HashKey.h | 52 ++++++++++ libraries/shared/src/ShapeInfo.cpp | 119 +++++------------------ libraries/shared/src/ShapeInfo.h | 6 +- tests/physics/src/ShapeInfoTests.cpp | 129 +++++++++---------------- tests/physics/src/ShapeInfoTests.h | 4 - 8 files changed, 202 insertions(+), 193 deletions(-) create mode 100644 libraries/shared/src/HashKey.cpp create mode 100644 libraries/shared/src/HashKey.h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 77716f671b..97b9e5dab1 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -32,7 +32,7 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { return nullptr; } - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { shapeRef->refCount++; @@ -50,7 +50,7 @@ const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { } // private helper method -bool ShapeManager::releaseShapeByKey(const DoubleHashKey& key) { +bool ShapeManager::releaseShapeByKey(const HashKey& key) { ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->refCount > 0) { @@ -88,7 +88,7 @@ bool ShapeManager::releaseShape(const btCollisionShape* shape) { void ShapeManager::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { - DoubleHashKey& key = _pendingGarbage[i]; + HashKey& key = _pendingGarbage[i]; ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef && shapeRef->refCount == 0) { ShapeFactory::deleteShape(shapeRef->shape); @@ -99,7 +99,7 @@ void ShapeManager::collectGarbage() { } int ShapeManager::getNumReferences(const ShapeInfo& info) const { - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); const ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { return shapeRef->refCount; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index ed81b5e8f8..6ec3573b53 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -17,7 +17,7 @@ #include -#include "DoubleHashKey.h" +#include "HashKey.h" class ShapeManager { public: @@ -41,18 +41,18 @@ public: bool hasShape(const btCollisionShape* shape) const; private: - bool releaseShapeByKey(const DoubleHashKey& key); + bool releaseShapeByKey(const HashKey& key); class ShapeReference { public: int refCount; const btCollisionShape* shape; - DoubleHashKey key; + HashKey key; ShapeReference() : refCount(0), shape(nullptr) {} }; - btHashMap _shapeMap; - btAlignedObjectArray _pendingGarbage; + btHashMap _shapeMap; + btAlignedObjectArray _pendingGarbage; }; #endif // hifi_ShapeManager_h diff --git a/libraries/shared/src/HashKey.cpp b/libraries/shared/src/HashKey.cpp new file mode 100644 index 0000000000..488eccb1bf --- /dev/null +++ b/libraries/shared/src/HashKey.cpp @@ -0,0 +1,67 @@ +// +// HashKey.cpp +// libraries/shared/src +// +// Created by Andrew Meadows 2017.10.25 +// 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 +// + +#include "HashKey.h" + +#include "NumericalConstants.h" + + +const uint8_t NUM_PRIMES = 64; +const uint64_t PRIMES[] = { + 4194301UL, 4194287UL, 4194277UL, 4194271UL, 4194247UL, 4194217UL, 4194199UL, 4194191UL, + 4194187UL, 4194181UL, 4194173UL, 4194167UL, 4194143UL, 4194137UL, 4194131UL, 4194107UL, + 4194103UL, 4194023UL, 4194011UL, 4194007UL, 4193977UL, 4193971UL, 4193963UL, 4193957UL, + 4193939UL, 4193929UL, 4193909UL, 4193869UL, 4193807UL, 4193803UL, 4193801UL, 4193789UL, + 4193759UL, 4193753UL, 4193743UL, 4193701UL, 4193663UL, 4193633UL, 4193573UL, 4193569UL, + 4193551UL, 4193549UL, 4193531UL, 4193513UL, 4193507UL, 4193459UL, 4193447UL, 4193443UL, + 4193417UL, 4193411UL, 4193393UL, 4193389UL, 4193381UL, 4193377UL, 4193369UL, 4193359UL, + 4193353UL, 4193327UL, 4193309UL, 4193303UL, 4193297UL, 4193279UL, 4193269UL, 4193263UL +}; + + +// this hash function inspired by Squirrel Eiserloh's GDC2017 talk: "Noise-Based RNG" +uint64_t squirrel3_64(uint64_t data, uint8_t primeIndex) { + constexpr uint64_t BIT_NOISE1 = 2760725261486592643UL; + constexpr uint64_t BIT_NOISE2 = 6774464464027632833UL; + constexpr uint64_t BIT_NOISE3 = 5545331650366059883UL; + + // blend prime numbers into the hash to prevent dupes + // when hashing the same set of numbers in a different order + uint64_t hash = PRIMES[primeIndex % NUM_PRIMES] * data; + hash *= BIT_NOISE1; + hash ^= (hash >> 16); + hash += BIT_NOISE2; + hash ^= (hash << 16); + hash *= BIT_NOISE3; + return hash ^ (hash >> 16); +} + +constexpr float QUANTIZED_VALUES_PER_METER = 250.0f; + +// static +float HashKey::getNumQuantizedValuesPerMeter() { + return QUANTIZED_VALUES_PER_METER; +} + +void HashKey::hashUint64(uint64_t data) { + _hash += squirrel3_64(data, ++_hashCount); +} + +void HashKey::hashFloat(float data) { + _hash += squirrel3_64((uint64_t)((int64_t)(data * QUANTIZED_VALUES_PER_METER)), ++_hashCount); +} + +void HashKey::hashVec3(const glm::vec3& data) { + _hash += squirrel3_64((uint64_t)((int64_t)(data[0] * QUANTIZED_VALUES_PER_METER)), ++_hashCount); + _hash *= squirrel3_64((uint64_t)((int64_t)(data[1] * QUANTIZED_VALUES_PER_METER)), ++_hashCount); + _hash ^= squirrel3_64((uint64_t)((int64_t)(data[2] * QUANTIZED_VALUES_PER_METER)), ++_hashCount); +} + diff --git a/libraries/shared/src/HashKey.h b/libraries/shared/src/HashKey.h new file mode 100644 index 0000000000..5fce182084 --- /dev/null +++ b/libraries/shared/src/HashKey.h @@ -0,0 +1,52 @@ +// +// HashKey.h +// libraries/shared/src +// +// Created by Andrew Meadows 2017.10.25 +// 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 +// + +#ifndef hifi_HashKey_h +#define hifi_HashKey_h + +#include +#include + +#include + + +// HashKey for use with btHashMap which requires a particular API for its keys. In particular it +// requires its Key to implement these methods: +// +// bool Key::equals() +// int32_t Key::getHash() +// +// The important thing about the HashKey implementation is that while getHash() returns 32-bits, +// internally HashKey stores a 64-bit hash which is used for the equals() comparison. This allows +// btHashMap to insert "dupe" 32-bit keys to different "values". + +class HashKey { +public: + static float getNumQuantizedValuesPerMeter(); + + // These two methods are required by btHashMap. + bool equals(const HashKey& other) const { return _hash == other._hash; } + int32_t getHash() const { return (int32_t)((uint32_t)_hash); } + + void clear() { _hash = _hashCount = 0; } + bool isNull() const { return _hash == 0 && _hashCount == 0; } + void hashUint64(uint64_t data); + void hashFloat(float data); + void hashVec3(const glm::vec3& data); + + uint64_t getHash64() const { return _hash; } // for debug/test purposes + +private: + uint64_t _hash { 0 }; + uint8_t _hashCount { 0 }; +}; + +#endif // hifi_HashKey_h diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 36ce38335a..8cdc4bcf14 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -53,7 +53,7 @@ void ShapeInfo::clear() { _triangleIndices.clear(); _halfExtents = glm::vec3(0.0f); _offset = glm::vec3(0.0f); - _doubleHashKey.clear(); + _hashKey.clear(); _type = SHAPE_TYPE_NONE; } @@ -87,14 +87,14 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString default: break; } - _doubleHashKey.clear(); + _hashKey.clear(); } void ShapeInfo::setBox(const glm::vec3& halfExtents) { _url = ""; _type = SHAPE_TYPE_BOX; setHalfExtents(halfExtents); - _doubleHashKey.clear(); + _hashKey.clear(); } void ShapeInfo::setSphere(float radius) { @@ -102,12 +102,12 @@ void ShapeInfo::setSphere(float radius) { _type = SHAPE_TYPE_SPHERE; radius = glm::max(radius, MIN_HALF_EXTENT); _halfExtents = glm::vec3(radius); - _doubleHashKey.clear(); + _hashKey.clear(); } void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) { _pointCollection = pointCollection; - _doubleHashKey.clear(); + _hashKey.clear(); } void ShapeInfo::setCapsuleY(float radius, float halfHeight) { @@ -116,12 +116,12 @@ void ShapeInfo::setCapsuleY(float radius, float halfHeight) { radius = glm::max(radius, MIN_HALF_EXTENT); halfHeight = glm::max(halfHeight, 0.0f); _halfExtents = glm::vec3(radius, halfHeight, radius); - _doubleHashKey.clear(); + _hashKey.clear(); } void ShapeInfo::setOffset(const glm::vec3& offset) { _offset = offset; - _doubleHashKey.clear(); + _hashKey.clear(); } uint32_t ShapeInfo::getNumSubShapes() const { @@ -256,119 +256,46 @@ bool ShapeInfo::contains(const glm::vec3& point) const { } } -const DoubleHashKey& ShapeInfo::getHash() const { +const HashKey& ShapeInfo::getHash() const { // NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance. - if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) { - bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET; + if (_hashKey.isNull() && _type != SHAPE_TYPE_NONE) { // The key is not yet cached therefore we must compute it. - // compute hash1 - // TODO?: provide lookup table for hash/hash2 of _type rather than recompute? - uint32_t primeIndex = 0; - _doubleHashKey.computeHash((uint32_t)_type, primeIndex++); - + _hashKey.hashUint64((uint64_t)_type); if (_type != SHAPE_TYPE_SIMPLE_HULL) { - // compute hash1 - uint32_t hash = _doubleHashKey.getHash(); - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - hash ^= DoubleHashKey::hashFunction( - (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f), - primeIndex++); - if (useOffset) { - hash ^= DoubleHashKey::hashFunction( - (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f), - primeIndex++); - } - } - _doubleHashKey.setHash(hash); - - // compute hash2 - hash = _doubleHashKey.getHash2(); - for (int j = 0; j < 3; ++j) { - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - uint32_t floatHash = DoubleHashKey::hashFunction2( - (uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f)); - if (useOffset) { - floatHash ^= DoubleHashKey::hashFunction2( - (uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f)); - } - hash += ~(floatHash << 17); - hash ^= (floatHash >> 11); - hash += (floatHash << 4); - hash ^= (floatHash >> 7); - hash += ~(floatHash << 10); - hash = (hash << 16) | (hash >> 16); - } - _doubleHashKey.setHash2(hash); + _hashKey.hashVec3(_halfExtents); + _hashKey.hashVec3(_offset); } else { - + // TODO: we could avoid hashing all of these points if we were to supply the ShapeInfo with a unique + // descriptive string. Shapes that are uniquely described by their type and URL could just put their + // url in the description. assert(_pointCollection.size() == (size_t)1); const PointList & points = _pointCollection.back(); const int numPoints = (int)points.size(); - uint32_t hash = _doubleHashKey.getHash(); - uint32_t hash2 = _doubleHashKey.getHash2(); - for (int pointIndex = 0; pointIndex < numPoints; ++pointIndex) { - // compute hash1 & 2 - const glm::vec3 &curPoint = points[pointIndex]; - for (int vecCompIndex = 0; vecCompIndex < 3; ++vecCompIndex) { - - // NOTE: 0.49f is used to bump the float up almost half a millimeter - // so the cast to int produces a round() effect rather than a floor() - uint32_t valueToHash = (uint32_t)(curPoint[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, curPoint[vecCompIndex]) * 0.49f); - - hash ^= DoubleHashKey::hashFunction(valueToHash, primeIndex++); - uint32_t floatHash = DoubleHashKey::hashFunction2(valueToHash); - - if (useOffset) { - - const uint32_t offsetValToHash = (uint32_t)(_offset[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[vecCompIndex])* 0.49f); - - hash ^= DoubleHashKey::hashFunction(offsetValToHash, primeIndex++); - floatHash ^= DoubleHashKey::hashFunction2(offsetValToHash); - } - - hash2 += ~(floatHash << 17); - hash2 ^= (floatHash >> 11); - hash2 += (floatHash << 4); - hash2 ^= (floatHash >> 7); - hash2 += ~(floatHash << 10); - hash2 = (hash2 << 16) | (hash2 >> 16); - } + for (int i = 0; i < numPoints; ++i) { + _hashKey.hashVec3(points[i]); } - - _doubleHashKey.setHash(hash); - _doubleHashKey.setHash2(hash2); } QString url = _url.toString(); if (!url.isEmpty()) { - // fold the urlHash into both parts QByteArray baUrl = url.toLocal8Bit(); uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size()); - _doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash); - _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash); + _hashKey.hashUint64((uint64_t)urlHash); } - uint32_t numHulls = 0; if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) { - numHulls = (uint32_t)_pointCollection.size(); + uint64_t numHulls = (uint64_t)_pointCollection.size(); + _hashKey.hashUint64(numHulls); } else if (_type == SHAPE_TYPE_SIMPLE_HULL) { - numHulls = 1; - } - if (numHulls > 0) { - uint32_t hash = DoubleHashKey::hashFunction(numHulls, primeIndex++); - _doubleHashKey.setHash(_doubleHashKey.getHash() ^ hash); - hash = DoubleHashKey::hashFunction2(numHulls); - _doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ hash); + _hashKey.hashUint64(1); } } - return _doubleHashKey; + return _hashKey; } void ShapeInfo::setHalfExtents(const glm::vec3& halfExtents) { _halfExtents = glm::max(halfExtents, glm::vec3(MIN_HALF_EXTENT)); + _hashKey.clear(); } diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index d658b936a3..069241e29d 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -18,7 +18,7 @@ #include #include -#include "DoubleHashKey.h" +#include "HashKey.h" const float MIN_SHAPE_OFFSET = 0.001f; // offsets less than 1mm will be ignored @@ -89,7 +89,7 @@ public: /// For compound shapes it will only return whether it is inside the bounding box bool contains(const glm::vec3& point) const; - const DoubleHashKey& getHash() const; + const HashKey& getHash() const; protected: void setHalfExtents(const glm::vec3& halfExtents); @@ -99,7 +99,7 @@ protected: TriangleIndices _triangleIndices; glm::vec3 _halfExtents = glm::vec3(0.0f); glm::vec3 _offset = glm::vec3(0.0f); - mutable DoubleHashKey _doubleHashKey; + mutable HashKey _hashKey; ShapeType _type = SHAPE_TYPE_NONE; }; diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp index c6a19084a2..79d0092dc3 100644 --- a/tests/physics/src/ShapeInfoTests.cpp +++ b/tests/physics/src/ShapeInfoTests.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include @@ -23,108 +23,78 @@ QTEST_MAIN(ShapeInfoTests) +// Enable this to manually run testHashCollisions +// (NOT a regular unit test; takes ~40 secs to run on an i7) +//#define MANUAL_TEST true + void ShapeInfoTests::testHashFunctions() { #if MANUAL_TEST int maxTests = 10000000; ShapeInfo info; - btHashMap hashes; + btHashMap hashes; - uint32_t bits[32]; - uint32_t masks[32]; - for (int i = 0; i < 32; ++i) { + const int32_t NUM_HASH_BITS = 32; + uint32_t bits[NUM_HASH_BITS]; + uint32_t masks[NUM_HASH_BITS]; + for (int i = 0; i < NUM_HASH_BITS; ++i) { bits[i] = 0; - masks[i] = 1U << i; + masks[i] = 1UL << i; } - float deltaLength = 0.002f; - float endLength = 100.0f; + float deltaLength = 1.0f / (HashKey::getNumQuantizedValuesPerMeter() - 3.0f); + float endLength = 2000.0f * deltaLength; int numSteps = (int)(endLength / deltaLength); int testCount = 0; int numCollisions = 0; btClock timer; - for (int x = 1; x < numSteps && testCount < maxTests; ++x) { - float radiusX = (float)x * deltaLength; + for (int i = 1; i < numSteps && testCount < maxTests; ++i) { + float radiusX = (float)i * deltaLength; + int32_t* hashPtr; // test sphere info.setSphere(radiusX); ++testCount; - DoubleHashKey key = info.getHash(); - uint32_t* hashPtr = hashes.find(key.getHash()); - if (hashPtr && *hashPtr == key.getHash2()) { - std::cout << testCount << " hash collision radiusX = " << radiusX - << " h1 = 0x" << std::hex << key.getHash() - << " h2 = 0x" << std::hex << key.getHash2() - << std::endl; + HashKey key = info.getHash(); + hashPtr = hashes.find(key); + if (hashPtr) { + std::cout << testCount << " hash collision sphere radius = " << radiusX + << " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr + << std::dec << std::endl; ++numCollisions; assert(false); } else { - hashes.insert(key.getHash(), key.getHash2()); + hashes.insert(key, key.getHash()); } - for (int k = 0; k < 32; ++k) { - if (masks[k] & key.getHash2()) { - ++bits[k]; + // track bit distribution counts to evaluate hash function randomness + for (int j = 0; j < NUM_HASH_BITS; ++j) { + if (masks[j] & key.getHash()) { + ++bits[j]; } } for (int y = 1; y < numSteps && testCount < maxTests; ++y) { float radiusY = (float)y * deltaLength; - /* TODO: reimplement Cylinder and Capsule shapes - // test cylinder and capsule - int types[] = { CYLINDER_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE }; - for (int i = 0; i < 2; ++i) { - switch(types[i]) { - case CYLINDER_SHAPE_PROXYTYPE: { - info.setCylinder(radiusX, radiusY); - break; - } - case CAPSULE_SHAPE_PROXYTYPE: { - info.setCapsuleY(radiusX, radiusY); - break; - } - } - - ++testCount; - key = info.getHash(); - hashPtr = hashes.find(key.getHash()); - if (hashPtr && *hashPtr == key.getHash2()) { - std::cout << testCount << " hash collision radiusX = " << radiusX << " radiusY = " << radiusY - << " h1 = 0x" << std::hex << key.getHash() - << " h2 = 0x" << std::hex << key.getHash2() - << std::endl; - ++numCollisions; - assert(false); - } else { - hashes.insert(key.getHash(), key.getHash2()); - } - for (int k = 0; k < 32; ++k) { - if (masks[k] & key.getHash2()) { - ++bits[k]; - } - } - } - */ - for (int z = 1; z < numSteps && testCount < maxTests; ++z) { float radiusZ = (float)z * deltaLength; // test box info.setBox(glm::vec3(radiusX, radiusY, radiusZ)); ++testCount; - DoubleHashKey key = info.getHash(); - hashPtr = hashes.find(key.getHash()); - if (hashPtr && *hashPtr == key.getHash2()) { - std::cout << testCount << " hash collision radiusX = " << radiusX - << " radiusY = " << radiusY << " radiusZ = " << radiusZ - << " h1 = 0x" << std::hex << key.getHash() - << " h2 = 0x" << std::hex << key.getHash2() - << std::endl; + HashKey key = info.getHash(); + hashPtr = hashes.find(key); + if (hashPtr) { + std::cout << testCount << " hash collision box dimensions = < " << radiusX + << ", " << radiusY << ", " << radiusZ << " >" + << " h = 0x" << std::hex << key.getHash() << " : 0x" << *hashPtr << " : 0x" << key.getHash64() + << std::dec << std::endl; ++numCollisions; assert(false); } else { - hashes.insert(key.getHash(), key.getHash2()); + hashes.insert(key, key.getHash()); } - for (int k = 0; k < 32; ++k) { - if (masks[k] & key.getHash2()) { + // track bit distribution counts to evaluate hash function randomness + for (int k = 0; k < NUM_HASH_BITS; ++k) { + if (masks[k] & key.getHash()) { ++bits[k]; } } @@ -135,7 +105,8 @@ void ShapeInfoTests::testHashFunctions() { std::cout << msec << " msec with " << numCollisions << " collisions out of " << testCount << " hashes" << std::endl; // print out distribution of bits - for (int i = 0; i < 32; ++i) { + // ideally the numbers in each bin will be about the same + for (int i = 0; i < NUM_HASH_BITS; ++i) { std::cout << "bit 0x" << std::hex << masks[i] << std::dec << " = " << bits[i] << std::endl; } QCOMPARE(numCollisions, 0); @@ -146,15 +117,14 @@ void ShapeInfoTests::testBoxShape() { ShapeInfo info; glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); info.setBox(halfExtents); - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); QCOMPARE(shape != nullptr, true); ShapeInfo otherInfo = info; - DoubleHashKey otherKey = otherInfo.getHash(); + HashKey otherKey = otherInfo.getHash(); QCOMPARE(key.getHash(), otherKey.getHash()); - QCOMPARE(key.getHash2(), otherKey.getHash2()); delete shape; } @@ -163,15 +133,14 @@ void ShapeInfoTests::testSphereShape() { ShapeInfo info; float radius = 1.23f; info.setSphere(radius); - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); QCOMPARE(shape != nullptr, true); ShapeInfo otherInfo = info; - DoubleHashKey otherKey = otherInfo.getHash(); + HashKey otherKey = otherInfo.getHash(); QCOMPARE(key.getHash(), otherKey.getHash()); - QCOMPARE(key.getHash2(), otherKey.getHash2()); delete shape; } @@ -182,15 +151,14 @@ void ShapeInfoTests::testCylinderShape() { float radius = 1.23f; float height = 4.56f; info.setCylinder(radius, height); - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); QCOMPARE(shape != nullptr, true); ShapeInfo otherInfo = info; - DoubleHashKey otherKey = otherInfo.getHash(); + HashKey otherKey = otherInfo.getHash(); QCOMPARE(key.getHash(), otherKey.getHash()); - QCOMPARE(key.getHash2(), otherKey.getHash2()); delete shape; */ @@ -202,15 +170,14 @@ void ShapeInfoTests::testCapsuleShape() { float radius = 1.23f; float height = 4.56f; info.setCapsule(radius, height); - DoubleHashKey key = info.getHash(); + HashKey key = info.getHash(); btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); QCOMPARE(shape != nullptr, true); ShapeInfo otherInfo = info; - DoubleHashKey otherKey = otherInfo.getHash(); + HashKey otherKey = otherInfo.getHash(); QCOMPARE(key.getHash(), otherKey.getHash()); - QCOMPARE(key.getHash2(), otherKey.getHash2()); delete shape; */ diff --git a/tests/physics/src/ShapeInfoTests.h b/tests/physics/src/ShapeInfoTests.h index fbd89a13a8..1f6054dd1a 100644 --- a/tests/physics/src/ShapeInfoTests.h +++ b/tests/physics/src/ShapeInfoTests.h @@ -18,10 +18,6 @@ //#include "BulletTestUtils.h" //#include "../QTestExtensions.h" -// Enable this to manually run testHashCollisions -// (NOT a regular unit test; takes ~17 secs to run on an i7) -#define MANUAL_TEST false - class ShapeInfoTests : public QObject { Q_OBJECT private slots: From b00d15834255f9ad1f8d1e6359e104efbfb72698 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 26 Oct 2017 09:00:42 -0700 Subject: [PATCH 054/171] remove DoubleHashKey: it is no longer used --- libraries/shared/src/DoubleHashKey.cpp | 48 ------------------------- libraries/shared/src/DoubleHashKey.h | 49 -------------------------- 2 files changed, 97 deletions(-) delete mode 100644 libraries/shared/src/DoubleHashKey.cpp delete mode 100644 libraries/shared/src/DoubleHashKey.h diff --git a/libraries/shared/src/DoubleHashKey.cpp b/libraries/shared/src/DoubleHashKey.cpp deleted file mode 100644 index ded2f073eb..0000000000 --- a/libraries/shared/src/DoubleHashKey.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// DoubleHashKey.cpp -// libraries/shared/src -// -// Created by Andrew Meadows 2014.11.02 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "DoubleHashKey.h" - -const uint32_t NUM_PRIMES = 64; -const uint32_t PRIMES[] = { - 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, - 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, - 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, - 4193939U, 4193929U, 4193909U, 4193869U, 4193807U, 4193803U, 4193801U, 4193789U, - 4193759U, 4193753U, 4193743U, 4193701U, 4193663U, 4193633U, 4193573U, 4193569U, - 4193551U, 4193549U, 4193531U, 4193513U, 4193507U, 4193459U, 4193447U, 4193443U, - 4193417U, 4193411U, 4193393U, 4193389U, 4193381U, 4193377U, 4193369U, 4193359U, - 4193353U, 4193327U, 4193309U, 4193303U, 4193297U, 4193279U, 4193269U, 4193263U -}; - -uint32_t DoubleHashKey::hashFunction(uint32_t value, uint32_t primeIndex) { - uint32_t hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); - hash += ~(hash << 15); - hash ^= (hash >> 10); - hash += (hash << 3); - hash ^= (hash >> 6); - hash += ~(hash << 11); - return hash ^ (hash >> 16); -} - -uint32_t DoubleHashKey::hashFunction2(uint32_t value) { - uint32_t hash = 0x811c9dc5U; - for (uint32_t i = 0; i < 4; i++ ) { - uint32_t byte = (value << (i * 8)) >> (24 - i * 8); - hash = ( hash ^ byte ) * 0x01000193U; - } - return hash; -} - -void DoubleHashKey::computeHash(uint32_t value, uint32_t primeIndex) { - _hash = DoubleHashKey::hashFunction(value, primeIndex); - _hash2 = DoubleHashKey::hashFunction2(value); -} diff --git a/libraries/shared/src/DoubleHashKey.h b/libraries/shared/src/DoubleHashKey.h deleted file mode 100644 index ca92a7197f..0000000000 --- a/libraries/shared/src/DoubleHashKey.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// DoubleHashKey.h -// libraries/shared/src -// -// Created by Andrew Meadows 2014.11.02 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_DoubleHashKey_h -#define hifi_DoubleHashKey_h - -#include - -// DoubleHashKey for use with btHashMap -class DoubleHashKey { -public: - static uint32_t hashFunction(uint32_t value, uint32_t primeIndex); - static uint32_t hashFunction2(uint32_t value); - - DoubleHashKey() : _hash(0), _hash2(0) { } - - DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) : - _hash(hashFunction(value, primeIndex)), - _hash2(hashFunction2(value)) { - } - - void clear() { _hash = 0; _hash2 = 0; } - bool isNull() const { return _hash == 0 && _hash2 == 0; } - - bool equals(const DoubleHashKey& other) const { - return _hash == other._hash && _hash2 == other._hash2; - } - - void computeHash(uint32_t value, uint32_t primeIndex = 0); - uint32_t getHash() const { return _hash; } - uint32_t getHash2() const { return _hash2; } - - void setHash(uint32_t hash) { _hash = hash; } - void setHash2(uint32_t hash2) { _hash2 = hash2; } - -private: - uint32_t _hash; - uint32_t _hash2; -}; - -#endif // hifi_DoubleHashKey_h From 4cadcd79bfb522e453a75fa46f859ccbcdcd6d27 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 27 Oct 2017 17:07:19 +0200 Subject: [PATCH 055/171] Return full viewport when scissor is disabled and items in outline group --- libraries/render-utils/src/OutlineEffect.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index e3f4ff2b7f..fb2aab95f2 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -113,8 +113,9 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; - auto framebufferSize = ressources->getSourceFrameSize(); +#if OUTLINE_USE_SCISSOR + auto framebufferSize = ressources->getSourceFrameSize(); // First thing we do is determine the projected bounding rect of all the outlined items auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize); auto blurPixelWidth = _sharedParameters->_blurPixelWidths[_outlineIndex]; @@ -123,6 +124,10 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // Add 1 pixel of extra margin to be on the safe side outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize); outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize); +#else + // Render full screen + outputs = args->_viewport; +#endif // Clear the framebuffer without stereo // Needs to be distinct from the other batch because using the clear call From 4cbee72eae60305cc616b53aee5fba092f2090ae Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 27 Oct 2017 17:50:22 +0200 Subject: [PATCH 056/171] Fixed warning on Mac and Ubuntu --- libraries/render-utils/src/OutlineEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index fb2aab95f2..f459ddc42c 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -367,7 +367,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const const auto outlineRessources = input.get0(); const auto outlineRect = input.get1(); - if (_isDisplayEnabled && outlineRessources) { + if (_isDisplayEnabled && outlineRessources && outlineRect.z>0 && outlineRect.w>0) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; From d45febf1db706a7f8855004818816d9220a9f823 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Oct 2017 08:55:41 -0700 Subject: [PATCH 057/171] add description of ShapeManager in comments --- libraries/physics/src/ShapeManager.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index 6ec3573b53..d75bb1dc4a 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -19,6 +19,28 @@ #include "HashKey.h" +// The ShapeManager handles the ref-counting on shared shapes: +// +// Each object added to the physics simulation gets a corresponding btRigidBody. +// The body has a btCollisionShape that represents the contours of its collision +// surface. Multiple bodies may have the same shape. Rather than create a unique +// btCollisionShape instance for every body with a particular shape we can instead +// use a single shape instance for all of the bodies. This is called "shape +// sharing". +// +// When body needs a new shape a description of ths shape (ShapeInfo) is assembled +// and a request is sent to the ShapeManager for a corresponding btCollisionShape +// pointer. The ShapeManager will compute a hash of the ShapeInfo's data and use +// that to find the shape in its map. If it finds one it increments the ref-count +// and returns the pointer. If not it asks the ShapeFactory to create it, adds an +// entry in the map with a ref-count of 1, and returns the pointer. +// +// When a body stops using a shape the ShapeManager must be informed so it can +// decrement its ref-count. When a ref-count drops to zero the ShapeManager +// doesn't delete it right away. Instead it puts the shape's key on a list delete +// later. When that list grows big enough the ShapeManager will remove any matching +// entries that still have zero ref-count. + class ShapeManager { public: @@ -51,6 +73,7 @@ private: ShapeReference() : refCount(0), shape(nullptr) {} }; + // btHashMap is required because it supports memory alignment of the btCollisionShapes btHashMap _shapeMap; btAlignedObjectArray _pendingGarbage; }; From 137fccbd91b46c20fddc891e52915824bd440f72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 27 Oct 2017 08:56:26 -0700 Subject: [PATCH 058/171] cleanup ShapeFactory implementation --- libraries/physics/src/ShapeFactory.cpp | 63 ++++++++++++++------------ libraries/physics/src/ShapeFactory.h | 16 +------ 2 files changed, 35 insertions(+), 44 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index cd0fba848a..f484f32fdf 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -16,6 +16,40 @@ #include "ShapeFactory.h" #include "BulletUtil.h" + +class StaticMeshShape : public btBvhTriangleMeshShape { +public: + StaticMeshShape() = delete; + + StaticMeshShape(btTriangleIndexVertexArray* dataArray) + : btBvhTriangleMeshShape(dataArray, true), _dataArray(dataArray) { + assert(_dataArray); + } + + ~StaticMeshShape() { + assert(_dataArray); + IndexedMeshArray& meshes = _dataArray->getIndexedMeshArray(); + for (int32_t i = 0; i < meshes.size(); ++i) { + btIndexedMesh mesh = meshes[i]; + mesh.m_numTriangles = 0; + delete [] mesh.m_triangleIndexBase; + mesh.m_triangleIndexBase = nullptr; + mesh.m_numVertices = 0; + delete [] mesh.m_vertexBase; + mesh.m_vertexBase = nullptr; + } + meshes.clear(); + delete _dataArray; + _dataArray = nullptr; + } + +private: + // the StaticMeshShape owns its vertex/index data + btTriangleIndexVertexArray* _dataArray; +}; + +// the dataArray must be created before we create the StaticMeshShape + // These are the same normalized directions used by the btShapeHull class. // 12 points for the face centers of a dodecahedron plus another 30 points // for the midpoints the edges, for a total of 42. @@ -230,23 +264,6 @@ btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info) { return dataArray; } -// util method -void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { - assert(dataArray); - IndexedMeshArray& meshes = dataArray->getIndexedMeshArray(); - for (int32_t i = 0; i < meshes.size(); ++i) { - btIndexedMesh mesh = meshes[i]; - mesh.m_numTriangles = 0; - delete [] mesh.m_triangleIndexBase; - mesh.m_triangleIndexBase = nullptr; - mesh.m_numVertices = 0; - delete [] mesh.m_vertexBase; - mesh.m_vertexBase = nullptr; - } - meshes.clear(); - delete dataArray; -} - const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); @@ -431,7 +448,6 @@ void ShapeFactory::deleteShape(const btCollisionShape* shape) { assert(shape); // ShapeFactory is responsible for deleting all shapes, even the const ones that are stored // in the ShapeManager, so we must cast to non-const here when deleting. - // so we cast to non-const here when deleting memory. btCollisionShape* nonConstShape = const_cast(shape); if (nonConstShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { btCompoundShape* compoundShape = static_cast(nonConstShape); @@ -448,14 +464,3 @@ void ShapeFactory::deleteShape(const btCollisionShape* shape) { } delete nonConstShape; } - -// the dataArray must be created before we create the StaticMeshShape -ShapeFactory::StaticMeshShape::StaticMeshShape(btTriangleIndexVertexArray* dataArray) -: btBvhTriangleMeshShape(dataArray, true), _dataArray(dataArray) { - assert(dataArray); -} - -ShapeFactory::StaticMeshShape::~StaticMeshShape() { - deleteStaticMeshArray(_dataArray); - _dataArray = nullptr; -} diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 2bf79f390c..704a7804b3 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -17,25 +17,11 @@ #include -// translates between ShapeInfo and btShape +// The ShapeFactory assembles and correctly disassembles btCollisionShapes. namespace ShapeFactory { const btCollisionShape* createShapeFromInfo(const ShapeInfo& info); void deleteShape(const btCollisionShape* shape); - - //btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info); - //void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray); - - class StaticMeshShape : public btBvhTriangleMeshShape { - public: - StaticMeshShape() = delete; - StaticMeshShape(btTriangleIndexVertexArray* dataArray); - ~StaticMeshShape(); - - private: - // the StaticMeshShape owns its vertex/index data - btTriangleIndexVertexArray* _dataArray; - }; }; #endif // hifi_ShapeFactory_h From 3a977f60397077aa2a7f18712c41736c6b354f24 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 27 Oct 2017 22:59:23 +0200 Subject: [PATCH 059/171] Disabled stereo in batch when using full screen outline --- libraries/render-utils/src/OutlineEffect.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index f459ddc42c..ad4c59b35a 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -278,6 +278,9 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto outlineFrameBuffer = inputs.get1(); auto outlineRect = inputs.get3(); + // TODO : If scissor isn't possible in stereo, send the AABox in the shader + // and do a raycasting per pixel to determine if we need to do the outline + // This should improve performance. if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); @@ -299,6 +302,9 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { +#if !OUTLINE_USE_SCISSOR + batch.enableStereo(false); +#endif batch.setFramebuffer(destinationFrameBuffer); batch.setViewportTransform(args->_viewport); From e9743d4c950a1e4591ec2690b12d9aa1de70561a Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 2 Nov 2017 10:00:30 +0100 Subject: [PATCH 060/171] Added jsdoc to SelectionScriptingInterface --- .../scripting/SelectionScriptingInterface.h | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/interface/src/scripting/SelectionScriptingInterface.h b/interface/src/scripting/SelectionScriptingInterface.h index 28c1713050..d9003c2c32 100644 --- a/interface/src/scripting/SelectionScriptingInterface.h +++ b/interface/src/scripting/SelectionScriptingInterface.h @@ -56,11 +56,44 @@ public: GameplayObjects getList(const QString& listName); + /**jsdoc + * Prints out the list of avatars, entities and overlays stored in a particular selection. + * @function Selection.printList + * @param listName {string} name of the selection + */ Q_INVOKABLE void printList(const QString& listName); + /**jsdoc + * Removes a named selection from the list of selections. + * @function Selection.removeListFromMap + * @param listName {string} name of the selection + * @returns {bool} true if the selection existed and was successfully removed. + */ Q_INVOKABLE bool removeListFromMap(const QString& listName); + /**jsdoc + * Add an item in a selection. + * @function Selection.addToSelectedItemsList + * @param listName {string} name of the selection + * @param itemType {string} the type of the item (one of "avatar", "entity" or "overlay") + * @param id {EntityID} the Id of the item to add to the selection + * @returns {bool} true if the item was successfully added. + */ Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); + /**jsdoc + * Remove an item from a selection. + * @function Selection.removeFromSelectedItemsList + * @param listName {string} name of the selection + * @param itemType {string} the type of the item (one of "avatar", "entity" or "overlay") + * @param id {EntityID} the Id of the item to remove + * @returns {bool} true if the item was successfully removed. + */ Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id); + /**jsdoc + * Remove all items from a selection. + * @function Selection.clearSelectedItemsList + * @param listName {string} name of the selection + * @returns {bool} true if the item was successfully cleared. + */ Q_INVOKABLE bool clearSelectedItemsList(const QString& listName); signals: From 4b598a6e241e35edaa622856e4a04fade4dfbce5 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 3 Nov 2017 14:26:36 +0100 Subject: [PATCH 061/171] Working stencil mask with object bounding boxes --- libraries/render-utils/src/OutlineEffect.cpp | 189 ++++++++---------- libraries/render-utils/src/OutlineEffect.h | 10 +- libraries/render-utils/src/Outline_aabox.slv | 103 ++++++++++ libraries/render-utils/src/Outline_shared.slh | 16 +- .../render-utils/src/RenderDeferredTask.cpp | 2 + libraries/render/src/render/SortTask.cpp | 8 +- .../developer/utilities/render/outline.qml | 57 +++--- .../render/outlinePage/OutlinePage.qml | 143 ++++++------- 8 files changed, 305 insertions(+), 223 deletions(-) create mode 100644 libraries/render-utils/src/Outline_aabox.slv diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index ad4c59b35a..a42cbfe358 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -11,7 +11,6 @@ #include "OutlineEffect.h" #include "GeometryCache.h" -#include "RenderUtilsLogging.h" #include "CubeProjectedPolygon.h" @@ -28,10 +27,11 @@ #include "debug_deferred_buffer_frag.h" #include "Outline_frag.h" #include "Outline_filled_frag.h" +#include "Outline_aabox_vert.h" using namespace render; -#define OUTLINE_USE_SCISSOR false +#define OUTLINE_STENCIL_MASK 1 OutlineRessources::OutlineRessources() { } @@ -56,15 +56,16 @@ void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer } void OutlineRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { - _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithoutDepth")); + _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil")); _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); + _colorFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); } void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); - auto depthTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); + _depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); - _depthFrameBuffer->setDepthStencilBuffer(depthTexture, depthFormat); + _depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat); } gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { @@ -73,10 +74,10 @@ gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { } gpu::TexturePointer OutlineRessources::getDepthTexture() { - return getDepthFramebuffer()->getDepthStencilBuffer(); + return _depthStencilTexture; } -gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { +gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { assert(_colorFrameBuffer); return _colorFrameBuffer; } @@ -96,6 +97,10 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, outputs = _ressources; } +gpu::PipelinePointer DrawOutlineMask::_stencilMaskPipeline; +gpu::PipelinePointer DrawOutlineMask::_stencilMaskFillPipeline; +gpu::BufferPointer DrawOutlineMask::_boundsBuffer; + DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : _outlineIndex{ outlineIndex }, @@ -108,26 +113,42 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con assert(renderContext->args->hasViewFrustum()); auto& inShapes = inputs.get0(); + if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) { + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO, gpu::State::STENCIL_OP_REPLACE)); + state->setColorWriteMask(false, false, false, false); + state->setCullMode(gpu::State::CULL_FRONT); + + gpu::StatePointer fillState = gpu::StatePointer(new gpu::State()); + fillState->setDepthTest(false, false, gpu::LESS_EQUAL); + fillState->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); + fillState->setColorWriteMask(false, false, false, false); + fillState->setCullMode(gpu::State::CULL_FRONT); + + auto vs = gpu::Shader::createVertex(std::string(Outline_aabox_vert)); + auto ps = gpu::StandardShaderLib::getDrawWhitePS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _stencilMaskPipeline = gpu::Pipeline::create(program, state); + _stencilMaskFillPipeline = gpu::Pipeline::create(program, fillState); + } + + if (!_boundsBuffer) { + _boundsBuffer = std::make_shared(sizeof(render::ItemBound)); + } + if (!inShapes.empty()) { auto ressources = inputs.get1(); RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; -#if OUTLINE_USE_SCISSOR - auto framebufferSize = ressources->getSourceFrameSize(); - // First thing we do is determine the projected bounding rect of all the outlined items - auto outlinedRect = computeOutlineRect(inShapes, args->getViewFrustum(), framebufferSize); - auto blurPixelWidth = _sharedParameters->_blurPixelWidths[_outlineIndex]; - //qCDebug(renderutils) << "Outline rect is " << outlinedRect.x << ' ' << outlinedRect.y << ' ' << outlinedRect.z << ' ' << outlinedRect.w; - - // Add 1 pixel of extra margin to be on the safe side - outputs = expandRect(outlinedRect, blurPixelWidth+1, framebufferSize); - outlinedRect = expandRect(outputs, blurPixelWidth+1, framebufferSize); -#else // Render full screen outputs = args->_viewport; -#endif // Clear the framebuffer without stereo // Needs to be distinct from the other batch because using the clear call @@ -135,25 +156,22 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setFramebuffer(ressources->getDepthFramebuffer()); - batch.clearDepthFramebuffer(1.0f); + batch.clearDepthStencilFramebuffer(1.0f, 0); }); + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + render::ItemBounds itemBounds; + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; auto maskPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder); auto maskSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned()); - glm::mat4 projMat; - Transform viewMat; - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); - -#if OUTLINE_USE_SCISSOR - batch.setStateScissorRect(outlinedRect); -#endif - batch.setFramebuffer(ressources->getDepthFramebuffer()); - // Setup camera, projection and viewport for all items batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(projMat); @@ -164,7 +182,8 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // Iterate through all inShapes and render the unskinned args->_shapePipeline = maskPipeline; batch.setPipeline(maskPipeline->pipeline); - for (auto items : inShapes) { + for (const auto& items : inShapes) { + itemBounds.insert(itemBounds.end(), items.second.begin(), items.second.end()); if (items.first.isSkinned()) { skinnedShapeKeys.push_back(items.first); } else { @@ -182,72 +201,34 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con args->_shapePipeline = nullptr; args->_batch = nullptr; }); + + _boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data()); + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + // Setup camera, projection and viewport for all items + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + // Draw stencil mask with object bounding boxes + const auto outlineWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth"); + const auto sqrt3 = 1.74f; + const float blurPixelWidth = 2.0f * sqrt3 *_sharedParameters->_blurPixelWidths[_outlineIndex]; + const auto framebufferSize = ressources->getSourceFrameSize(); + + auto stencilPipeline = _sharedParameters->_isFilled.test(_outlineIndex) ? _stencilMaskFillPipeline : _stencilMaskPipeline; + batch.setPipeline(stencilPipeline); + batch.setResourceBuffer(0, _boundsBuffer); + batch._glUniform2f(outlineWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y); + static const int NUM_VERTICES_PER_CUBE = 36; + batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_CUBE * (gpu::uint32) itemBounds.size(), 0); + }); } else { // Outline rect should be null as there are no outlined shapes outputs = glm::ivec4(0, 0, 0, 0); } } -glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes, - const ViewFrustum& viewFrustum, glm::ivec2 frameSize) { - glm::vec4 minMaxBounds{ - std::numeric_limits::max(), - std::numeric_limits::max(), - -std::numeric_limits::max(), - -std::numeric_limits::max(), - }; - - for (const auto& keyShapes : shapes) { - const auto& items = keyShapes.second; - - for (const auto& item : items) { - const auto& aabb = item.bound; - glm::vec2 bottomLeft; - glm::vec2 topRight; - - if (viewFrustum.getProjectedRect(aabb, bottomLeft, topRight)) { - minMaxBounds.x = std::min(minMaxBounds.x, bottomLeft.x); - minMaxBounds.y = std::min(minMaxBounds.y, bottomLeft.y); - minMaxBounds.z = std::max(minMaxBounds.z, topRight.x); - minMaxBounds.w = std::max(minMaxBounds.w, topRight.y); - } - } - } - - if (minMaxBounds.x != std::numeric_limits::max()) { - const glm::vec2 halfFrameSize{ frameSize.x*0.5f, frameSize.y*0.5f }; - glm::ivec4 rect; - - minMaxBounds += 1.0f; - rect.x = glm::clamp((int)floorf(minMaxBounds.x * halfFrameSize.x), 0, frameSize.x); - rect.y = glm::clamp((int)floorf(minMaxBounds.y * halfFrameSize.y), 0, frameSize.y); - rect.z = glm::clamp((int)ceilf(minMaxBounds.z * halfFrameSize.x), 0, frameSize.x); - rect.w = glm::clamp((int)ceilf(minMaxBounds.w * halfFrameSize.y), 0, frameSize.y); - - rect.z -= rect.x; - rect.w -= rect.y; - return rect; - } else { - return glm::ivec4(0, 0, 0, 0); - } -} - -glm::ivec4 DrawOutlineMask::expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize) { - // Go bo back to min max values - rect.z += rect.x; - rect.w += rect.y; - - rect.x = std::max(0, rect.x - amount); - rect.y = std::max(0, rect.y - amount); - rect.z = std::min(frameSize.x, rect.z + amount); - rect.w = std::min(frameSize.y, rect.w + amount); - - // Back to width height - rect.z -= rect.x; - rect.w -= rect.y; - return rect; -} - gpu::PipelinePointer DrawOutline::_pipeline; gpu::PipelinePointer DrawOutline::_pipelineFilled; @@ -270,7 +251,7 @@ void DrawOutline::configure(const Config& config) { _parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; _parameters._size.y = _size; _sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); - _isFilled = (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON); + _sharedParameters->_isFilled.set(_outlineIndex, (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON)); _configuration.edit() = _parameters; } @@ -278,9 +259,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto outlineFrameBuffer = inputs.get1(); auto outlineRect = inputs.get3(); - // TODO : If scissor isn't possible in stereo, send the AABox in the shader - // and do a raycasting per pixel to determine if we need to do the outline - // This should improve performance. if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); @@ -302,9 +280,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I } gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { -#if !OUTLINE_USE_SCISSOR batch.enableStereo(false); -#endif batch.setFramebuffer(destinationFrameBuffer); batch.setViewportTransform(args->_viewport); @@ -312,9 +288,6 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); -#if OUTLINE_USE_SCISSOR - batch.setStateScissorRect(outlineRect); -#endif batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); @@ -331,7 +304,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false, false)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - state->setScissorEnable(OUTLINE_USE_SCISSOR); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); @@ -351,7 +324,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); } - return _isFilled ? _pipelineFilled : _pipeline; + return _sharedParameters->_isFilled.test(_outlineIndex) ? _pipelineFilled : _pipeline; } DebugOutline::DebugOutline() { @@ -380,9 +353,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); -#if OUTLINE_USE_SCISSOR - batch.setStateScissorRect(outlineRect); -#endif + batch.setFramebuffer(outlineRessources->getColorFramebuffer()); const auto geometryBuffer = DependencyManager::get(); @@ -416,8 +387,8 @@ void DebugOutline::initializePipelines() { "Could not find source placeholder"); auto state = std::make_shared(); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(OUTLINE_USE_SCISSOR); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); @@ -473,7 +444,7 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende auto state = std::make_shared(); state->setDepthTest(true, true, gpu::LESS_EQUAL); state->setColorWriteMask(false, false, false, false); - state->setScissorEnable(OUTLINE_USE_SCISSOR); + initMaskPipelines(*shapePlumber, state); } auto sharedParameters = std::make_shared(); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index ee5e503de9..a2bfc88c81 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -33,6 +33,7 @@ protected: gpu::FramebufferPointer _depthFrameBuffer; gpu::FramebufferPointer _colorFrameBuffer; + gpu::TexturePointer _depthStencilTexture; glm::ivec2 _frameSize; @@ -48,6 +49,7 @@ public: OutlineSharedParameters(); std::array _blurPixelWidths; + std::bitset _isFilled; }; using OutlineSharedParametersPointer = std::shared_ptr; @@ -84,9 +86,10 @@ protected: unsigned int _outlineIndex; render::ShapePlumberPointer _shapePlumber; OutlineSharedParametersPointer _sharedParameters; - - static glm::ivec4 computeOutlineRect(const render::ShapeBounds& shapes, const ViewFrustum& viewFrustum, glm::ivec2 frameSize); - static glm::ivec4 expandRect(glm::ivec4 rect, int amount, glm::ivec2 frameSize); + + static gpu::BufferPointer _boundsBuffer; + static gpu::PipelinePointer _stencilMaskPipeline; + static gpu::PipelinePointer _stencilMaskFillPipeline; }; class DrawOutlineConfig : public render::Job::Config { @@ -158,7 +161,6 @@ private: OutlineSharedParametersPointer _sharedParameters; OutlineConfigurationBuffer _configuration; glm::ivec2 _framebufferSize{ 0,0 }; - bool _isFilled{ false }; float _size; }; diff --git a/libraries/render-utils/src/Outline_aabox.slv b/libraries/render-utils/src/Outline_aabox.slv new file mode 100644 index 0000000000..1a46ccd9c7 --- /dev/null +++ b/libraries/render-utils/src/Outline_aabox.slv @@ -0,0 +1,103 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Draw and transform the fed vertex position with the standard MVP stack +// and offset the vertices by a certain amount in the vertex direction +// +// Created by Olivier Prat on 11/02/2017 +// 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 +// + +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +struct ItemBound { + vec4 id_boundPos; + vec4 boundDim_s; +}; + +#if defined(GPU_GL410) +uniform samplerBuffer ssbo0Buffer; +ItemBound getItemBound(int i) { + int offset = 2 * i; + ItemBound bound; + bound.id_boundPos = texelFetch(ssbo0Buffer, offset); + bound.boundDim_s = texelFetch(ssbo0Buffer, offset + 1); + return bound; +} +#else +layout(std140) buffer ssbo0Buffer { + ItemBound bounds[]; +}; +ItemBound getItemBound(int i) { + ItemBound bound = bounds[i]; + return bound; +} +#endif + +uniform vec2 outlineWidth; + +void main(void) { + const vec3 UNIT_BOX_VERTICES[8] = vec3[8]( + vec3(0.0, 1.0, 0.0), + vec3(1.0, 1.0, 0.0), + vec3(1.0, 0.0, 0.0), + vec3(0.0, 0.0, 0.0), + vec3(0.0, 1.0, 1.0), + vec3(1.0, 1.0, 1.0), + vec3(1.0, 0.0, 1.0), + vec3(0.0, 0.0, 1.0) + ); + const vec3 UNIT_BOX_NORMALS[8] = vec3[8]( + vec3(-1.0, 1.0, -1.0), + vec3(1.0, 1.0, -1.0), + vec3(1.0, -1.0, -1.0), + vec3(-1.0, -1.0, -1.0), + vec3(-1.0, 1.0, 1.0), + vec3(1.0, 1.0, 1.0), + vec3(1.0, -1.0, 1.0), + vec3(-1.0, -1.0, 1.0) + ); + const int NUM_VERTICES_PER_CUBE = 36; + const int UNIT_BOX_TRIANGLE_INDICES[NUM_VERTICES_PER_CUBE] = int[NUM_VERTICES_PER_CUBE]( + 0, 1, 2, + 0, 2, 3, + 3, 2, 6, + 3, 6, 7, + 7, 6, 5, + 7, 5, 4, + 4, 5, 1, + 4, 1, 0, + 1, 5, 6, + 1, 6, 2, + 4, 0, 3, + 4, 3, 7 + ); + + int boundID = gl_VertexID / NUM_VERTICES_PER_CUBE; + int vertexID = gl_VertexID - boundID * NUM_VERTICES_PER_CUBE; + int triangleIndex = UNIT_BOX_TRIANGLE_INDICES[vertexID]; + vec3 cubeVec = UNIT_BOX_VERTICES[triangleIndex]; + + ItemBound bound = getItemBound(boundID); + vec3 boundPos = bound.id_boundPos.yzw; + vec3 boundDim = bound.boundDim_s.xyz; + + vec4 pos = vec4(boundPos + boundDim * cubeVec.xyz, 1.0); + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, pos, gl_Position)$> + + // Offset the vertex to take into account the outline width + pos.xyz += UNIT_BOX_NORMALS[triangleIndex]; + vec4 offsetPosition; + <$transformModelToClipPos(cam, obj, pos, offsetPosition)$> + gl_Position.xy += normalize(offsetPosition.xy-gl_Position.xy) * outlineWidth * gl_Position.w; +} diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Outline_shared.slh index 2ebece8903..3fd089e2fc 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Outline_shared.slh @@ -1,20 +1,20 @@ // glsl / C++ compatible source as interface for Outline #ifdef __cplusplus -# define VEC2 glm::vec2 -# define VEC3 glm::vec3 -# define VEC4 glm::vec4 +# define TVEC2 glm::vec2 +# define TVEC3 glm::vec3 +# define TVEC4 glm::vec4 #else -# define VEC2 vec2 -# define VEC3 vec3 -# define VEC4 vec4 +# define TVEC2 vec2 +# define TVEC3 vec3 +# define TVEC4 vec4 #endif struct OutlineParameters { - VEC3 _color; + TVEC3 _color; float _intensity; - VEC2 _size; + TVEC2 _size; float _unoccludedFillOpacity; float _occludedFillOpacity; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 63936b0809..16db1281f5 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,6 +35,7 @@ #include "TextureCache.h" #include "ZoneRenderer.h" #include "FadeEffect.h" +#include "RenderUtilsLogging.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" @@ -471,6 +472,7 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer auto blitFbo = renderArgs->_blitFramebuffer; if (!blitFbo) { + qCWarning(renderutils) << "Blit::run - no blit frame buffer."; return; } diff --git a/libraries/render/src/render/SortTask.cpp b/libraries/render/src/render/SortTask.cpp index 5b7ead4b6a..00146e393d 100644 --- a/libraries/render/src/render/SortTask.cpp +++ b/libraries/render/src/render/SortTask.cpp @@ -74,9 +74,13 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort); } - // Finally once sorted result to a list of itemID + // Finally once sorted result to a list of itemID and keep uniques + render::ItemID previousID = Item::INVALID_ITEM_ID; for (auto& item : itemBoundSorts) { - outItems.emplace_back(ItemBound(item._id, item._bounds)); + if (item._id != previousID) { + outItems.emplace_back(ItemBound(item._id, item._bounds)); + previousID = item._id; + } } } diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/outline.qml index 39acd854ac..8269ea830e 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/outline.qml @@ -8,22 +8,34 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 +import QtQuick 2.7 import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 import "outlinePage" +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls -Item { +Rectangle { id: root + HifiConstants { id: hifi;} + color: hifi.colors.baseGray; + anchors.margins: hifi.dimensions.contentMargin.x + property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug") signal sendToScript(var message); Column { - spacing: 8 - anchors.fill: parent + spacing: 5 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x Row { - spacing: 8 - CheckBox { + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + + HifiControls.CheckBox { id: debug text: "View Mask" checked: root.debugConfig["viewMask"] @@ -31,14 +43,14 @@ Item { root.debugConfig["viewMask"] = checked; } } - CheckBox { + HifiControls.CheckBox { text: "Hover select" checked: false onCheckedChanged: { sendToScript("pick "+checked.toString()) } } - CheckBox { + HifiControls.CheckBox { text: "Add to selection" checked: false onCheckedChanged: { @@ -56,28 +68,13 @@ Item { sendToScript("outline "+currentIndex) } - Tab { - title: "Outl.0" - OutlinePage { - outlineIndex: 0 - } - } - Tab { - title: "Outl.1" - OutlinePage { - outlineIndex: 1 - } - } - Tab { - title: "Outl.2" - OutlinePage { - outlineIndex: 2 - } - } - Tab { - title: "Outl.3" - OutlinePage { - outlineIndex: 3 + Repeater { + model: [ 0, 1, 2, 3 ] + Tab { + title: "Outl."+modelData + OutlinePage { + outlineIndex: modelData + } } } } diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml index a78bf02d3e..ff1d7fa23b 100644 --- a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml +++ b/scripts/developer/utilities/render/outlinePage/OutlinePage.qml @@ -8,19 +8,28 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 +import QtQuick 2.7 import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 import "../configSlider" +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls -Item { +Rectangle { id: root property var outlineIndex: 0 property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex) - Column { - spacing: 8 + HifiConstants { id: hifi;} + anchors.margins: hifi.dimensions.contentMargin.x - CheckBox { + Column { + spacing: 5 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x + + HifiControls.CheckBox { id: glow text: "Glow" checked: root.drawConfig["glow"] @@ -28,84 +37,78 @@ Item { root.drawConfig["glow"] = checked; } } - ConfigSlider { - label: "Width" - integral: false - config: root.drawConfig - property: "width" - max: 5.0 - min: 0.0 - width: 280 - } - ConfigSlider { - label: "Intensity" - integral: false - config: root.drawConfig - property: "intensity" - max: 1.0 - min: 0.0 - width: 280 - } + Repeater { + model: ["Width:width:5.0:0.0", + "Intensity:intensity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } + } GroupBox { title: "Color" - width: 280 + anchors.left: parent.left + anchors.right: parent.right Column { - spacing: 8 + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x - ConfigSlider { - label: "Red" - integral: false - config: root.drawConfig - property: "colorR" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Green" - integral: false - config: root.drawConfig - property: "colorG" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Blue" - integral: false - config: root.drawConfig - property: "colorB" - max: 1.0 - min: 0.0 - width: 270 + Repeater { + model: ["Red:colorR:1.0:0.0", + "Green:colorG:1.0:0.0", + "Blue:colorB:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } } } } GroupBox { title: "Fill Opacity" - width: 280 + anchors.left: parent.left + anchors.right: parent.right Column { - spacing: 8 + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: hifi.dimensions.contentMargin.x - ConfigSlider { - label: "Unoccluded" - integral: false - config: root.drawConfig - property: "unoccludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 - } - ConfigSlider { - label: "Occluded" - integral: false - config: root.drawConfig - property: "occludedFillOpacity" - max: 1.0 - min: 0.0 - width: 270 + Repeater { + model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0", + "Occluded:occludedFillOpacity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.drawConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + + anchors.left: parent.left + anchors.right: parent.right + } } } } From 79c2da3dcb4841f4a5c17f4cfc82643a1e4e560e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 3 Nov 2017 16:52:29 +0100 Subject: [PATCH 062/171] Removed cull functor from shadow render task as it is inadapted for the shadow's orthographic projection --- libraries/render-utils/src/RenderViewTask.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index fceaf7b5b9..1085a1148c 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -19,7 +19,10 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) { // auto items = input.get(); - task.addJob("RenderShadowTask", cullFunctor); + // Shadows use an orthographic projection because they are linked to sunlights + // but the cullFunctor passed is probably tailored for perspective projection and culls too much. + // TODO : create a special cull functor for this. + task.addJob("RenderShadowTask", nullptr); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); From f226835876238da2e6852552f72feeda15fd00ab Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 3 Nov 2017 11:51:03 -0700 Subject: [PATCH 063/171] 8495 No mirror camera in HMD mode --- interface/src/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f051697ad..228d39f87e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4441,7 +4441,7 @@ void Application::cameraModeChanged() { void Application::cameraMenuChanged() { auto menu = Menu::getInstance(); if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { - if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { + if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) { _myCamera.setMode(CAMERA_MODE_MIRROR); getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers } @@ -7271,6 +7271,10 @@ void Application::updateDisplayMode() { menu->setIsOptionChecked(MenuOption::FirstPerson, true); cameraMenuChanged(); } + + // Remove the mirror camera option from menu if in HMD mode + auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); + mirrorAction->setVisible(!isHmd); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); } From 9e6472b57783c514e34121941956fcceed902cc1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 6 Nov 2017 15:55:57 +0100 Subject: [PATCH 064/171] Added OutlineStyleStage --- .../ui/overlays/ContextOverlayInterface.cpp | 20 ++- .../src/ui/overlays/ContextOverlayInterface.h | 8 +- libraries/render-utils/src/OutlineEffect.cpp | 151 ++++++++++++------ libraries/render-utils/src/OutlineEffect.h | 89 ++++++----- .../render-utils/src/RenderDeferredTask.cpp | 16 +- .../render-utils/src/UpdateSceneTask.cpp | 2 + libraries/render/src/render/FilterTask.cpp | 7 +- libraries/render/src/render/FilterTask.h | 5 +- libraries/render/src/render/OutlineStyle.h | 39 +++++ .../render/src/render/OutlineStyleStage.cpp | 46 ++++++ .../render/src/render/OutlineStyleStage.h | 77 +++++++++ libraries/render/src/render/Scene.cpp | 64 ++++++++ libraries/render/src/render/Scene.h | 22 ++- 13 files changed, 427 insertions(+), 119 deletions(-) create mode 100644 libraries/render/src/render/OutlineStyle.h create mode 100644 libraries/render/src/render/OutlineStyleStage.cpp create mode 100644 libraries/render/src/render/OutlineStyleStage.h diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 1e9f827cb2..32e4137526 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -68,11 +68,15 @@ ContextOverlayInterface::ContextOverlayInterface() { connect(&qApp->getOverlays(), &Overlays::hoverEnterOverlay, this, &ContextOverlayInterface::contextOverlays_hoverEnterOverlay); connect(&qApp->getOverlays(), &Overlays::hoverLeaveOverlay, this, &ContextOverlayInterface::contextOverlays_hoverLeaveOverlay); - _selectionToSceneHandlers[0].initialize("contextOverlayHighlightList"); - connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[0], &SelectionToSceneHandler::selectedItemsListChanged); - for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) { - _selectionToSceneHandlers[i].initialize(QString("contextOverlayHighlightList") + QString::number(i)); - connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandlers[i], &SelectionToSceneHandler::selectedItemsListChanged); + { + render::Transaction transaction; + initializeSelectionToSceneHandler(_selectionToSceneHandlers[0], "contextOverlayHighlightList", transaction); + for (auto i = 1; i < MAX_SELECTION_COUNT; i++) { + auto selectionName = QString("contextOverlayHighlightList") + QString::number(i); + initializeSelectionToSceneHandler(_selectionToSceneHandlers[i], selectionName, transaction); + } + const render::ScenePointer& scene = qApp->getMain3DScene(); + scene->enqueueTransaction(transaction); } auto nodeList = DependencyManager::get(); @@ -81,6 +85,12 @@ ContextOverlayInterface::ContextOverlayInterface() { _challengeOwnershipTimeoutTimer.setSingleShot(true); } +void ContextOverlayInterface::initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction) { + handler.initialize(selectionName); + connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &handler, &SelectionToSceneHandler::selectedItemsListChanged); + transaction.resetSelectionOutline(selectionName.toStdString()); +} + static const uint32_t MOUSE_HW_ID = 0; static const uint32_t LEFT_HAND_HW_ID = 1; static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 }; diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index e5ebcdcff3..81e398e15d 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -76,6 +76,11 @@ private slots: void handleChallengeOwnershipReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode); private: + + enum { + MAX_SELECTION_COUNT = 16 + }; + bool _verboseLogging { true }; bool _enabled { true }; EntityItemID _currentEntityWithContextOverlay{}; @@ -91,8 +96,9 @@ private: void disableEntityHighlight(const EntityItemID& entityItemID); void deletingEntity(const EntityItemID& entityItemID); + void initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction); - SelectionToSceneHandler _selectionToSceneHandlers[render::Scene::MAX_OUTLINE_COUNT]; + SelectionToSceneHandler _selectionToSceneHandlers[MAX_SELECTION_COUNT]; Q_INVOKABLE void startChallengeOwnershipTimer(); QTimer _challengeOwnershipTimeoutTimer; diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index a42cbfe358..590277bf6d 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -83,7 +83,11 @@ gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { } OutlineSharedParameters::OutlineSharedParameters() { - std::fill(_blurPixelWidths.begin(), _blurPixelWidths.end(), 0); + _outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX); +} + +float OutlineSharedParameters::getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight) { + return ceilf(style.width * frameBufferHeight / 400.0f); } PrepareDrawOutline::PrepareDrawOutline() { @@ -141,8 +145,12 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con _boundsBuffer = std::make_shared(sizeof(render::ItemBound)); } - if (!inShapes.empty()) { + auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); + auto outlineId = _sharedParameters->_outlineIds[_outlineIndex]; + + if (!inShapes.empty() && !render::OutlineStyleStage::isIndexInvalid(outlineId)) { auto ressources = inputs.get1(); + auto& outline = outlineStage->getOutline(outlineId); RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; @@ -213,10 +221,10 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con // Draw stencil mask with object bounding boxes const auto outlineWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth"); const auto sqrt3 = 1.74f; - const float blurPixelWidth = 2.0f * sqrt3 *_sharedParameters->_blurPixelWidths[_outlineIndex]; + const float blurPixelWidth = 2.0f * sqrt3 * OutlineSharedParameters::getBlurPixelWidth(outline._style, args->_viewport.w); const auto framebufferSize = ressources->getSourceFrameSize(); - auto stencilPipeline = _sharedParameters->_isFilled.test(_outlineIndex) ? _stencilMaskFillPipeline : _stencilMaskPipeline; + auto stencilPipeline = outline._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline; batch.setPipeline(stencilPipeline); batch.setResourceBuffer(0, _boundsBuffer); batch._glUniform2f(outlineWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y); @@ -237,24 +245,6 @@ DrawOutline::DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPoint _sharedParameters{ parameters } { } -void DrawOutline::configure(const Config& config) { - const auto OPACITY_EPSILON = 5e-3f; - - _parameters._color = config.color; - _parameters._intensity = config.intensity * (config.glow ? 2.0f : 1.0f); - _parameters._unoccludedFillOpacity = config.unoccludedFillOpacity; - _parameters._occludedFillOpacity = config.occludedFillOpacity; - _parameters._threshold = config.glow ? 1.0f : 1e-3f; - _parameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(config.width * 3 + 0.5f))); - // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. - _size = config.width / 400.0f; - _parameters._size.x = (_size * _framebufferSize.y) / _framebufferSize.x; - _parameters._size.y = _size; - _sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); - _sharedParameters->_isFilled.set(_outlineIndex, (config.unoccludedFillOpacity > OPACITY_EPSILON || config.occludedFillOpacity > OPACITY_EPSILON)); - _configuration.edit() = _parameters; -} - void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { auto outlineFrameBuffer = inputs.get1(); auto outlineRect = inputs.get3(); @@ -267,39 +257,50 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); if (sceneDepthBuffer) { - auto pipeline = getPipeline(); auto args = renderContext->args; - if (_framebufferSize != framebufferSize) - { - _parameters._size.x = (_size * framebufferSize.y) / framebufferSize.x; - _parameters._size.y = _size; - _framebufferSize = framebufferSize; - _sharedParameters->_blurPixelWidths[_outlineIndex] = (int)ceilf(_size * _framebufferSize.y); - _configuration.edit() = _parameters; + auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); + auto outlineId = _sharedParameters->_outlineIds[_outlineIndex]; + if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) { + auto& outline = outlineStage->getOutline(_sharedParameters->_outlineIds[_outlineIndex]); + auto pipeline = getPipeline(outline._style); + { + auto& shaderParameters = _configuration.edit(); + + shaderParameters._color = outline._style.color; + shaderParameters._intensity = outline._style.intensity * (outline._style.glow ? 2.0f : 1.0f); + shaderParameters._unoccludedFillOpacity = outline._style.unoccludedFillOpacity; + shaderParameters._occludedFillOpacity = outline._style.occludedFillOpacity; + shaderParameters._threshold = outline._style.glow ? 1.0f : 1e-3f; + shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(outline._style.width * 3 + 0.5f))); + // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. + auto size = outline._style.width / 400.0f; + shaderParameters._size.x = (size * framebufferSize.y) / framebufferSize.x; + shaderParameters._size.y = size; + } + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setFramebuffer(destinationFrameBuffer); + + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); + batch.setPipeline(pipeline); + + batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); + batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); + batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); + batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); } - - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - batch.enableStereo(false); - batch.setFramebuffer(destinationFrameBuffer); - - batch.setViewportTransform(args->_viewport); - batch.setProjectionTransform(glm::mat4()); - batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); - batch.setPipeline(pipeline); - - batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); - batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); - batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); - batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); - batch.draw(gpu::TRIANGLE_STRIP, 4); - }); } } } -const gpu::PipelinePointer& DrawOutline::getPipeline() { +const gpu::PipelinePointer& DrawOutline::getPipeline(const render::OutlineStyle& style) { if (!_pipeline) { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false, false)); @@ -324,7 +325,7 @@ const gpu::PipelinePointer& DrawOutline::getPipeline() { gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); } - return _sharedParameters->_isFilled.test(_outlineIndex) ? _pipelineFilled : _pipeline; + return style.isFilled() ? _pipelineFilled : _pipeline; } DebugOutline::DebugOutline() { @@ -424,6 +425,35 @@ const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { return _depthPipeline; } +void SelectionToOutline::run(const render::RenderContextPointer& renderContext, Outputs& outputs) { + auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); + + outputs.clear(); + _sharedParameters->_outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX); + + for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) { + std::ostringstream stream; + stream << "contextOverlayHighlightList"; + if (i > 0) { + stream << i; + } + auto selectionName = stream.str(); + auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) { + _sharedParameters->_outlineIds[outputs.size()] = outlineId; + outputs.emplace_back(selectionName); + } + } +} + +void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + if (_outlineIndex < inputs.size()) { + outputs = inputs[_outlineIndex]; + } else { + outputs.clear(); + } +} + DrawOutlineTask::DrawOutlineTask() { } @@ -433,7 +463,7 @@ void DrawOutlineTask::configure(const Config& config) { } void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto groups = inputs.getN(0).get(); + const auto items = inputs.getN(0).get(); const auto sceneFrameBuffer = inputs.getN(1); const auto primaryFramebuffer = inputs.getN(2); const auto deferredFrameTransform = inputs.getN(3); @@ -449,12 +479,15 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende } auto sharedParameters = std::make_shared(); + const auto outlineSelectionNames = task.addJob("SelectionToOutline", sharedParameters); + // Prepare for outline group rendering. const auto outlineRessources = task.addJob("PrepareOutline", primaryFramebuffer); render::Varying outline0Rect; - for (auto i = 0; i < render::Scene::MAX_OUTLINE_COUNT; i++) { - const auto groupItems = groups[i]; + for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) { + const auto selectionName = task.addJob("ExtractSelectionName", outlineSelectionNames, i); + const auto groupItems = addSelectItemJobs(task, selectionName, items); const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs); @@ -490,6 +523,20 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende task.addJob("OutlineDebug", debugInputs); } +const render::Varying DrawOutlineTask::addSelectItemJobs(JobModel& task, const render::Varying& selectionName, + const RenderFetchCullSortTask::BucketList& items) { + const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; + const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& metas = items[RenderFetchCullSortTask::META]; + + const auto selectMetaInput = SelectItems::Inputs(metas, Varying(), selectionName).asVarying(); + const auto selectedMetas = task.addJob("MetaSelection", selectMetaInput); + const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas, selectionName).asVarying(); + const auto selectedMetasAndOpaques = task.addJob("OpaqueSelection", selectMetaAndOpaqueInput); + const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, selectionName).asVarying(); + return task.addJob("TransparentSelection", selectItemInput); +} + #include "model_shadow_vert.h" #include "skin_model_shadow_vert.h" diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index a2bfc88c81..e25184eb5b 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -13,6 +13,9 @@ #define hifi_render_utils_OutlineEffect_h #include +#include +#include + #include "DeferredFramebuffer.h" #include "DeferredFrameTransform.h" @@ -46,10 +49,15 @@ using OutlineRessourcesPointer = std::shared_ptr; class OutlineSharedParameters { public: + enum { + MAX_OUTLINE_COUNT = 8 + }; + OutlineSharedParameters(); - std::array _blurPixelWidths; - std::bitset _isFilled; + std::array _outlineIds; + + static float getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight); }; using OutlineSharedParametersPointer = std::shared_ptr; @@ -70,6 +78,38 @@ private: }; +class SelectionToOutline { +public: + + using Outputs = std::vector; + using JobModel = render::Job::ModelO; + + SelectionToOutline(OutlineSharedParametersPointer parameters) : _sharedParameters{ parameters } {} + + void run(const render::RenderContextPointer& renderContext, Outputs& outputs); + +private: + + OutlineSharedParametersPointer _sharedParameters; +}; + +class ExtractSelectionName { +public: + + using Inputs = SelectionToOutline::Outputs; + using Outputs = std::string; + using JobModel = render::Job::ModelIO; + + ExtractSelectionName(unsigned int outlineIndex) : _outlineIndex{ outlineIndex } {} + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + +private: + + unsigned int _outlineIndex; + +}; + class DrawOutlineMask { public: @@ -92,49 +132,15 @@ protected: static gpu::PipelinePointer _stencilMaskFillPipeline; }; -class DrawOutlineConfig : public render::Job::Config { - Q_OBJECT - Q_PROPERTY(bool glow MEMBER glow NOTIFY dirty) - Q_PROPERTY(float width MEMBER width NOTIFY dirty) - Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty) - Q_PROPERTY(float colorR READ getColorR WRITE setColorR NOTIFY dirty) - Q_PROPERTY(float colorG READ getColorG WRITE setColorG NOTIFY dirty) - Q_PROPERTY(float colorB READ getColorB WRITE setColorB NOTIFY dirty) - Q_PROPERTY(float unoccludedFillOpacity MEMBER unoccludedFillOpacity NOTIFY dirty) - Q_PROPERTY(float occludedFillOpacity MEMBER occludedFillOpacity NOTIFY dirty) - -public: - - void setColorR(float value) { color.r = value; emit dirty(); } - float getColorR() const { return color.r; } - - void setColorG(float value) { color.g = value; emit dirty(); } - float getColorG() const { return color.g; } - - void setColorB(float value) { color.b = value; emit dirty(); } - float getColorB() const { return color.b; } - - glm::vec3 color{ 1.f, 0.7f, 0.2f }; - float width{ 2.0f }; - float intensity{ 0.9f }; - float unoccludedFillOpacity{ 0.0f }; - float occludedFillOpacity{ 0.0f }; - bool glow{ false }; - -signals: - void dirty(); -}; - class DrawOutline { public: using Inputs = render::VaryingSet4; - using Config = DrawOutlineConfig; + using Config = render::Job::Config; using JobModel = render::Job::ModelI; DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters); - void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); private: @@ -151,7 +157,7 @@ private: using OutlineConfigurationBuffer = gpu::StructBuffer; - const gpu::PipelinePointer& getPipeline(); + static const gpu::PipelinePointer& getPipeline(const render::OutlineStyle& style); static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; @@ -160,8 +166,6 @@ private: OutlineParameters _parameters; OutlineSharedParametersPointer _sharedParameters; OutlineConfigurationBuffer _configuration; - glm::ivec2 _framebufferSize{ 0,0 }; - float _size; }; class DebugOutlineConfig : public render::Job::Config { @@ -201,8 +205,7 @@ private: class DrawOutlineTask { public: - using Groups = render::VaryingArray; - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = render::Task::Config; using JobModel = render::Task::ModelI; @@ -214,6 +217,8 @@ public: private: static void initMaskPipelines(render::ShapePlumber& plumber, gpu::StatePointer state); + static const render::Varying addSelectItemJobs(JobModel& task, const render::Varying& selectionName, const RenderFetchCullSortTask::BucketList& items); + }; #endif // hifi_render_utils_OutlineEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 16db1281f5..52b8896e69 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -64,11 +64,11 @@ const render::Varying RenderDeferredTask::addSelectItemJobs(JobModel& task, cons const render::Varying& metas, const render::Varying& opaques, const render::Varying& transparents) { - const auto selectMetaInput = SelectItems::Inputs(metas, Varying()).asVarying(); + const auto selectMetaInput = SelectItems::Inputs(metas, Varying(), std::string()).asVarying(); const auto selectedMetas = task.addJob("MetaSelection", selectMetaInput, selectionName); - const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas).asVarying(); + const auto selectMetaAndOpaqueInput = SelectItems::Inputs(opaques, selectedMetas, std::string()).asVarying(); const auto selectedMetasAndOpaques = task.addJob("OpaqueSelection", selectMetaAndOpaqueInput, selectionName); - const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques).asVarying(); + const auto selectItemInput = SelectItems::Inputs(transparents, selectedMetasAndOpaques, std::string()).asVarying(); return task.addJob("TransparentSelection", selectItemInput, selectionName); } @@ -187,16 +187,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Select items that need to be outlined const auto selectionBaseName = "contextOverlayHighlightList"; const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); - DrawOutlineTask::Groups outlineGroups; - outlineGroups[0] = selectedItems; - for (auto i = 1; i < render::Scene::MAX_OUTLINE_COUNT; i++) { - std::ostringstream selectionName; - selectionName << selectionBaseName; - selectionName << i; - outlineGroups[i] = addSelectItemJobs(task, selectionName.str().c_str(), metas, opaques, transparents); - } - const auto outlineInputs = DrawOutlineTask::Inputs(outlineGroups, deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); + const auto outlineInputs = DrawOutlineTask::Inputs(items.get0(), deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); task.addJob("DrawOutline", outlineInputs); task.addJob("OutlineRangeTimer", outlineRangeTimer); diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index 06e02907f2..d37569b526 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -15,6 +15,7 @@ #include "BackgroundStage.h" #include "HazeStage.h" #include +#include #include "DeferredLightingEffect.h" void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { @@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); task.addJob("TransitionStageSetup"); + task.addJob("OutlineStyleStageSetup"); task.addJob("DefaultLightingSetup"); diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index f60f5895b7..20d29f3e5d 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -57,7 +57,12 @@ void SliceItems::run(const RenderContextPointer& renderContext, const ItemBounds } void SelectItems::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems) { - auto selection = renderContext->_scene->getSelection(_name); + auto selectionName{ _name }; + if (!inputs.get2().empty()) { + selectionName = inputs.get2(); + } + + auto selection = renderContext->_scene->getSelection(selectionName); const auto& selectedItems = selection.getItems(); const auto& inItems = inputs.get0(); const auto itemsToAppend = inputs[1]; diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index a7180b6cde..9b40728b00 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -113,12 +113,13 @@ namespace render { // Keep items belonging to the job selection class SelectItems { public: - using Inputs = VaryingSet2; + using Inputs = VaryingSet3; using JobModel = Job::ModelIO; std::string _name; + SelectItems() {} SelectItems(const Selection::Name& name) : _name(name) {} - + void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; diff --git a/libraries/render/src/render/OutlineStyle.h b/libraries/render/src/render/OutlineStyle.h new file mode 100644 index 0000000000..cdcdf79f3e --- /dev/null +++ b/libraries/render/src/render/OutlineStyle.h @@ -0,0 +1,39 @@ +// +// OutlineStyle.h + +// Created by Olivier Prat on 11/06/2017. +// 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 +// + +#ifndef hifi_render_utils_OutlineStyle_h +#define hifi_render_utils_OutlineStyle_h + +#include + +#include + +namespace render { + + // This holds the configuration for a particular outline style + class OutlineStyle { + public: + + bool isFilled() const { + return unoccludedFillOpacity > 5e-3f || occludedFillOpacity > 5e-3f; + } + + glm::vec3 color{ 1.f, 0.7f, 0.2f }; + float width{ 2.0f }; + float intensity{ 0.9f }; + float unoccludedFillOpacity{ 0.0f }; + float occludedFillOpacity{ 0.0f }; + bool glow{ false }; + std::string selectionName; + }; + +} + +#endif // hifi_render_utils_OutlineStyle_h \ No newline at end of file diff --git a/libraries/render/src/render/OutlineStyleStage.cpp b/libraries/render/src/render/OutlineStyleStage.cpp new file mode 100644 index 0000000000..e3fd1672de --- /dev/null +++ b/libraries/render/src/render/OutlineStyleStage.cpp @@ -0,0 +1,46 @@ +#include "OutlineStyleStage.h" + +using namespace render; + +std::string OutlineStyleStage::_name("OutlineStyle"); + +OutlineStyleStage::Index OutlineStyleStage::addOutline(const std::string& selectionName, const OutlineStyle& style) { + Outline outline{ selectionName, style }; + Index id; + + id = _outlines.newElement(outline); + _activeOutlineIds.push_back(id); + + return id; +} + +void OutlineStyleStage::removeOutline(Index index) { + OutlineIdList::iterator idIterator = std::find(_activeOutlineIds.begin(), _activeOutlineIds.end(), index); + if (idIterator != _activeOutlineIds.end()) { + _activeOutlineIds.erase(idIterator); + } + if (!_outlines.isElementFreed(index)) { + _outlines.freeElement(index); + } +} + +Index OutlineStyleStage::getOutlineIdBySelection(const std::string& selectionName) const { + for (auto outlineId : _activeOutlineIds) { + const auto& outline = _outlines.get(outlineId); + if (outline._selectionName == selectionName) { + return outlineId; + } + } + return INVALID_INDEX; +} + +OutlineStyleStageSetup::OutlineStyleStageSetup() { +} + +void OutlineStyleStageSetup::run(const render::RenderContextPointer& renderContext) { + if (!renderContext->_scene->getStage(OutlineStyleStage::getName())) { + auto stage = std::make_shared(); + renderContext->_scene->resetStage(OutlineStyleStage::getName(), stage); + } +} + diff --git a/libraries/render/src/render/OutlineStyleStage.h b/libraries/render/src/render/OutlineStyleStage.h new file mode 100644 index 0000000000..79835a22a4 --- /dev/null +++ b/libraries/render/src/render/OutlineStyleStage.h @@ -0,0 +1,77 @@ +// +// OutlineStyleStage.h + +// Created by Olivier Prat on 07/07/2017. +// 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 +// + +#ifndef hifi_render_utils_outlinestage_h +#define hifi_render_utils_outlinestage_h + +#include "Stage.h" +#include "Engine.h" +#include "IndexedContainer.h" +#include "OutlineStyle.h" + +namespace render { + + // OutlineStyle stage to set up OutlineStyle-related effects + class OutlineStyleStage : public Stage { + public: + + class Outline { + public: + + Outline(const std::string& selectionName, const OutlineStyle& style) : _selectionName{ selectionName }, _style{ style } { } + + std::string _selectionName; + OutlineStyle _style; + + }; + + static const std::string& getName() { return _name; } + + using Index = render::indexed_container::Index; + static const Index INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; + using OutlineIdList = render::indexed_container::Indices; + + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } + + bool checkOutlineId(Index index) const { return _outlines.checkIndex(index); } + + const Outline& getOutline(Index OutlineStyleId) const { return _outlines.get(OutlineStyleId); } + Outline& editOutline(Index OutlineStyleId) { return _outlines.edit(OutlineStyleId); } + + Index addOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle()); + Index getOutlineIdBySelection(const std::string& selectionName) const; + void removeOutline(Index index); + + OutlineIdList::iterator begin() { return _activeOutlineIds.begin(); } + OutlineIdList::iterator end() { return _activeOutlineIds.end(); } + + private: + + using Outlines = render::indexed_container::IndexedVector; + + static std::string _name; + + Outlines _outlines; + OutlineIdList _activeOutlineIds; + }; + using OutlineStyleStagePointer = std::shared_ptr; + + class OutlineStyleStageSetup { + public: + using JobModel = render::Job::Model; + + OutlineStyleStageSetup(); + void run(const RenderContextPointer& renderContext); + + protected: + }; + +} +#endif // hifi_render_utils_outlinestage_h diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 714be2a8c6..0e680dfdaf 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -14,6 +14,7 @@ #include #include "Logging.h" #include "TransitionStage.h" +#include "OutlineStyleStage.h" using namespace render; @@ -54,6 +55,18 @@ void Transaction::resetSelection(const Selection& selection) { _resetSelections.emplace_back(selection); } +void Transaction::resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style) { + _outlineResets.emplace_back(OutlineReset{ selectionName, style }); +} + +void Transaction::removeOutlineFromSelection(const std::string& selectionName) { + _outlineRemoves.emplace_back(selectionName); +} + +void Transaction::querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func) { + _outlineQueries.emplace_back(OutlineQuery{ selectionName, func }); +} + void Transaction::merge(const Transaction& transaction) { _resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end()); _removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end()); @@ -62,6 +75,9 @@ void Transaction::merge(const Transaction& transaction) { _addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end()); _queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end()); _reAppliedTransitions.insert(_reAppliedTransitions.end(), transaction._reAppliedTransitions.begin(), transaction._reAppliedTransitions.end()); + _outlineResets.insert(_outlineResets.end(), transaction._outlineResets.begin(), transaction._outlineResets.end()); + _outlineRemoves.insert(_outlineRemoves.end(), transaction._outlineRemoves.begin(), transaction._outlineRemoves.end()); + _outlineQueries.insert(_outlineQueries.end(), transaction._outlineQueries.begin(), transaction._outlineQueries.end()); } @@ -176,6 +192,10 @@ void Scene::processTransactionFrame(const Transaction& transaction) { // resets and potential NEW items resetSelections(transaction._resetSelections); } + + resetOutlines(transaction._outlineResets); + removeOutlines(transaction._outlineRemoves); + queryOutlines(transaction._outlineQueries); } void Scene::resetItems(const Transaction::Resets& transactions) { @@ -316,6 +336,50 @@ void Scene::queryTransitionItems(const Transaction::TransitionQueries& transacti } } +void Scene::resetOutlines(const Transaction::OutlineResets& transactions) { + auto outlineStage = getStage(OutlineStyleStage::getName()); + + for (auto& transaction : transactions) { + const auto& selectionName = std::get<0>(transaction); + const auto& newStyle = std::get<1>(transaction); + auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + + if (OutlineStyleStage::isIndexInvalid(outlineId)) { + outlineStage->addOutline(selectionName, newStyle); + } else { + outlineStage->editOutline(outlineId)._style = newStyle; + } + } +} + +void Scene::removeOutlines(const Transaction::OutlineRemoves& transactions) { + auto outlineStage = getStage(OutlineStyleStage::getName()); + + for (auto& selectionName : transactions) { + auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + + if (!OutlineStyleStage::isIndexInvalid(outlineId)) { + outlineStage->removeOutline(outlineId); + } + } +} + +void Scene::queryOutlines(const Transaction::OutlineQueries& transactions) { + auto outlineStage = getStage(OutlineStyleStage::getName()); + + for (auto& transaction : transactions) { + const auto& selectionName = std::get<0>(transaction); + const auto& func = std::get<1>(transaction); + auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + + if (!OutlineStyleStage::isIndexInvalid(outlineId)) { + func(&outlineStage->editOutline(outlineId)._style); + } else { + func(nullptr); + } + } +} + void Scene::collectSubItems(ItemID parentId, ItemIDs& subItems) const { // Access the true item auto& item = _items[parentId]; diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 1f3b9a72c3..38f528aced 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -17,6 +17,7 @@ #include "Stage.h" #include "Selection.h" #include "Transition.h" +#include "OutlineStyle.h" namespace render { @@ -37,6 +38,7 @@ class Transaction { public: typedef std::function TransitionQueryFunc; + typedef std::function SelectionOutlineQueryFunc; Transaction() {} ~Transaction() {} @@ -61,6 +63,10 @@ public: // Selection transactions void resetSelection(const Selection& selection); + void resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle()); + void removeOutlineFromSelection(const std::string& selectionName); + void querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func); + void merge(const Transaction& transaction); // Checkers if there is work to do when processing the transaction @@ -75,6 +81,9 @@ protected: using TransitionQuery = std::tuple; using TransitionReApply = ItemID; using SelectionReset = Selection; + using OutlineReset = std::tuple; + using OutlineRemove = std::string; + using OutlineQuery = std::tuple; using Resets = std::vector; using Removes = std::vector; @@ -83,6 +92,9 @@ protected: using TransitionQueries = std::vector; using TransitionReApplies = std::vector; using SelectionResets = std::vector; + using OutlineResets = std::vector; + using OutlineRemoves = std::vector; + using OutlineQueries = std::vector; Resets _resetItems; Removes _removedItems; @@ -91,6 +103,9 @@ protected: TransitionQueries _queriedTransitions; TransitionReApplies _reAppliedTransitions; SelectionResets _resetSelections; + OutlineResets _outlineResets; + OutlineRemoves _outlineRemoves; + OutlineQueries _outlineQueries; }; typedef std::queue TransactionQueue; @@ -103,10 +118,6 @@ typedef std::queue TransactionQueue; class Scene { public: - enum { - MAX_OUTLINE_COUNT = 8 - }; - Scene(glm::vec3 origin, float size); ~Scene(); @@ -192,6 +203,9 @@ protected: void transitionItems(const Transaction::TransitionAdds& transactions); void reApplyTransitions(const Transaction::TransitionReApplies& transactions); void queryTransitionItems(const Transaction::TransitionQueries& transactions); + void resetOutlines(const Transaction::OutlineResets& transactions); + void removeOutlines(const Transaction::OutlineRemoves& transactions); + void queryOutlines(const Transaction::OutlineQueries& transactions); void collectSubItems(ItemID parentId, ItemIDs& subItems) const; From 31b63ffbe6617bfe8ee418488ba2589bdc7662bc Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 6 Nov 2017 08:03:07 -0700 Subject: [PATCH 065/171] Not posible to change to mirror mode using js --- interface/src/Application.cpp | 7 ++++++- libraries/shared/src/shared/Camera.cpp | 1 + libraries/shared/src/shared/Camera.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 228d39f87e..58e433af84 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4423,7 +4423,12 @@ void Application::cameraModeChanged() { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); break; case CAMERA_MODE_MIRROR: - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); + if (isHMDMode()) { + _myCamera.setMode(_myCamera.getLastMode()); + qDebug() << "Mirror mode is not available"; + } else { + Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); + } break; case CAMERA_MODE_INDEPENDENT: Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true); diff --git a/libraries/shared/src/shared/Camera.cpp b/libraries/shared/src/shared/Camera.cpp index ab841c4717..100124a416 100644 --- a/libraries/shared/src/shared/Camera.cpp +++ b/libraries/shared/src/shared/Camera.cpp @@ -85,6 +85,7 @@ void Camera::setOrientation(const glm::quat& orientation) { } void Camera::setMode(CameraMode mode) { + _lastMode = _mode; _mode = mode; emit modeUpdated(modeToString(mode)); } diff --git a/libraries/shared/src/shared/Camera.h b/libraries/shared/src/shared/Camera.h index 3ad08bd719..11d4cf4254 100644 --- a/libraries/shared/src/shared/Camera.h +++ b/libraries/shared/src/shared/Camera.h @@ -56,6 +56,7 @@ public: void update(); CameraMode getMode() const { return _mode; } + CameraMode getLastMode() const { return _lastMode; } void setMode(CameraMode m); void loadViewFrustum(ViewFrustum& frustum) const; @@ -123,6 +124,7 @@ private: void decompose(); CameraMode _mode{ CAMERA_MODE_THIRD_PERSON }; + CameraMode _lastMode{ _mode }; glm::mat4 _transform; glm::mat4 _projection; From 650df247611fe83ab1b6c4e2035f42d410ce4e02 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Mon, 6 Nov 2017 14:27:02 -0800 Subject: [PATCH 066/171] Improved Haze UI in Create menu --- scripts/system/html/entityProperties.html | 46 +++++++++++++---------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index e7d4aed3fb..7fdeee67d3 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -555,20 +555,21 @@
-
+
+ + < + /div>
-
-
-
-
-
-
-
+
+
+
+
+
@@ -582,6 +583,15 @@
+
+
+
+
+ + +
+
+
@@ -600,20 +610,18 @@
-
-
-
-
-
- - +
+
+ + +
+
+ + +
-
- - -
From b272b2e6c8655862a54d63be9dc7948318d3bc56 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 7 Nov 2017 11:28:35 +1300 Subject: [PATCH 067/171] Fix import from URL adding multiple copies of imported entities --- scripts/system/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index e76a02b6f5..a5b1d9358b 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1533,7 +1533,7 @@ function handeMenuEvent(menuItem) { Window.openFileChanged.connect(onFileOpenChanged); Window.browseAsync("Select Model to Import", "", "*.json"); } else { - Window.promptTextChanged.connect(onFileOpenChanged); + Window.promptTextChanged.connect(onPromptTextChanged); Window.promptAsync("URL of SVO to import", ""); } } else if (menuItem === "Entity List...") { From 3cc445ff023b2a641996cde913b1812cf95a52bf Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 11:07:25 +0100 Subject: [PATCH 068/171] Renamed outline to highlight --- .gitignore | 1 + .../ui/overlays/ContextOverlayInterface.cpp | 2 +- .../src/{Outline.slf => Highlight.slf} | 6 +- .../src/{Outline.slh => Highlight.slh} | 24 +- ...{OutlineEffect.cpp => HighlightEffect.cpp} | 239 +++++++++--------- .../{OutlineEffect.h => HighlightEffect.h} | 112 ++++---- ...{Outline_aabox.slv => Highlight_aabox.slv} | 0 ...utline_filled.slf => Highlight_filled.slf} | 6 +- ...utline_shared.slh => Highlight_shared.slh} | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 10 +- .../render-utils/src/UpdateSceneTask.cpp | 4 +- .../render/src/render/HighlightStage.cpp | 46 ++++ libraries/render/src/render/HighlightStage.h | 77 ++++++ .../{OutlineStyle.h => HighlightStyle.h} | 17 +- .../render/src/render/OutlineStyleStage.cpp | 46 ---- .../render/src/render/OutlineStyleStage.h | 77 ------ libraries/render/src/render/Scene.cpp | 58 ++--- libraries/render/src/render/Scene.h | 34 +-- .../{debugOutline.js => debugHighlight.js} | 22 +- .../render/{outline.qml => highlight.qml} | 12 +- .../HighlightPage.qml} | 6 +- .../utilities/render/highlightPage/qmldir | 1 + .../utilities/render/outlinePage/qmldir | 1 - 23 files changed, 403 insertions(+), 402 deletions(-) rename libraries/render-utils/src/{Outline.slf => Highlight.slf} (72%) rename libraries/render-utils/src/{Outline.slh => Highlight.slh} (75%) rename libraries/render-utils/src/{OutlineEffect.cpp => HighlightEffect.cpp} (63%) rename libraries/render-utils/src/{OutlineEffect.h => HighlightEffect.h} (55%) rename libraries/render-utils/src/{Outline_aabox.slv => Highlight_aabox.slv} (100%) rename libraries/render-utils/src/{Outline_filled.slf => Highlight_filled.slf} (71%) rename libraries/render-utils/src/{Outline_shared.slh => Highlight_shared.slh} (84%) create mode 100644 libraries/render/src/render/HighlightStage.cpp create mode 100644 libraries/render/src/render/HighlightStage.h rename libraries/render/src/render/{OutlineStyle.h => HighlightStyle.h} (68%) delete mode 100644 libraries/render/src/render/OutlineStyleStage.cpp delete mode 100644 libraries/render/src/render/OutlineStyleStage.h rename scripts/developer/utilities/render/{debugOutline.js => debugHighlight.js} (88%) rename scripts/developer/utilities/render/{outline.qml => highlight.qml} (88%) rename scripts/developer/utilities/render/{outlinePage/OutlinePage.qml => highlightPage/HighlightPage.qml} (96%) create mode 100644 scripts/developer/utilities/render/highlightPage/qmldir delete mode 100644 scripts/developer/utilities/render/outlinePage/qmldir diff --git a/.gitignore b/.gitignore index 072e6001da..4b6949e268 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ gvr-interface/libs/* # ignore files for various dev environments TAGS *.sw[po] +*.qmlc # ignore node files for the console node_modules diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 32e4137526..6a21221a8b 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -88,7 +88,7 @@ ContextOverlayInterface::ContextOverlayInterface() { void ContextOverlayInterface::initializeSelectionToSceneHandler(SelectionToSceneHandler& handler, const QString& selectionName, render::Transaction& transaction) { handler.initialize(selectionName); connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &handler, &SelectionToSceneHandler::selectedItemsListChanged); - transaction.resetSelectionOutline(selectionName.toStdString()); + transaction.resetSelectionHighlight(selectionName.toStdString()); } static const uint32_t MOUSE_HW_ID = 0; diff --git a/libraries/render-utils/src/Outline.slf b/libraries/render-utils/src/Highlight.slf similarity index 72% rename from libraries/render-utils/src/Outline.slf rename to libraries/render-utils/src/Highlight.slf index 68ef870cba..bf65f92613 100644 --- a/libraries/render-utils/src/Outline.slf +++ b/libraries/render-utils/src/Highlight.slf @@ -1,5 +1,5 @@ -// Outline.slf -// Add outline effect based on two zbuffers : one containing the total scene z and another +// Highlight.slf +// Add highlight effect based on two zbuffers : one containing the total scene z and another // with the z of only the objects to be outlined. // This is the version without the fill effect inside the silhouette. // @@ -9,5 +9,5 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include Outline.slh@> +<@include Highlight.slh@> <$main(0)$> diff --git a/libraries/render-utils/src/Outline.slh b/libraries/render-utils/src/Highlight.slh similarity index 75% rename from libraries/render-utils/src/Outline.slh rename to libraries/render-utils/src/Highlight.slh index aeaf20a24a..2faa10682e 100644 --- a/libraries/render-utils/src/Outline.slh +++ b/libraries/render-utils/src/Highlight.slh @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> <$declareDeferredFrameTransform()$> -<@include Outline_shared.slh@> +<@include Highlight_shared.slh@> -uniform outlineParamsBuffer { - OutlineParameters params; +uniform highlightParamsBuffer { + HighlightParameters params; }; uniform sampler2D sceneDepthMap; -uniform sampler2D outlinedDepthMap; +uniform sampler2D highlightedDepthMap; in vec2 varTexCoord0; out vec4 outFragColor; @@ -35,20 +35,20 @@ void main(void) { // We offset by half a texel to be centered on the depth sample. If we don't do this // the blur will have a different width between the left / right sides and top / bottom // sides of the silhouette - float outlinedDepth = texture(outlinedDepthMap, varTexCoord0).x; + float highlightedDepth = texture(highlightedDepthMap, varTexCoord0).x; float intensity = 0.0; - if (outlinedDepth < FAR_Z) { - // We're not on the far plane so we are on the outlined object, thus no outline to do! + if (highlightedDepth < FAR_Z) { + // We're not on the far plane so we are on the highlighted object, thus no outline to do! <@if IS_FILLED@> // But we need to fill the interior float sceneDepth = texture(sceneDepthMap, varTexCoord0).x; // Transform to linear depth for better precision - outlinedDepth = -evalZeyeFromZdb(outlinedDepth); + highlightedDepth = -evalZeyeFromZdb(highlightedDepth); sceneDepth = -evalZeyeFromZdb(sceneDepth); // Are we occluded? - intensity = sceneDepth < (outlinedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity; + intensity = sceneDepth < (highlightedDepth-LINEAR_DEPTH_BIAS) ? params._occludedFillOpacity : params._unoccludedFillOpacity; <@else@> discard; <@endif@> @@ -70,8 +70,8 @@ void main(void) { for (x=0 ; x=0.0 && uv.x<=1.0) { - outlinedDepth = texture(outlinedDepthMap, uv).x; - intensity += (outlinedDepth < FAR_Z) ? 1.0 : 0.0; + highlightedDepth = texture(highlightedDepthMap, uv).x; + intensity += (highlightedDepth < FAR_Z) ? 1.0 : 0.0; weight += 1.0; } uv.x += deltaUv.x; diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp similarity index 63% rename from libraries/render-utils/src/OutlineEffect.cpp rename to libraries/render-utils/src/HighlightEffect.cpp index 590277bf6d..e332be53de 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -1,5 +1,5 @@ // -// OutlineEffect.cpp +// HighlightEffect.cpp // render-utils/src/ // // Created by Olivier Prat on 08/08/17. @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "OutlineEffect.h" +#include "HighlightEffect.h" #include "GeometryCache.h" @@ -25,18 +25,19 @@ #include "surfaceGeometry_copyDepth_frag.h" #include "debug_deferred_buffer_vert.h" #include "debug_deferred_buffer_frag.h" -#include "Outline_frag.h" -#include "Outline_filled_frag.h" -#include "Outline_aabox_vert.h" +#include "Highlight_frag.h" +#include "Highlight_filled_frag.h" +#include "Highlight_aabox_vert.h" +#include "nop_frag.h" using namespace render; #define OUTLINE_STENCIL_MASK 1 -OutlineRessources::OutlineRessources() { +HighlightRessources::HighlightRessources() { } -void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize()); // If the buffer size changed, we need to delete our FBOs and recreate them at the @@ -55,64 +56,64 @@ void OutlineRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer } } -void OutlineRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil")); _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); _colorFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); } -void OutlineRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); _depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); - _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("outlineDepth")); + _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("highlightDepth")); _depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat); } -gpu::FramebufferPointer OutlineRessources::getDepthFramebuffer() { +gpu::FramebufferPointer HighlightRessources::getDepthFramebuffer() { assert(_depthFrameBuffer); return _depthFrameBuffer; } -gpu::TexturePointer OutlineRessources::getDepthTexture() { +gpu::TexturePointer HighlightRessources::getDepthTexture() { return _depthStencilTexture; } -gpu::FramebufferPointer OutlineRessources::getColorFramebuffer() { +gpu::FramebufferPointer HighlightRessources::getColorFramebuffer() { assert(_colorFrameBuffer); return _colorFrameBuffer; } -OutlineSharedParameters::OutlineSharedParameters() { - _outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX); +HighlightSharedParameters::HighlightSharedParameters() { + _highlightIds.fill(render::HighlightStage::INVALID_INDEX); } -float OutlineSharedParameters::getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight) { - return ceilf(style.width * frameBufferHeight / 400.0f); +float HighlightSharedParameters::getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight) { + return ceilf(style.outlineWidth * frameBufferHeight / 400.0f); } -PrepareDrawOutline::PrepareDrawOutline() { - _ressources = std::make_shared(); +PrepareDrawHighlight::PrepareDrawHighlight() { + _ressources = std::make_shared(); } -void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { +void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto destinationFrameBuffer = inputs; _ressources->update(destinationFrameBuffer); outputs = _ressources; } -gpu::PipelinePointer DrawOutlineMask::_stencilMaskPipeline; -gpu::PipelinePointer DrawOutlineMask::_stencilMaskFillPipeline; -gpu::BufferPointer DrawOutlineMask::_boundsBuffer; +gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline; +gpu::PipelinePointer DrawHighlightMask::_stencilMaskFillPipeline; +gpu::BufferPointer DrawHighlightMask::_boundsBuffer; -DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, - render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : - _outlineIndex{ outlineIndex }, +DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex, + render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters) : + _highlightIndex{ highlightIndex }, _shapePlumber { shapePlumber }, _sharedParameters{ parameters } { } -void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { +void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); auto& inShapes = inputs.get0(); @@ -130,8 +131,8 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con fillState->setColorWriteMask(false, false, false, false); fillState->setCullMode(gpu::State::CULL_FRONT); - auto vs = gpu::Shader::createVertex(std::string(Outline_aabox_vert)); - auto ps = gpu::StandardShaderLib::getDrawWhitePS(); + auto vs = gpu::Shader::createVertex(std::string(Highlight_aabox_vert)); + auto ps = gpu::Shader::createPixel(std::string(nop_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -145,12 +146,12 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con _boundsBuffer = std::make_shared(sizeof(render::ItemBound)); } - auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); - auto outlineId = _sharedParameters->_outlineIds[_outlineIndex]; + auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); + auto highlightId = _sharedParameters->_highlightIds[_highlightIndex]; - if (!inShapes.empty() && !render::OutlineStyleStage::isIndexInvalid(outlineId)) { + if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) { auto ressources = inputs.get1(); - auto& outline = outlineStage->getOutline(outlineId); + auto& highlight = highlightStage->getHighlight(highlightId); RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; @@ -219,62 +220,62 @@ void DrawOutlineMask::run(const render::RenderContextPointer& renderContext, con batch.setViewTransform(viewMat); // Draw stencil mask with object bounding boxes - const auto outlineWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth"); + const auto highlightWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth"); const auto sqrt3 = 1.74f; - const float blurPixelWidth = 2.0f * sqrt3 * OutlineSharedParameters::getBlurPixelWidth(outline._style, args->_viewport.w); + const float blurPixelWidth = 2.0f * sqrt3 * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w); const auto framebufferSize = ressources->getSourceFrameSize(); - auto stencilPipeline = outline._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline; + auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline; batch.setPipeline(stencilPipeline); batch.setResourceBuffer(0, _boundsBuffer); - batch._glUniform2f(outlineWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y); + batch._glUniform2f(highlightWidthLoc, blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y); static const int NUM_VERTICES_PER_CUBE = 36; batch.draw(gpu::TRIANGLES, NUM_VERTICES_PER_CUBE * (gpu::uint32) itemBounds.size(), 0); }); } else { - // Outline rect should be null as there are no outlined shapes + // Highlight rect should be null as there are no highlighted shapes outputs = glm::ivec4(0, 0, 0, 0); } } -gpu::PipelinePointer DrawOutline::_pipeline; -gpu::PipelinePointer DrawOutline::_pipelineFilled; +gpu::PipelinePointer DrawHighlight::_pipeline; +gpu::PipelinePointer DrawHighlight::_pipelineFilled; -DrawOutline::DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters) : - _outlineIndex{ outlineIndex }, +DrawHighlight::DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters) : + _highlightIndex{ highlightIndex }, _sharedParameters{ parameters } { } -void DrawOutline::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { - auto outlineFrameBuffer = inputs.get1(); - auto outlineRect = inputs.get3(); +void DrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto highlightFrameBuffer = inputs.get1(); + auto highlightRect = inputs.get3(); - if (outlineFrameBuffer && outlineRect.z>0 && outlineRect.w>0) { + if (highlightFrameBuffer && highlightRect.z>0 && highlightRect.w>0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); - auto outlinedDepthTexture = outlineFrameBuffer->getDepthTexture(); - auto destinationFrameBuffer = outlineFrameBuffer->getColorFramebuffer(); - auto framebufferSize = glm::ivec2(outlinedDepthTexture->getDimensions()); + auto highlightedDepthTexture = highlightFrameBuffer->getDepthTexture(); + auto destinationFrameBuffer = highlightFrameBuffer->getColorFramebuffer(); + auto framebufferSize = glm::ivec2(highlightedDepthTexture->getDimensions()); if (sceneDepthBuffer) { auto args = renderContext->args; - auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); - auto outlineId = _sharedParameters->_outlineIds[_outlineIndex]; - if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) { - auto& outline = outlineStage->getOutline(_sharedParameters->_outlineIds[_outlineIndex]); - auto pipeline = getPipeline(outline._style); + auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); + auto highlightId = _sharedParameters->_highlightIds[_highlightIndex]; + if (!render::HighlightStage::isIndexInvalid(highlightId)) { + auto& highlight = highlightStage->getHighlight(_sharedParameters->_highlightIds[_highlightIndex]); + auto pipeline = getPipeline(highlight._style); { auto& shaderParameters = _configuration.edit(); - shaderParameters._color = outline._style.color; - shaderParameters._intensity = outline._style.intensity * (outline._style.glow ? 2.0f : 1.0f); - shaderParameters._unoccludedFillOpacity = outline._style.unoccludedFillOpacity; - shaderParameters._occludedFillOpacity = outline._style.occludedFillOpacity; - shaderParameters._threshold = outline._style.glow ? 1.0f : 1e-3f; - shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(outline._style.width * 3 + 0.5f))); - // Size is in normalized screen height. We decide that for outline width = 1, this is equal to 1/400. - auto size = outline._style.width / 400.0f; + shaderParameters._color = highlight._style.color; + shaderParameters._intensity = highlight._style.outlineIntensity * (highlight._style.isOutlineSmooth ? 2.0f : 1.0f); + shaderParameters._unoccludedFillOpacity = highlight._style.unoccludedFillOpacity; + shaderParameters._occludedFillOpacity = highlight._style.occludedFillOpacity; + shaderParameters._threshold = highlight._style.isOutlineSmooth ? 1.0f : 1e-3f; + shaderParameters._blurKernelSize = std::min(7, std::max(2, (int)floorf(highlight._style.outlineWidth * 3 + 0.5f))); + // Size is in normalized screen height. We decide that for highlight width = 1, this is equal to 1/400. + auto size = highlight._style.outlineWidth / 400.0f; shaderParameters._size.x = (size * framebufferSize.y) / framebufferSize.x; shaderParameters._size.y = size; } @@ -289,10 +290,10 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); batch.setPipeline(pipeline); - batch.setUniformBuffer(OUTLINE_PARAMS_SLOT, _configuration); + batch.setUniformBuffer(HIGHLIGHT_PARAMS_SLOT, _configuration); batch.setUniformBuffer(FRAME_TRANSFORM_SLOT, frameTransform->getFrameTransformBuffer()); - batch.setResourceTexture(SCENE_DEPTH_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); - batch.setResourceTexture(OUTLINED_DEPTH_SLOT, outlinedDepthTexture); + batch.setResourceTexture(SCENE_DEPTH_MAP_SLOT, sceneDepthBuffer->getPrimaryDepthTexture()); + batch.setResourceTexture(HIGHLIGHTED_DEPTH_MAP_SLOT, highlightedDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); }); } @@ -300,7 +301,7 @@ void DrawOutline::run(const render::RenderContextPointer& renderContext, const I } } -const gpu::PipelinePointer& DrawOutline::getPipeline(const render::OutlineStyle& style) { +const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightStyle& style) { if (!_pipeline) { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(gpu::State::DepthTest(false, false)); @@ -308,19 +309,19 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(const render::OutlineStyle& state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(Outline_frag)); + auto ps = gpu::Shader::createPixel(std::string(Highlight_frag)); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding("outlineParamsBuffer", OUTLINE_PARAMS_SLOT)); + slotBindings.insert(gpu::Shader::Binding("highlightParamsBuffer", HIGHLIGHT_PARAMS_SLOT)); slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", FRAME_TRANSFORM_SLOT)); - slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_SLOT)); - slotBindings.insert(gpu::Shader::Binding("outlinedDepthMap", OUTLINED_DEPTH_SLOT)); + slotBindings.insert(gpu::Shader::Binding("sceneDepthMap", SCENE_DEPTH_MAP_SLOT)); + slotBindings.insert(gpu::Shader::Binding("highlightedDepthMap", HIGHLIGHTED_DEPTH_MAP_SLOT)); gpu::Shader::makeProgram(*program, slotBindings); _pipeline = gpu::Pipeline::create(program, state); - ps = gpu::Shader::createPixel(std::string(Outline_filled_frag)); + ps = gpu::Shader::createPixel(std::string(Highlight_filled_frag)); program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); @@ -328,33 +329,33 @@ const gpu::PipelinePointer& DrawOutline::getPipeline(const render::OutlineStyle& return style.isFilled() ? _pipelineFilled : _pipeline; } -DebugOutline::DebugOutline() { +DebugHighlight::DebugHighlight() { _geometryDepthId = DependencyManager::get()->allocateID(); } -DebugOutline::~DebugOutline() { +DebugHighlight::~DebugHighlight() { auto geometryCache = DependencyManager::get(); if (geometryCache) { geometryCache->releaseID(_geometryDepthId); } } -void DebugOutline::configure(const Config& config) { +void DebugHighlight::configure(const Config& config) { _isDisplayEnabled = config.viewMask; } -void DebugOutline::run(const render::RenderContextPointer& renderContext, const Inputs& input) { - const auto outlineRessources = input.get0(); - const auto outlineRect = input.get1(); +void DebugHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& input) { + const auto highlightRessources = input.get0(); + const auto highlightRect = input.get1(); - if (_isDisplayEnabled && outlineRessources && outlineRect.z>0 && outlineRect.w>0) { + if (_isDisplayEnabled && highlightRessources && highlightRect.z>0 && highlightRect.w>0) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); - batch.setFramebuffer(outlineRessources->getColorFramebuffer()); + batch.setFramebuffer(highlightRessources->getColorFramebuffer()); const auto geometryBuffer = DependencyManager::get(); @@ -369,7 +370,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); batch.setPipeline(getDepthPipeline()); - batch.setResourceTexture(0, outlineRessources->getDepthTexture()); + batch.setResourceTexture(0, highlightRessources->getDepthTexture()); const glm::vec2 bottomLeft(-1.0f, -1.0f); const glm::vec2 topRight(1.0f, 1.0f); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId); @@ -379,7 +380,7 @@ void DebugOutline::run(const render::RenderContextPointer& renderContext, const } } -void DebugOutline::initializePipelines() { +void DebugHighlight::initializePipelines() { static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert }; static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag }; static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; @@ -417,7 +418,7 @@ void DebugOutline::initializePipelines() { } } -const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { +const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() { if (!_depthPipeline) { initializePipelines(); } @@ -425,44 +426,44 @@ const gpu::PipelinePointer& DebugOutline::getDepthPipeline() { return _depthPipeline; } -void SelectionToOutline::run(const render::RenderContextPointer& renderContext, Outputs& outputs) { - auto outlineStage = renderContext->_scene->getStage(render::OutlineStyleStage::getName()); +void SelectionToHighlight::run(const render::RenderContextPointer& renderContext, Outputs& outputs) { + auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); outputs.clear(); - _sharedParameters->_outlineIds.fill(render::OutlineStyleStage::INVALID_INDEX); + _sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX); - for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) { + for (auto i = 0; i < HighlightSharedParameters::MAX_HIGHLIGHT_COUNT; i++) { std::ostringstream stream; stream << "contextOverlayHighlightList"; if (i > 0) { stream << i; } auto selectionName = stream.str(); - auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); - if (!render::OutlineStyleStage::isIndexInvalid(outlineId)) { - _sharedParameters->_outlineIds[outputs.size()] = outlineId; + auto highlightId = highlightStage->getHighlightIdBySelection(selectionName); + if (!render::HighlightStage::isIndexInvalid(highlightId)) { + _sharedParameters->_highlightIds[outputs.size()] = highlightId; outputs.emplace_back(selectionName); } } } void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - if (_outlineIndex < inputs.size()) { - outputs = inputs[_outlineIndex]; + if (_highlightIndex < inputs.size()) { + outputs = inputs[_highlightIndex]; } else { outputs.clear(); } } -DrawOutlineTask::DrawOutlineTask() { +DrawHighlightTask::DrawHighlightTask() { } -void DrawOutlineTask::configure(const Config& config) { +void DrawHighlightTask::configure(const Config& config) { } -void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { +void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { const auto items = inputs.getN(0).get(); const auto sceneFrameBuffer = inputs.getN(1); const auto primaryFramebuffer = inputs.getN(2); @@ -477,53 +478,53 @@ void DrawOutlineTask::build(JobModel& task, const render::Varying& inputs, rende initMaskPipelines(*shapePlumber, state); } - auto sharedParameters = std::make_shared(); + auto sharedParameters = std::make_shared(); - const auto outlineSelectionNames = task.addJob("SelectionToOutline", sharedParameters); + const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters); - // Prepare for outline group rendering. - const auto outlineRessources = task.addJob("PrepareOutline", primaryFramebuffer); - render::Varying outline0Rect; + // Prepare for highlight group rendering. + const auto highlightRessources = task.addJob("PrepareHighlight", primaryFramebuffer); + render::Varying highlight0Rect; - for (auto i = 0; i < OutlineSharedParameters::MAX_OUTLINE_COUNT; i++) { - const auto selectionName = task.addJob("ExtractSelectionName", outlineSelectionNames, i); + for (auto i = 0; i < HighlightSharedParameters::MAX_HIGHLIGHT_COUNT; i++) { + const auto selectionName = task.addJob("ExtractSelectionName", highlightSelectionNames, i); const auto groupItems = addSelectItemJobs(task, selectionName, items); - const auto outlinedItemIDs = task.addJob("OutlineMetaToSubItemIDs", groupItems); - const auto outlinedItems = task.addJob("OutlineMetaToSubItems", outlinedItemIDs); + const auto highlightedItemIDs = task.addJob("HighlightMetaToSubItemIDs", groupItems); + const auto highlightedItems = task.addJob("HighlightMetaToSubItems", highlightedItemIDs); // Sort - const auto sortedPipelines = task.addJob("OutlinePipelineSort", outlinedItems); - const auto sortedBounds = task.addJob("OutlineDepthSort", sortedPipelines); + const auto sortedPipelines = task.addJob("HighlightPipelineSort", highlightedItems); + const auto sortedBounds = task.addJob("HighlightDepthSort", sortedPipelines); - // Draw depth of outlined objects in separate buffer + // Draw depth of highlighted objects in separate buffer std::string name; { std::ostringstream stream; - stream << "OutlineMask" << i; + stream << "HighlightMask" << i; name = stream.str(); } - const auto drawMaskInputs = DrawOutlineMask::Inputs(sortedBounds, outlineRessources).asVarying(); - const auto outlinedRect = task.addJob(name, drawMaskInputs, i, shapePlumber, sharedParameters); + const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightRessources).asVarying(); + const auto highlightedRect = task.addJob(name, drawMaskInputs, i, shapePlumber, sharedParameters); if (i == 0) { - outline0Rect = outlinedRect; + highlight0Rect = highlightedRect; } - // Draw outline + // Draw highlight { std::ostringstream stream; - stream << "OutlineEffect" << i; + stream << "HighlightEffect" << i; name = stream.str(); } - const auto drawOutlineInputs = DrawOutline::Inputs(deferredFrameTransform, outlineRessources, sceneFrameBuffer, outlinedRect).asVarying(); - task.addJob(name, drawOutlineInputs, i, sharedParameters); + const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightRessources, sceneFrameBuffer, highlightedRect).asVarying(); + task.addJob(name, drawHighlightInputs, i, sharedParameters); } - // Debug outline - const auto debugInputs = DebugOutline::Inputs(outlineRessources, const_cast(outline0Rect)).asVarying(); - task.addJob("OutlineDebug", debugInputs); + // Debug highlight + const auto debugInputs = DebugHighlight::Inputs(highlightRessources, const_cast(highlight0Rect)).asVarying(); + task.addJob("HighlightDebug", debugInputs); } -const render::Varying DrawOutlineTask::addSelectItemJobs(JobModel& task, const render::Varying& selectionName, +const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const render::Varying& selectionName, const RenderFetchCullSortTask::BucketList& items) { const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; @@ -542,7 +543,7 @@ const render::Varying DrawOutlineTask::addSelectItemJobs(JobModel& task, const r #include "model_shadow_frag.h" -void DrawOutlineTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { +void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/HighlightEffect.h similarity index 55% rename from libraries/render-utils/src/OutlineEffect.h rename to libraries/render-utils/src/HighlightEffect.h index e25184eb5b..0531c03efd 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/HighlightEffect.h @@ -1,5 +1,5 @@ // -// OutlineEffect.h +// HighlightEffect.h // render-utils/src/ // // Created by Olivier Prat on 08/08/17. @@ -9,19 +9,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_utils_OutlineEffect_h -#define hifi_render_utils_OutlineEffect_h +#ifndef hifi_render_utils_HighlightEffect_h +#define hifi_render_utils_HighlightEffect_h #include -#include +#include #include #include "DeferredFramebuffer.h" #include "DeferredFrameTransform.h" -class OutlineRessources { +class HighlightRessources { public: - OutlineRessources(); + HighlightRessources(); gpu::FramebufferPointer getDepthFramebuffer(); gpu::TexturePointer getDepthTexture(); @@ -44,131 +44,131 @@ protected: void allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer); }; -using OutlineRessourcesPointer = std::shared_ptr; +using HighlightRessourcesPointer = std::shared_ptr; -class OutlineSharedParameters { +class HighlightSharedParameters { public: enum { - MAX_OUTLINE_COUNT = 8 + MAX_HIGHLIGHT_COUNT = 8 }; - OutlineSharedParameters(); + HighlightSharedParameters(); - std::array _outlineIds; + std::array _highlightIds; - static float getBlurPixelWidth(const render::OutlineStyle& style, int frameBufferHeight); + static float getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight); }; -using OutlineSharedParametersPointer = std::shared_ptr; +using HighlightSharedParametersPointer = std::shared_ptr; -class PrepareDrawOutline { +class PrepareDrawHighlight { public: using Inputs = gpu::FramebufferPointer; - using Outputs = OutlineRessourcesPointer; - using JobModel = render::Job::ModelIO; + using Outputs = HighlightRessourcesPointer; + using JobModel = render::Job::ModelIO; - PrepareDrawOutline(); + PrepareDrawHighlight(); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); private: - OutlineRessourcesPointer _ressources; + HighlightRessourcesPointer _ressources; }; -class SelectionToOutline { +class SelectionToHighlight { public: using Outputs = std::vector; - using JobModel = render::Job::ModelO; + using JobModel = render::Job::ModelO; - SelectionToOutline(OutlineSharedParametersPointer parameters) : _sharedParameters{ parameters } {} + SelectionToHighlight(HighlightSharedParametersPointer parameters) : _sharedParameters{ parameters } {} void run(const render::RenderContextPointer& renderContext, Outputs& outputs); private: - OutlineSharedParametersPointer _sharedParameters; + HighlightSharedParametersPointer _sharedParameters; }; class ExtractSelectionName { public: - using Inputs = SelectionToOutline::Outputs; + using Inputs = SelectionToHighlight::Outputs; using Outputs = std::string; using JobModel = render::Job::ModelIO; - ExtractSelectionName(unsigned int outlineIndex) : _outlineIndex{ outlineIndex } {} + ExtractSelectionName(unsigned int highlightIndex) : _highlightIndex{ highlightIndex } {} void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); private: - unsigned int _outlineIndex; + unsigned int _highlightIndex; }; -class DrawOutlineMask { +class DrawHighlightMask { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet2; using Outputs = glm::ivec4; - using JobModel = render::Job::ModelIO; + using JobModel = render::Job::ModelIO; - DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters); + DrawHighlightMask(unsigned int highlightIndex, render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); protected: - unsigned int _outlineIndex; + unsigned int _highlightIndex; render::ShapePlumberPointer _shapePlumber; - OutlineSharedParametersPointer _sharedParameters; + HighlightSharedParametersPointer _sharedParameters; static gpu::BufferPointer _boundsBuffer; static gpu::PipelinePointer _stencilMaskPipeline; static gpu::PipelinePointer _stencilMaskFillPipeline; }; -class DrawOutline { +class DrawHighlight { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = render::Job::Config; - using JobModel = render::Job::ModelI; + using JobModel = render::Job::ModelI; - DrawOutline(unsigned int outlineIndex, OutlineSharedParametersPointer parameters); + DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); private: -#include "Outline_shared.slh" +#include "Highlight_shared.slh" enum { - SCENE_DEPTH_SLOT = 0, - OUTLINED_DEPTH_SLOT, + SCENE_DEPTH_MAP_SLOT = 0, + HIGHLIGHTED_DEPTH_MAP_SLOT, - OUTLINE_PARAMS_SLOT = 0, + HIGHLIGHT_PARAMS_SLOT = 0, FRAME_TRANSFORM_SLOT, }; - using OutlineConfigurationBuffer = gpu::StructBuffer; + using HighlightConfigurationBuffer = gpu::StructBuffer; - static const gpu::PipelinePointer& getPipeline(const render::OutlineStyle& style); + static const gpu::PipelinePointer& getPipeline(const render::HighlightStyle& style); static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; - unsigned int _outlineIndex; - OutlineParameters _parameters; - OutlineSharedParametersPointer _sharedParameters; - OutlineConfigurationBuffer _configuration; + unsigned int _highlightIndex; + HighlightParameters _parameters; + HighlightSharedParametersPointer _sharedParameters; + HighlightConfigurationBuffer _configuration; }; -class DebugOutlineConfig : public render::Job::Config { +class DebugHighlightConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool viewMask MEMBER viewMask NOTIFY dirty) @@ -180,14 +180,14 @@ signals: void dirty(); }; -class DebugOutline { +class DebugHighlight { public: - using Inputs = render::VaryingSet2; - using Config = DebugOutlineConfig; - using JobModel = render::Job::ModelI; + using Inputs = render::VaryingSet2; + using Config = DebugHighlightConfig; + using JobModel = render::Job::ModelI; - DebugOutline(); - ~DebugOutline(); + DebugHighlight(); + ~DebugHighlight(); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); @@ -202,14 +202,14 @@ private: void initializePipelines(); }; -class DrawOutlineTask { +class DrawHighlightTask { public: using Inputs = render::VaryingSet4; using Config = render::Task::Config; - using JobModel = render::Task::ModelI; + using JobModel = render::Task::ModelI; - DrawOutlineTask(); + DrawHighlightTask(); void configure(const Config& config); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); @@ -221,6 +221,6 @@ private: }; -#endif // hifi_render_utils_OutlineEffect_h +#endif // hifi_render_utils_HighlightEffect_h diff --git a/libraries/render-utils/src/Outline_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv similarity index 100% rename from libraries/render-utils/src/Outline_aabox.slv rename to libraries/render-utils/src/Highlight_aabox.slv diff --git a/libraries/render-utils/src/Outline_filled.slf b/libraries/render-utils/src/Highlight_filled.slf similarity index 71% rename from libraries/render-utils/src/Outline_filled.slf rename to libraries/render-utils/src/Highlight_filled.slf index aaa3396bac..53530746f0 100644 --- a/libraries/render-utils/src/Outline_filled.slf +++ b/libraries/render-utils/src/Highlight_filled.slf @@ -1,5 +1,5 @@ -// Outline_filled.slf -// Add outline effect based on two zbuffers : one containing the total scene z and another +// Highlight_filled.slf +// Add highlight effect based on two zbuffers : one containing the total scene z and another // with the z of only the objects to be outlined. // This is the version with the fill effect inside the silhouette. // @@ -9,5 +9,5 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include Outline.slh@> +<@include Highlight.slh@> <$main(1)$> diff --git a/libraries/render-utils/src/Outline_shared.slh b/libraries/render-utils/src/Highlight_shared.slh similarity index 84% rename from libraries/render-utils/src/Outline_shared.slh rename to libraries/render-utils/src/Highlight_shared.slh index 3fd089e2fc..5efbde4d52 100644 --- a/libraries/render-utils/src/Outline_shared.slh +++ b/libraries/render-utils/src/Highlight_shared.slh @@ -1,4 +1,4 @@ -// glsl / C++ compatible source as interface for Outline +// glsl / C++ compatible source as interface for highlight #ifdef __cplusplus # define TVEC2 glm::vec2 # define TVEC3 glm::vec3 @@ -9,7 +9,7 @@ # define TVEC4 vec4 #endif -struct OutlineParameters +struct HighlightParameters { TVEC3 _color; float _intensity; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 52b8896e69..1f839b25eb 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -42,7 +42,7 @@ #include "ToneMappingEffect.h" #include "SubsurfaceScattering.h" #include "DrawHaze.h" -#include "OutlineEffect.h" +#include "HighlightEffect.h" #include @@ -183,15 +183,15 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer).asVarying(); task.addJob("ToneMapping", toneMappingInputs); - const auto outlineRangeTimer = task.addJob("BeginOutlineRangeTimer", "Outline"); + const auto outlineRangeTimer = task.addJob("BeginHighlightRangeTimer", "Highlight"); // Select items that need to be outlined const auto selectionBaseName = "contextOverlayHighlightList"; const auto selectedItems = addSelectItemJobs(task, selectionBaseName, metas, opaques, transparents); - const auto outlineInputs = DrawOutlineTask::Inputs(items.get0(), deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); - task.addJob("DrawOutline", outlineInputs); + const auto outlineInputs = DrawHighlightTask::Inputs(items.get0(), deferredFramebuffer, primaryFramebuffer, deferredFrameTransform).asVarying(); + task.addJob("DrawHighlight", outlineInputs); - task.addJob("OutlineRangeTimer", outlineRangeTimer); + task.addJob("HighlightRangeTimer", outlineRangeTimer); { // DEbug the bounds of the rendered items, still look at the zbuffer task.addJob("DrawMetaBounds", metas); diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index d37569b526..e05f28ef0d 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -15,7 +15,7 @@ #include "BackgroundStage.h" #include "HazeStage.h" #include -#include +#include #include "DeferredLightingEffect.h" void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { @@ -23,7 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); task.addJob("TransitionStageSetup"); - task.addJob("OutlineStyleStageSetup"); + task.addJob("HighlightStageSetup"); task.addJob("DefaultLightingSetup"); diff --git a/libraries/render/src/render/HighlightStage.cpp b/libraries/render/src/render/HighlightStage.cpp new file mode 100644 index 0000000000..effb7c7e98 --- /dev/null +++ b/libraries/render/src/render/HighlightStage.cpp @@ -0,0 +1,46 @@ +#include "HighlightStage.h" + +using namespace render; + +std::string HighlightStage::_name("Highlight"); + +HighlightStage::Index HighlightStage::addHighlight(const std::string& selectionName, const HighlightStyle& style) { + Highlight outline{ selectionName, style }; + Index id; + + id = _highlights.newElement(outline); + _activeHighlightIds.push_back(id); + + return id; +} + +void HighlightStage::removeHighlight(Index index) { + HighlightIdList::iterator idIterator = std::find(_activeHighlightIds.begin(), _activeHighlightIds.end(), index); + if (idIterator != _activeHighlightIds.end()) { + _activeHighlightIds.erase(idIterator); + } + if (!_highlights.isElementFreed(index)) { + _highlights.freeElement(index); + } +} + +Index HighlightStage::getHighlightIdBySelection(const std::string& selectionName) const { + for (auto outlineId : _activeHighlightIds) { + const auto& outline = _highlights.get(outlineId); + if (outline._selectionName == selectionName) { + return outlineId; + } + } + return INVALID_INDEX; +} + +HighlightStageSetup::HighlightStageSetup() { +} + +void HighlightStageSetup::run(const render::RenderContextPointer& renderContext) { + if (!renderContext->_scene->getStage(HighlightStage::getName())) { + auto stage = std::make_shared(); + renderContext->_scene->resetStage(HighlightStage::getName(), stage); + } +} + diff --git a/libraries/render/src/render/HighlightStage.h b/libraries/render/src/render/HighlightStage.h new file mode 100644 index 0000000000..a2c123580c --- /dev/null +++ b/libraries/render/src/render/HighlightStage.h @@ -0,0 +1,77 @@ +// +// HighlightStage.h + +// Created by Olivier Prat on 07/07/2017. +// 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 +// + +#ifndef hifi_render_utils_HighlightStage_h +#define hifi_render_utils_HighlightStage_h + +#include "Stage.h" +#include "Engine.h" +#include "IndexedContainer.h" +#include "HighlightStyle.h" + +namespace render { + + // Highlight stage to set up HighlightStyle-related effects + class HighlightStage : public Stage { + public: + + class Highlight { + public: + + Highlight(const std::string& selectionName, const HighlightStyle& style) : _selectionName{ selectionName }, _style{ style } { } + + std::string _selectionName; + HighlightStyle _style; + + }; + + static const std::string& getName() { return _name; } + + using Index = render::indexed_container::Index; + static const Index INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; + using HighlightIdList = render::indexed_container::Indices; + + static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } + + bool checkHighlightId(Index index) const { return _highlights.checkIndex(index); } + + const Highlight& getHighlight(Index index) const { return _highlights.get(index); } + Highlight& editHighlight(Index index) { return _highlights.edit(index); } + + Index addHighlight(const std::string& selectionName, const HighlightStyle& style = HighlightStyle()); + Index getHighlightIdBySelection(const std::string& selectionName) const; + void removeHighlight(Index index); + + HighlightIdList::iterator begin() { return _activeHighlightIds.begin(); } + HighlightIdList::iterator end() { return _activeHighlightIds.end(); } + + private: + + using Highlights = render::indexed_container::IndexedVector; + + static std::string _name; + + Highlights _highlights; + HighlightIdList _activeHighlightIds; + }; + using HighlightStagePointer = std::shared_ptr; + + class HighlightStageSetup { + public: + using JobModel = render::Job::Model; + + HighlightStageSetup(); + void run(const RenderContextPointer& renderContext); + + protected: + }; + +} +#endif // hifi_render_utils_HighlightStage_h diff --git a/libraries/render/src/render/OutlineStyle.h b/libraries/render/src/render/HighlightStyle.h similarity index 68% rename from libraries/render/src/render/OutlineStyle.h rename to libraries/render/src/render/HighlightStyle.h index cdcdf79f3e..6e7373c78b 100644 --- a/libraries/render/src/render/OutlineStyle.h +++ b/libraries/render/src/render/HighlightStyle.h @@ -1,5 +1,5 @@ // -// OutlineStyle.h +// HighlightStyle.h // Created by Olivier Prat on 11/06/2017. // Copyright 2017 High Fidelity, Inc. @@ -8,8 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_utils_OutlineStyle_h -#define hifi_render_utils_OutlineStyle_h +#ifndef hifi_render_utils_HighlightStyle_h +#define hifi_render_utils_HighlightStyle_h #include @@ -18,7 +18,7 @@ namespace render { // This holds the configuration for a particular outline style - class OutlineStyle { + class HighlightStyle { public: bool isFilled() const { @@ -26,14 +26,13 @@ namespace render { } glm::vec3 color{ 1.f, 0.7f, 0.2f }; - float width{ 2.0f }; - float intensity{ 0.9f }; + float outlineWidth{ 2.0f }; + float outlineIntensity{ 0.9f }; float unoccludedFillOpacity{ 0.0f }; float occludedFillOpacity{ 0.0f }; - bool glow{ false }; - std::string selectionName; + bool isOutlineSmooth{ false }; }; } -#endif // hifi_render_utils_OutlineStyle_h \ No newline at end of file +#endif // hifi_render_utils_HighlightStyle_h \ No newline at end of file diff --git a/libraries/render/src/render/OutlineStyleStage.cpp b/libraries/render/src/render/OutlineStyleStage.cpp deleted file mode 100644 index e3fd1672de..0000000000 --- a/libraries/render/src/render/OutlineStyleStage.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "OutlineStyleStage.h" - -using namespace render; - -std::string OutlineStyleStage::_name("OutlineStyle"); - -OutlineStyleStage::Index OutlineStyleStage::addOutline(const std::string& selectionName, const OutlineStyle& style) { - Outline outline{ selectionName, style }; - Index id; - - id = _outlines.newElement(outline); - _activeOutlineIds.push_back(id); - - return id; -} - -void OutlineStyleStage::removeOutline(Index index) { - OutlineIdList::iterator idIterator = std::find(_activeOutlineIds.begin(), _activeOutlineIds.end(), index); - if (idIterator != _activeOutlineIds.end()) { - _activeOutlineIds.erase(idIterator); - } - if (!_outlines.isElementFreed(index)) { - _outlines.freeElement(index); - } -} - -Index OutlineStyleStage::getOutlineIdBySelection(const std::string& selectionName) const { - for (auto outlineId : _activeOutlineIds) { - const auto& outline = _outlines.get(outlineId); - if (outline._selectionName == selectionName) { - return outlineId; - } - } - return INVALID_INDEX; -} - -OutlineStyleStageSetup::OutlineStyleStageSetup() { -} - -void OutlineStyleStageSetup::run(const render::RenderContextPointer& renderContext) { - if (!renderContext->_scene->getStage(OutlineStyleStage::getName())) { - auto stage = std::make_shared(); - renderContext->_scene->resetStage(OutlineStyleStage::getName(), stage); - } -} - diff --git a/libraries/render/src/render/OutlineStyleStage.h b/libraries/render/src/render/OutlineStyleStage.h deleted file mode 100644 index 79835a22a4..0000000000 --- a/libraries/render/src/render/OutlineStyleStage.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// OutlineStyleStage.h - -// Created by Olivier Prat on 07/07/2017. -// 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 -// - -#ifndef hifi_render_utils_outlinestage_h -#define hifi_render_utils_outlinestage_h - -#include "Stage.h" -#include "Engine.h" -#include "IndexedContainer.h" -#include "OutlineStyle.h" - -namespace render { - - // OutlineStyle stage to set up OutlineStyle-related effects - class OutlineStyleStage : public Stage { - public: - - class Outline { - public: - - Outline(const std::string& selectionName, const OutlineStyle& style) : _selectionName{ selectionName }, _style{ style } { } - - std::string _selectionName; - OutlineStyle _style; - - }; - - static const std::string& getName() { return _name; } - - using Index = render::indexed_container::Index; - static const Index INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; - using OutlineIdList = render::indexed_container::Indices; - - static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } - - bool checkOutlineId(Index index) const { return _outlines.checkIndex(index); } - - const Outline& getOutline(Index OutlineStyleId) const { return _outlines.get(OutlineStyleId); } - Outline& editOutline(Index OutlineStyleId) { return _outlines.edit(OutlineStyleId); } - - Index addOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle()); - Index getOutlineIdBySelection(const std::string& selectionName) const; - void removeOutline(Index index); - - OutlineIdList::iterator begin() { return _activeOutlineIds.begin(); } - OutlineIdList::iterator end() { return _activeOutlineIds.end(); } - - private: - - using Outlines = render::indexed_container::IndexedVector; - - static std::string _name; - - Outlines _outlines; - OutlineIdList _activeOutlineIds; - }; - using OutlineStyleStagePointer = std::shared_ptr; - - class OutlineStyleStageSetup { - public: - using JobModel = render::Job::Model; - - OutlineStyleStageSetup(); - void run(const RenderContextPointer& renderContext); - - protected: - }; - -} -#endif // hifi_render_utils_outlinestage_h diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 0e680dfdaf..9cdaa89cf6 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -14,7 +14,7 @@ #include #include "Logging.h" #include "TransitionStage.h" -#include "OutlineStyleStage.h" +#include "HighlightStage.h" using namespace render; @@ -55,16 +55,16 @@ void Transaction::resetSelection(const Selection& selection) { _resetSelections.emplace_back(selection); } -void Transaction::resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style) { - _outlineResets.emplace_back(OutlineReset{ selectionName, style }); +void Transaction::resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style) { + _highlightResets.emplace_back(HighlightReset{ selectionName, style }); } -void Transaction::removeOutlineFromSelection(const std::string& selectionName) { - _outlineRemoves.emplace_back(selectionName); +void Transaction::removeHighlightFromSelection(const std::string& selectionName) { + _highlightRemoves.emplace_back(selectionName); } -void Transaction::querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func) { - _outlineQueries.emplace_back(OutlineQuery{ selectionName, func }); +void Transaction::querySelectionHighlight(const std::string& selectionName, SelectionHighlightQueryFunc func) { + _highlightQueries.emplace_back(HighlightQuery{ selectionName, func }); } void Transaction::merge(const Transaction& transaction) { @@ -75,9 +75,9 @@ void Transaction::merge(const Transaction& transaction) { _addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end()); _queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end()); _reAppliedTransitions.insert(_reAppliedTransitions.end(), transaction._reAppliedTransitions.begin(), transaction._reAppliedTransitions.end()); - _outlineResets.insert(_outlineResets.end(), transaction._outlineResets.begin(), transaction._outlineResets.end()); - _outlineRemoves.insert(_outlineRemoves.end(), transaction._outlineRemoves.begin(), transaction._outlineRemoves.end()); - _outlineQueries.insert(_outlineQueries.end(), transaction._outlineQueries.begin(), transaction._outlineQueries.end()); + _highlightResets.insert(_highlightResets.end(), transaction._highlightResets.begin(), transaction._highlightResets.end()); + _highlightRemoves.insert(_highlightRemoves.end(), transaction._highlightRemoves.begin(), transaction._highlightRemoves.end()); + _highlightQueries.insert(_highlightQueries.end(), transaction._highlightQueries.begin(), transaction._highlightQueries.end()); } @@ -193,9 +193,9 @@ void Scene::processTransactionFrame(const Transaction& transaction) { resetSelections(transaction._resetSelections); } - resetOutlines(transaction._outlineResets); - removeOutlines(transaction._outlineRemoves); - queryOutlines(transaction._outlineQueries); + resetHighlights(transaction._highlightResets); + removeHighlights(transaction._highlightRemoves); + queryHighlights(transaction._highlightQueries); } void Scene::resetItems(const Transaction::Resets& transactions) { @@ -336,44 +336,44 @@ void Scene::queryTransitionItems(const Transaction::TransitionQueries& transacti } } -void Scene::resetOutlines(const Transaction::OutlineResets& transactions) { - auto outlineStage = getStage(OutlineStyleStage::getName()); +void Scene::resetHighlights(const Transaction::HighlightResets& transactions) { + auto outlineStage = getStage(HighlightStage::getName()); for (auto& transaction : transactions) { const auto& selectionName = std::get<0>(transaction); const auto& newStyle = std::get<1>(transaction); - auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + auto outlineId = outlineStage->getHighlightIdBySelection(selectionName); - if (OutlineStyleStage::isIndexInvalid(outlineId)) { - outlineStage->addOutline(selectionName, newStyle); + if (HighlightStage::isIndexInvalid(outlineId)) { + outlineStage->addHighlight(selectionName, newStyle); } else { - outlineStage->editOutline(outlineId)._style = newStyle; + outlineStage->editHighlight(outlineId)._style = newStyle; } } } -void Scene::removeOutlines(const Transaction::OutlineRemoves& transactions) { - auto outlineStage = getStage(OutlineStyleStage::getName()); +void Scene::removeHighlights(const Transaction::HighlightRemoves& transactions) { + auto outlineStage = getStage(HighlightStage::getName()); for (auto& selectionName : transactions) { - auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + auto outlineId = outlineStage->getHighlightIdBySelection(selectionName); - if (!OutlineStyleStage::isIndexInvalid(outlineId)) { - outlineStage->removeOutline(outlineId); + if (!HighlightStage::isIndexInvalid(outlineId)) { + outlineStage->removeHighlight(outlineId); } } } -void Scene::queryOutlines(const Transaction::OutlineQueries& transactions) { - auto outlineStage = getStage(OutlineStyleStage::getName()); +void Scene::queryHighlights(const Transaction::HighlightQueries& transactions) { + auto outlineStage = getStage(HighlightStage::getName()); for (auto& transaction : transactions) { const auto& selectionName = std::get<0>(transaction); const auto& func = std::get<1>(transaction); - auto outlineId = outlineStage->getOutlineIdBySelection(selectionName); + auto outlineId = outlineStage->getHighlightIdBySelection(selectionName); - if (!OutlineStyleStage::isIndexInvalid(outlineId)) { - func(&outlineStage->editOutline(outlineId)._style); + if (!HighlightStage::isIndexInvalid(outlineId)) { + func(&outlineStage->editHighlight(outlineId)._style); } else { func(nullptr); } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 38f528aced..4bf38b89cc 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -17,7 +17,7 @@ #include "Stage.h" #include "Selection.h" #include "Transition.h" -#include "OutlineStyle.h" +#include "HighlightStyle.h" namespace render { @@ -38,7 +38,7 @@ class Transaction { public: typedef std::function TransitionQueryFunc; - typedef std::function SelectionOutlineQueryFunc; + typedef std::function SelectionHighlightQueryFunc; Transaction() {} ~Transaction() {} @@ -63,9 +63,9 @@ public: // Selection transactions void resetSelection(const Selection& selection); - void resetSelectionOutline(const std::string& selectionName, const OutlineStyle& style = OutlineStyle()); - void removeOutlineFromSelection(const std::string& selectionName); - void querySelectionOutline(const std::string& selectionName, SelectionOutlineQueryFunc func); + void resetSelectionHighlight(const std::string& selectionName, const HighlightStyle& style = HighlightStyle()); + void removeHighlightFromSelection(const std::string& selectionName); + void querySelectionHighlight(const std::string& selectionName, SelectionHighlightQueryFunc func); void merge(const Transaction& transaction); @@ -81,9 +81,9 @@ protected: using TransitionQuery = std::tuple; using TransitionReApply = ItemID; using SelectionReset = Selection; - using OutlineReset = std::tuple; - using OutlineRemove = std::string; - using OutlineQuery = std::tuple; + using HighlightReset = std::tuple; + using HighlightRemove = std::string; + using HighlightQuery = std::tuple; using Resets = std::vector; using Removes = std::vector; @@ -92,9 +92,9 @@ protected: using TransitionQueries = std::vector; using TransitionReApplies = std::vector; using SelectionResets = std::vector; - using OutlineResets = std::vector; - using OutlineRemoves = std::vector; - using OutlineQueries = std::vector; + using HighlightResets = std::vector; + using HighlightRemoves = std::vector; + using HighlightQueries = std::vector; Resets _resetItems; Removes _removedItems; @@ -103,9 +103,9 @@ protected: TransitionQueries _queriedTransitions; TransitionReApplies _reAppliedTransitions; SelectionResets _resetSelections; - OutlineResets _outlineResets; - OutlineRemoves _outlineRemoves; - OutlineQueries _outlineQueries; + HighlightResets _highlightResets; + HighlightRemoves _highlightRemoves; + HighlightQueries _highlightQueries; }; typedef std::queue TransactionQueue; @@ -203,9 +203,9 @@ protected: void transitionItems(const Transaction::TransitionAdds& transactions); void reApplyTransitions(const Transaction::TransitionReApplies& transactions); void queryTransitionItems(const Transaction::TransitionQueries& transactions); - void resetOutlines(const Transaction::OutlineResets& transactions); - void removeOutlines(const Transaction::OutlineRemoves& transactions); - void queryOutlines(const Transaction::OutlineQueries& transactions); + void resetHighlights(const Transaction::HighlightResets& transactions); + void removeHighlights(const Transaction::HighlightRemoves& transactions); + void queryHighlights(const Transaction::HighlightQueries& transactions); void collectSubItems(ItemID parentId, ItemIDs& subItems) const; diff --git a/scripts/developer/utilities/render/debugOutline.js b/scripts/developer/utilities/render/debugHighlight.js similarity index 88% rename from scripts/developer/utilities/render/debugOutline.js rename to scripts/developer/utilities/render/debugHighlight.js index ce32d61e1b..5175761978 100644 --- a/scripts/developer/utilities/render/debugOutline.js +++ b/scripts/developer/utilities/render/debugHighlight.js @@ -1,5 +1,5 @@ // -// debugOutline.js +// debugHighlight.js // developer/utilities/render // // Olivier Prat, created on 08/08/2017. @@ -10,9 +10,9 @@ // // Set up the qml ui -var qml = Script.resolvePath('outline.qml'); +var qml = Script.resolvePath('highlight.qml'); var window = new OverlayWindow({ - title: 'Outline', + title: 'Highlight', source: qml, width: 400, height: 400, @@ -54,7 +54,7 @@ var end2 = { visible: true } -var outlineGroupIndex = 0 +var highlightGroupIndex = 0 var isSelectionAddEnabled = false var isSelectionEnabled = false var renderStates = [{name: "test", end: end}]; @@ -72,18 +72,18 @@ var ray = LaserPointers.createLaserPointer({ function getSelectionName() { var selectionName = "contextOverlayHighlightList" - if (outlineGroupIndex>0) { - selectionName += outlineGroupIndex + if (highlightGroupIndex>0) { + selectionName += highlightGroupIndex } return selectionName } function fromQml(message) { tokens = message.split(' ') - print("Received '"+message+"' from outline.qml") - if (tokens[0]=="outline") { - outlineGroupIndex = parseInt(tokens[1]) - print("Switching to outline group "+outlineGroupIndex) + print("Received '"+message+"' from hightlight.qml") + if (tokens[0]=="highlight") { + highlightGroupIndex = parseInt(tokens[1]) + print("Switching to highlight group "+highlightGroupIndex) } else if (tokens[0]=="pick") { isSelectionEnabled = tokens[1]=='true' print("Ray picking set to "+isSelectionEnabled.toString()) @@ -143,7 +143,7 @@ function update(deltaTime) { selectedID = prevID selectedType = prevType Selection.addToSelectedItemsList(selectionName, selectedType, selectedID) - print("OUTLINE " + outlineGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); + print("HIGHLIGHT " + highlightGroupIndex + " picked type: " + result.type + ", id: " + result.objectID); } } else { if (prevID != 0 && !isSelectionAddEnabled) { diff --git a/scripts/developer/utilities/render/outline.qml b/scripts/developer/utilities/render/highlight.qml similarity index 88% rename from scripts/developer/utilities/render/outline.qml rename to scripts/developer/utilities/render/highlight.qml index 8269ea830e..eb2c66b275 100644 --- a/scripts/developer/utilities/render/outline.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -1,5 +1,5 @@ // -// outline.qml +// highlight.qml // developer/utilities/render // // Olivier Prat, created on 08/08/2017. @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "outlinePage" +import "highlightPage" import "qrc:///qml/styles-uit" import "qrc:///qml/controls-uit" as HifiControls @@ -21,7 +21,7 @@ Rectangle { color: hifi.colors.baseGray; anchors.margins: hifi.dimensions.contentMargin.x - property var debugConfig: Render.getConfig("RenderMainView.OutlineDebug") + property var debugConfig: Render.getConfig("RenderMainView.HighlightDebug") signal sendToScript(var message); Column { @@ -65,15 +65,15 @@ Rectangle { height: 400 onCurrentIndexChanged: { - sendToScript("outline "+currentIndex) + sendToScript("highlight "+currentIndex) } Repeater { model: [ 0, 1, 2, 3 ] Tab { title: "Outl."+modelData - OutlinePage { - outlineIndex: modelData + HighlightPage { + highlightIndex: modelData } } } diff --git a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml b/scripts/developer/utilities/render/highlightPage/HighlightPage.qml similarity index 96% rename from scripts/developer/utilities/render/outlinePage/OutlinePage.qml rename to scripts/developer/utilities/render/highlightPage/HighlightPage.qml index ff1d7fa23b..5669f90628 100644 --- a/scripts/developer/utilities/render/outlinePage/OutlinePage.qml +++ b/scripts/developer/utilities/render/highlightPage/HighlightPage.qml @@ -1,5 +1,5 @@ // -// outlinePage.qml +// highlightPage.qml // developer/utilities/render // // Olivier Prat, created on 08/08/2017. @@ -17,8 +17,8 @@ import "qrc:///qml/controls-uit" as HifiControls Rectangle { id: root - property var outlineIndex: 0 - property var drawConfig: Render.getConfig("RenderMainView.OutlineEffect"+outlineIndex) + property var highlightIndex: 0 + property var drawConfig: Render.getConfig("RenderMainView.HighlightEffect"+highlightIndex) HifiConstants { id: hifi;} anchors.margins: hifi.dimensions.contentMargin.x diff --git a/scripts/developer/utilities/render/highlightPage/qmldir b/scripts/developer/utilities/render/highlightPage/qmldir new file mode 100644 index 0000000000..bb3de24b84 --- /dev/null +++ b/scripts/developer/utilities/render/highlightPage/qmldir @@ -0,0 +1 @@ +HighlightPage 1.0 HighlightPage.qml \ No newline at end of file diff --git a/scripts/developer/utilities/render/outlinePage/qmldir b/scripts/developer/utilities/render/outlinePage/qmldir deleted file mode 100644 index 56f5d45414..0000000000 --- a/scripts/developer/utilities/render/outlinePage/qmldir +++ /dev/null @@ -1 +0,0 @@ -OutlinePage 1.0 OutlinePage.qml \ No newline at end of file From 9817cb4c44e4f47b777fdd0368c1893e5623f554 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 15:35:43 +0100 Subject: [PATCH 069/171] Added highlight configuration in HighlightStageSetup job --- .../ui/overlays/ContextOverlayInterface.cpp | 2 +- .../render-utils/src/HighlightEffect.cpp | 5 +- .../render/src/render/HighlightStage.cpp | 97 +++++++++++++- libraries/render/src/render/HighlightStage.h | 60 ++++++++- .../developer/utilities/render/highlight.qml | 123 ++++++++++++++++-- 5 files changed, 262 insertions(+), 25 deletions(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 6a21221a8b..d40c0972e9 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -72,7 +72,7 @@ ContextOverlayInterface::ContextOverlayInterface() { render::Transaction transaction; initializeSelectionToSceneHandler(_selectionToSceneHandlers[0], "contextOverlayHighlightList", transaction); for (auto i = 1; i < MAX_SELECTION_COUNT; i++) { - auto selectionName = QString("contextOverlayHighlightList") + QString::number(i); + auto selectionName = QString("highlightList") + QString::number(i); initializeSelectionToSceneHandler(_selectionToSceneHandlers[i], selectionName, transaction); } const render::ScenePointer& scene = qApp->getMain3DScene(); diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index e332be53de..c938567425 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -434,9 +434,10 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext for (auto i = 0; i < HighlightSharedParameters::MAX_HIGHLIGHT_COUNT; i++) { std::ostringstream stream; - stream << "contextOverlayHighlightList"; if (i > 0) { - stream << i; + stream << "highlightList" << i; + } else { + stream << "contextOverlayHighlightList"; } auto selectionName = stream.str(); auto highlightId = highlightStage->getHighlightIdBySelection(selectionName); diff --git a/libraries/render/src/render/HighlightStage.cpp b/libraries/render/src/render/HighlightStage.cpp index effb7c7e98..6821504649 100644 --- a/libraries/render/src/render/HighlightStage.cpp +++ b/libraries/render/src/render/HighlightStage.cpp @@ -34,13 +34,96 @@ Index HighlightStage::getHighlightIdBySelection(const std::string& selectionName return INVALID_INDEX; } -HighlightStageSetup::HighlightStageSetup() { -} - -void HighlightStageSetup::run(const render::RenderContextPointer& renderContext) { - if (!renderContext->_scene->getStage(HighlightStage::getName())) { - auto stage = std::make_shared(); - renderContext->_scene->resetStage(HighlightStage::getName(), stage); +const HighlightStyle& HighlightStageConfig::getStyle() const { + auto styleIterator = _styles.find(_selectionName); + if (styleIterator != _styles.end()) { + return styleIterator->second; + } else { + auto insertion = _styles.insert(SelectionStyles::value_type{ _selectionName, HighlightStyle{} }); + return insertion.first->second; + } +} + +HighlightStyle& HighlightStageConfig::editStyle() { + auto styleIterator = _styles.find(_selectionName); + if (styleIterator != _styles.end()) { + return styleIterator->second; + } else { + auto insertion = _styles.insert(SelectionStyles::value_type{ _selectionName, HighlightStyle{} }); + return insertion.first->second; + } +} + +void HighlightStageConfig::setSelectionName(const QString& name) { + _selectionName = name.toStdString(); + emit dirty(); +} + +void HighlightStageConfig::setOutlineSmooth(bool isSmooth) { + editStyle().isOutlineSmooth = isSmooth; + emit dirty(); +} + +void HighlightStageConfig::setColorRed(float value) { + editStyle().color.r = value; + emit dirty(); +} + +void HighlightStageConfig::setColorGreen(float value) { + editStyle().color.g = value; + emit dirty(); +} + +void HighlightStageConfig::setColorBlue(float value) { + editStyle().color.b = value; + emit dirty(); +} + +void HighlightStageConfig::setOutlineWidth(float value) { + editStyle().outlineWidth = value; + emit dirty(); +} + +void HighlightStageConfig::setOutlineIntensity(float value) { + editStyle().outlineIntensity = value; + emit dirty(); +} + +void HighlightStageConfig::setUnoccludedFillOpacity(float value) { + editStyle().unoccludedFillOpacity = value; + emit dirty(); +} + +void HighlightStageConfig::setOccludedFillOpacity(float value) { + editStyle().occludedFillOpacity = value; + emit dirty(); +} + +HighlightStageSetup::HighlightStageSetup() { +} + +void HighlightStageSetup::configure(const Config& config) { + // Copy the styles here but update the stage with the new styles in run to be sure everything is + // thread safe... + _styles = config._styles; +} + +void HighlightStageSetup::run(const render::RenderContextPointer& renderContext) { + auto stage = renderContext->_scene->getStage(HighlightStage::getName()); + if (!stage) { + stage = std::make_shared(); + renderContext->_scene->resetStage(HighlightStage::getName(), stage); + } + + if (!_styles.empty()) { + render::Transaction transaction; + for (const auto& selection : _styles) { + auto& selectionName = selection.first; + auto& selectionStyle = selection.second; + transaction.resetSelectionHighlight(selectionName, selectionStyle); + } + renderContext->_scene->enqueueTransaction(transaction); + _styles.clear(); } } diff --git a/libraries/render/src/render/HighlightStage.h b/libraries/render/src/render/HighlightStage.h index a2c123580c..7600f1f724 100644 --- a/libraries/render/src/render/HighlightStage.h +++ b/libraries/render/src/render/HighlightStage.h @@ -63,14 +63,72 @@ namespace render { }; using HighlightStagePointer = std::shared_ptr; + class HighlightStageConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(QString selectionName READ getSelectionName WRITE setSelectionName NOTIFY dirty) + Q_PROPERTY(bool isOutlineSmooth READ isOutlineSmooth WRITE setOutlineSmooth NOTIFY dirty) + Q_PROPERTY(float colorR READ getColorRed WRITE setColorRed NOTIFY dirty) + Q_PROPERTY(float colorG READ getColorGreen WRITE setColorGreen NOTIFY dirty) + Q_PROPERTY(float colorB READ getColorBlue WRITE setColorBlue NOTIFY dirty) + Q_PROPERTY(float outlineWidth READ getOutlineWidth WRITE setOutlineWidth NOTIFY dirty) + Q_PROPERTY(float outlineIntensity READ getOutlineIntensity WRITE setOutlineIntensity NOTIFY dirty) + Q_PROPERTY(float unoccludedFillOpacity READ getUnoccludedFillOpacity WRITE setUnoccludedFillOpacity NOTIFY dirty) + Q_PROPERTY(float occludedFillOpacity READ getOccludedFillOpacity WRITE setOccludedFillOpacity NOTIFY dirty) + + public: + + using SelectionStyles = std::map; + + QString getSelectionName() const { return QString(_selectionName.c_str()); } + void setSelectionName(const QString& name); + + bool isOutlineSmooth() const { return getStyle().isOutlineSmooth; } + void setOutlineSmooth(bool isSmooth); + + float getColorRed() const { return getStyle().color.r; } + void setColorRed(float value); + + float getColorGreen() const { return getStyle().color.g; } + void setColorGreen(float value); + + float getColorBlue() const { return getStyle().color.b; } + void setColorBlue(float value); + + float getOutlineWidth() const { return getStyle().outlineWidth; } + void setOutlineWidth(float value); + + float getOutlineIntensity() const { return getStyle().outlineIntensity; } + void setOutlineIntensity(float value); + + float getUnoccludedFillOpacity() const { return getStyle().unoccludedFillOpacity; } + void setUnoccludedFillOpacity(float value); + + float getOccludedFillOpacity() const { return getStyle().occludedFillOpacity; } + void setOccludedFillOpacity(float value); + + std::string _selectionName{ "contextOverlayHighlightList" }; + mutable SelectionStyles _styles; + + const HighlightStyle& getStyle() const; + HighlightStyle& editStyle(); + + signals: + void dirty(); + }; + class HighlightStageSetup { public: - using JobModel = render::Job::Model; + using Config = HighlightStageConfig; + using JobModel = render::Job::Model; HighlightStageSetup(); + + void configure(const Config& config); void run(const RenderContextPointer& renderContext); protected: + + HighlightStageConfig::SelectionStyles _styles; }; } diff --git a/scripts/developer/utilities/render/highlight.qml b/scripts/developer/utilities/render/highlight.qml index eb2c66b275..6be74fcf40 100644 --- a/scripts/developer/utilities/render/highlight.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -11,9 +11,10 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "highlightPage" + import "qrc:///qml/styles-uit" import "qrc:///qml/controls-uit" as HifiControls +import "configSlider" Rectangle { id: root @@ -22,10 +23,13 @@ Rectangle { anchors.margins: hifi.dimensions.contentMargin.x property var debugConfig: Render.getConfig("RenderMainView.HighlightDebug") + property var highlightConfig: Render.getConfig("UpdateScene.HighlightStageSetup") + signal sendToScript(var message); Column { - spacing: 5 + id: col + spacing: 10 anchors.left: parent.left anchors.right: parent.right anchors.margins: hifi.dimensions.contentMargin.x @@ -59,21 +63,112 @@ Rectangle { } } - TabView { - id: tabs - width: 384 - height: 400 + HifiControls.ComboBox { + id: box + width: 350 + z: 999 + editable: true + colorScheme: hifi.colorSchemes.dark + model: [ + "contextOverlayHighlightList", + "highlightList1", + "highlightList2", + "highlightList3", + "highlightList4"] + label: "" - onCurrentIndexChanged: { - sendToScript("highlight "+currentIndex) + Timer { + id: postpone + interval: 100; running: false; repeat: false + onTriggered: { paramWidgetLoader.sourceComponent = paramWidgets } } + onCurrentIndexChanged: { + root.highlightConfig["selectionName"] = model[currentIndex]; + sendToScript("highlight "+currentIndex) + // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component + // by setting the loader source to Null and then recreate it 100ms later + paramWidgetLoader.sourceComponent = undefined; + postpone.interval = 100 + postpone.start() + } + } - Repeater { - model: [ 0, 1, 2, 3 ] - Tab { - title: "Outl."+modelData - HighlightPage { - highlightIndex: modelData + Loader { + id: paramWidgetLoader + sourceComponent: paramWidgets + width: 350 + } + + Component { + id: paramWidgets + + Column { + spacing: 10 + anchors.margins: hifi.dimensions.contentMargin.x + + HifiControls.Label { + text: "Outline" + } + Column { + spacing: 10 + anchors.left: parent.left + anchors.right: parent.right + HifiControls.CheckBox { + text: "Smooth" + checked: root.highlightConfig["isOutlineSmooth"] + onCheckedChanged: { + root.highlightConfig["isOutlineSmooth"] = checked; + } + } + Repeater { + model: ["Width:outlineWidth:5.0:0.0", + "Intensity:outlineIntensity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.highlightConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + } + } + } + + Separator {} + HifiControls.Label { + text: "Color" + } + Repeater { + model: ["Red:colorR:1.0:0.0", + "Green:colorG:1.0:0.0", + "Blue:colorB:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.highlightConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] + } + } + + Separator {} + HifiControls.Label { + text: "Fill Opacity" + } + Repeater { + model: ["Unoccluded:unoccludedFillOpacity:1.0:0.0", + "Occluded:occludedFillOpacity:1.0:0.0" + ] + ConfigSlider { + label: qsTr(modelData.split(":")[0]) + integral: false + config: root.highlightConfig + property: modelData.split(":")[1] + max: modelData.split(":")[2] + min: modelData.split(":")[3] } } } From 25b2a2ff5ee070cb90c4a94b5276fbdf341ddb4b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 16:57:33 +0100 Subject: [PATCH 070/171] Bounds buffer is now per instance to fix a bug --- libraries/render-utils/src/OutlineEffect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.h b/libraries/render-utils/src/OutlineEffect.h index a2bfc88c81..50c30db728 100644 --- a/libraries/render-utils/src/OutlineEffect.h +++ b/libraries/render-utils/src/OutlineEffect.h @@ -86,8 +86,8 @@ protected: unsigned int _outlineIndex; render::ShapePlumberPointer _shapePlumber; OutlineSharedParametersPointer _sharedParameters; + gpu::BufferPointer _boundsBuffer; - static gpu::BufferPointer _boundsBuffer; static gpu::PipelinePointer _stencilMaskPipeline; static gpu::PipelinePointer _stencilMaskFillPipeline; }; From fe79730012da39e024b86af80cb60dc5fc462593 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 16:58:04 +0100 Subject: [PATCH 071/171] Bounds buffer is now per instance to fix a bug --- libraries/render-utils/src/OutlineEffect.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/render-utils/src/OutlineEffect.cpp b/libraries/render-utils/src/OutlineEffect.cpp index a42cbfe358..4d2682cebd 100644 --- a/libraries/render-utils/src/OutlineEffect.cpp +++ b/libraries/render-utils/src/OutlineEffect.cpp @@ -99,7 +99,6 @@ void PrepareDrawOutline::run(const render::RenderContextPointer& renderContext, gpu::PipelinePointer DrawOutlineMask::_stencilMaskPipeline; gpu::PipelinePointer DrawOutlineMask::_stencilMaskFillPipeline; -gpu::BufferPointer DrawOutlineMask::_boundsBuffer; DrawOutlineMask::DrawOutlineMask(unsigned int outlineIndex, render::ShapePlumberPointer shapePlumber, OutlineSharedParametersPointer parameters) : From ffa46b487a898db3eac17a436fab8f744cd38eb0 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 17:07:37 +0100 Subject: [PATCH 072/171] Only non empty selections are now linked to highlight passes --- .../render-utils/src/HighlightEffect.cpp | 36 ++++++++++--------- libraries/render-utils/src/HighlightEffect.h | 16 ++++----- libraries/render/src/render/Scene.cpp | 13 ++++++- libraries/render/src/render/Scene.h | 4 +++ 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index c938567425..98a8835409 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -104,11 +104,10 @@ void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline; gpu::PipelinePointer DrawHighlightMask::_stencilMaskFillPipeline; -gpu::BufferPointer DrawHighlightMask::_boundsBuffer; DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex, render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters) : - _highlightIndex{ highlightIndex }, + _highlightPassIndex{ highlightIndex }, _shapePlumber { shapePlumber }, _sharedParameters{ parameters } { } @@ -147,7 +146,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c } auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); - auto highlightId = _sharedParameters->_highlightIds[_highlightIndex]; + auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex]; if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) { auto ressources = inputs.get1(); @@ -221,8 +220,8 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c // Draw stencil mask with object bounding boxes const auto highlightWidthLoc = _stencilMaskPipeline->getProgram()->getUniforms().findLocation("outlineWidth"); - const auto sqrt3 = 1.74f; - const float blurPixelWidth = 2.0f * sqrt3 * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w); + const auto securityMargin = 2.0f; + const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w); const auto framebufferSize = ressources->getSourceFrameSize(); auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline; @@ -242,7 +241,7 @@ gpu::PipelinePointer DrawHighlight::_pipeline; gpu::PipelinePointer DrawHighlight::_pipelineFilled; DrawHighlight::DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters) : - _highlightIndex{ highlightIndex }, + _highlightPassIndex{ highlightIndex }, _sharedParameters{ parameters } { } @@ -261,9 +260,9 @@ void DrawHighlight::run(const render::RenderContextPointer& renderContext, const auto args = renderContext->args; auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); - auto highlightId = _sharedParameters->_highlightIds[_highlightIndex]; + auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex]; if (!render::HighlightStage::isIndexInvalid(highlightId)) { - auto& highlight = highlightStage->getHighlight(_sharedParameters->_highlightIds[_highlightIndex]); + auto& highlight = highlightStage->getHighlight(highlightId); auto pipeline = getPipeline(highlight._style); { auto& shaderParameters = _configuration.edit(); @@ -427,12 +426,13 @@ const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() { } void SelectionToHighlight::run(const render::RenderContextPointer& renderContext, Outputs& outputs) { - auto highlightStage = renderContext->_scene->getStage(render::HighlightStage::getName()); + auto scene = renderContext->_scene; + auto highlightStage = scene->getStage(render::HighlightStage::getName()); outputs.clear(); _sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX); - for (auto i = 0; i < HighlightSharedParameters::MAX_HIGHLIGHT_COUNT; i++) { + for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) { std::ostringstream stream; if (i > 0) { stream << "highlightList" << i; @@ -440,17 +440,19 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext stream << "contextOverlayHighlightList"; } auto selectionName = stream.str(); - auto highlightId = highlightStage->getHighlightIdBySelection(selectionName); - if (!render::HighlightStage::isIndexInvalid(highlightId)) { - _sharedParameters->_highlightIds[outputs.size()] = highlightId; - outputs.emplace_back(selectionName); + if (!scene->isSelectionEmpty(selectionName)) { + auto highlightId = highlightStage->getHighlightIdBySelection(selectionName); + if (!render::HighlightStage::isIndexInvalid(highlightId)) { + _sharedParameters->_highlightIds[outputs.size()] = highlightId; + outputs.emplace_back(selectionName); + } } } } void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - if (_highlightIndex < inputs.size()) { - outputs = inputs[_highlightIndex]; + if (_highlightPassIndex < inputs.size()) { + outputs = inputs[_highlightPassIndex]; } else { outputs.clear(); } @@ -487,7 +489,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto highlightRessources = task.addJob("PrepareHighlight", primaryFramebuffer); render::Varying highlight0Rect; - for (auto i = 0; i < HighlightSharedParameters::MAX_HIGHLIGHT_COUNT; i++) { + for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) { const auto selectionName = task.addJob("ExtractSelectionName", highlightSelectionNames, i); const auto groupItems = addSelectItemJobs(task, selectionName, items); const auto highlightedItemIDs = task.addJob("HighlightMetaToSubItemIDs", groupItems); diff --git a/libraries/render-utils/src/HighlightEffect.h b/libraries/render-utils/src/HighlightEffect.h index 0531c03efd..90a8e730ce 100644 --- a/libraries/render-utils/src/HighlightEffect.h +++ b/libraries/render-utils/src/HighlightEffect.h @@ -50,12 +50,12 @@ class HighlightSharedParameters { public: enum { - MAX_HIGHLIGHT_COUNT = 8 + MAX_PASS_COUNT = 8 }; HighlightSharedParameters(); - std::array _highlightIds; + std::array _highlightIds; static float getBlurPixelWidth(const render::HighlightStyle& style, int frameBufferHeight); }; @@ -100,13 +100,13 @@ public: using Outputs = std::string; using JobModel = render::Job::ModelIO; - ExtractSelectionName(unsigned int highlightIndex) : _highlightIndex{ highlightIndex } {} + ExtractSelectionName(unsigned int highlightIndex) : _highlightPassIndex{ highlightIndex } {} void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); private: - unsigned int _highlightIndex; + unsigned int _highlightPassIndex; }; @@ -123,11 +123,11 @@ public: protected: - unsigned int _highlightIndex; + unsigned int _highlightPassIndex; render::ShapePlumberPointer _shapePlumber; HighlightSharedParametersPointer _sharedParameters; - - static gpu::BufferPointer _boundsBuffer; + gpu::BufferPointer _boundsBuffer; + static gpu::PipelinePointer _stencilMaskPipeline; static gpu::PipelinePointer _stencilMaskFillPipeline; }; @@ -162,7 +162,7 @@ private: static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipelineFilled; - unsigned int _highlightIndex; + unsigned int _highlightPassIndex; HighlightParameters _parameters; HighlightSharedParametersPointer _sharedParameters; HighlightConfigurationBuffer _configuration; diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 9cdaa89cf6..88e25b6d27 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -426,7 +426,7 @@ void Scene::resetItemTransition(ItemID itemId) { } } -// THis fucntion is thread safe +// This function is thread safe Selection Scene::getSelection(const Selection::Name& name) const { std::unique_lock lock(_selectionsMutex); auto found = _selections.find(name); @@ -437,6 +437,17 @@ Selection Scene::getSelection(const Selection::Name& name) const { } } +// This function is thread safe +bool Scene::isSelectionEmpty(const Selection::Name& name) const { + std::unique_lock lock(_selectionsMutex); + auto found = _selections.find(name); + if (found == _selections.end()) { + return false; + } else { + return (*found).second.isEmpty(); + } +} + void Scene::resetSelections(const Transaction::SelectionResets& transactions) { for (auto selection : transactions) { auto found = _selections.find(selection.getName()); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 4bf38b89cc..af6204acb4 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -143,6 +143,10 @@ public: // Thread safe Selection getSelection(const Selection::Name& name) const; + // Check if a particular selection is empty (returns true if doesn't exist) + // Thread safe + bool isSelectionEmpty(const Selection::Name& name) const; + // This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues // Access a particular item form its ID From 0bbd1edc0aff10cb275c11bfae23c211dcf9603f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 7 Nov 2017 18:26:15 +0100 Subject: [PATCH 073/171] Fixed fluttering highlight bug by attaching only stencil when drawing outline --- libraries/gpu/src/gpu/Framebuffer.cpp | 63 +++++++++++++++---- libraries/gpu/src/gpu/Framebuffer.h | 3 + .../render-utils/src/HighlightEffect.cpp | 2 +- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index f1257e7c83..4fcc9ab0f9 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -220,7 +220,7 @@ uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const { } } -bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { +bool Framebuffer::assignDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { if (isSwapchain()) { return false; } @@ -244,20 +244,59 @@ bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const For // assign the new one _depthStencilBuffer = TextureView(texture, subresource, format); - _bufferMask = ( _bufferMask & ~BUFFER_DEPTHSTENCIL); - if (texture) { - if (format.getSemantic() == gpu::DEPTH) { - _bufferMask |= BUFFER_DEPTH; - } else if (format.getSemantic() == gpu::STENCIL) { - _bufferMask |= BUFFER_STENCIL; - } else if (format.getSemantic() == gpu::DEPTH_STENCIL) { - _bufferMask |= BUFFER_DEPTHSTENCIL; - } - } - return true; } +bool Framebuffer::setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { + if (assignDepthStencilBuffer(texture, format, subresource)) { + _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL); + if (texture) { + if (format.getSemantic() == gpu::DEPTH || format.getSemantic() == gpu::DEPTH_STENCIL) { + _bufferMask |= BUFFER_DEPTH; + } else { + return false; + } + } + + return true; + } + return false; +} + +bool Framebuffer::setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { + if (assignDepthStencilBuffer(texture, format, subresource)) { + _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL); + if (texture) { + if (format.getSemantic() == gpu::STENCIL || format.getSemantic() == gpu::DEPTH_STENCIL) { + _bufferMask |= BUFFER_STENCIL; + } else { + return false; + } + } + + return true; + } + return false; +} + +bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource) { + if (assignDepthStencilBuffer(texture, format, subresource)) { + _bufferMask = (_bufferMask & ~BUFFER_DEPTHSTENCIL); + if (texture) { + if (format.getSemantic() == gpu::DEPTH) { + _bufferMask |= BUFFER_DEPTH; + } else if (format.getSemantic() == gpu::STENCIL) { + _bufferMask |= BUFFER_STENCIL; + } else if (format.getSemantic() == gpu::DEPTH_STENCIL) { + _bufferMask |= BUFFER_DEPTHSTENCIL; + } + } + + return true; + } + return false; +} + TexturePointer Framebuffer::getDepthStencilBuffer() const { if (isSwapchain()) { return TexturePointer(); diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index b3a500d68f..b3cf0fbba3 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -107,6 +107,8 @@ public: TexturePointer getRenderBuffer(uint32 slot) const; uint32 getRenderBufferSubresource(uint32 slot) const; + bool setDepthBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0); + bool setStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0); bool setDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource = 0); TexturePointer getDepthStencilBuffer() const; uint32 getDepthStencilBufferSubresource() const; @@ -168,6 +170,7 @@ protected: uint16 _numSamples = 0; void updateSize(const TexturePointer& texture); + bool assignDepthStencilBuffer(const TexturePointer& texture, const Format& format, uint32 subresource); // Non exposed Framebuffer(const Framebuffer& framebuffer) = delete; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 98a8835409..7c58e5ba66 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -59,7 +59,7 @@ void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuff void HighlightRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil")); _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); - _colorFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); + _colorFrameBuffer->setStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); } void HighlightRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { From f248eb5518daf79a1671ee1c1890abb0d56550e0 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 7 Nov 2017 11:30:09 -0800 Subject: [PATCH 074/171] Change wallet home when 0 transactions --- .../qml/hifi/commerce/wallet/WalletHome.qml | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 1fe0dcc58b..ff89f01943 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -196,7 +196,52 @@ Item { anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right; - anchors.rightMargin: 24; + + Item { + visible: transactionHistoryModel.count === 0 && root.historyReceived; + anchors.centerIn: parent; + width: parent.width - 12; + height: parent.height; + + HifiControlsUit.Separator { + colorScheme: 1; + anchors.left: parent.left; + anchors.right: parent.right; + anchors.top: parent.top; + } + + RalewayRegular { + id: noActivityText; + text: "No activity yet.


Looking for a little spending money?
Click the button below to apply for your free HFC!"; + // Text size + size: 24; + // Style + color: hifi.colors.blueAccent; + anchors.top: parent.top; + anchors.topMargin: 26; + anchors.left: parent.left; + anchors.right: parent.right; + height: paintedHeight; + wrapMode: Text.WordWrap; + horizontalAlignment: Text.AlignHCenter; + } + + // "Apply" button + HifiControlsUit.Button { + id: changePassphraseButton; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.top: noActivityText.bottom; + anchors.topMargin: 25; + anchors.horizontalCenter: parent.horizontalCenter; + width: 180; + height: 40; + text: "Apply Now"; + onClicked: { + Qt.openUrlExternally("https://www.highfidelity.com/"); + } + } + } ListView { id: transactionHistory; @@ -294,17 +339,6 @@ Item { } } } - - // This should never be visible (since you immediately get 100 HFC) - FiraSansRegular { - id: emptyTransationHistory; - size: 24; - visible: !transactionHistory.visible && root.historyReceived; - text: "Recent Activity Unavailable"; - anchors.fill: parent; - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } } } @@ -350,7 +384,9 @@ Item { } root.pendingCount = pendingCount; - transactionHistoryModel.insert(0, {"transaction_type": "pendingCount"}); + if (pendingCount > 0) { + transactionHistoryModel.insert(0, {"transaction_type": "pendingCount"}); + } } // From 8f54c106f6411ad8cfe624fdf3a32ac72fbb0e5f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 7 Nov 2017 12:12:27 -0800 Subject: [PATCH 075/171] Could it be this simple? --- interface/src/commerce/Ledger.cpp | 9 +++++++++ interface/src/commerce/Wallet.cpp | 16 ++++++++++++---- interface/src/commerce/Wallet.h | 5 +++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index f607c923ee..ed862384dc 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -90,6 +90,15 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure); } +void Ledger::receiveAtSuccess(QNetworkReply& reply) { + auto wallet = DependencyManager::get(); + QByteArray response = reply.readAll(); + QJsonObject data = QJsonDocument::fromJson(response).object(); + + if (data["status"] == "fail") { // Not on "The List" for receiving HFC + wallet->setMustRegenerateKeypair(true); + } +} bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 9bc8dc9e43..b746b58015 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -327,6 +327,12 @@ Wallet::Wallet() { auto walletScriptingInterface = DependencyManager::get(); uint status; + if (_mustRegenerateKeypair) { + _mustRegenerateKeypair = false; + resetKeysOnly(); + generateKeyPair(); + } + if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP; } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { @@ -661,9 +667,13 @@ QString Wallet::getKeyFilePath() { } } -void Wallet::reset() { +void Wallet::resetKeysOnly() { _publicKeys.clear(); + QFile keyFile(keyFilePath()); + keyFile.remove(); +} +void Wallet::reset() { delete _securityImage; _securityImage = nullptr; @@ -671,9 +681,7 @@ void Wallet::reset() { updateImageProvider(); _passphrase->clear(); - - QFile keyFile(keyFilePath()); - keyFile.remove(); + resetKeysOnly(); } bool Wallet::writeWallet(const QString& newPassphrase) { RSA* keys = readKeys(keyFilePath().toStdString().c_str()); diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index ed145df451..f0f13aaf6e 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -49,6 +49,7 @@ public: bool walletIsAuthenticatedWithPassphrase(); bool changePassphrase(const QString& newPassphrase); + void resetKeysOnly(); void reset(); void getWalletStatus(); @@ -59,6 +60,8 @@ public: WALLET_STATUS_READY }; + void setMustRegenerateKeypair(const bool& val) { _mustRegenerateKeypair = val; } + signals: void securityImageResult(bool exists); void keyFilePathIfExistsResult(const QString& path); @@ -83,6 +86,8 @@ private: bool writeBackupInstructions(); void account(); + + bool _mustRegenerateKeypair { false }; }; #endif // hifi_Wallet_h From 332cb48a41e0db4eaed996b0ab0a73162bc008ee Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 7 Nov 2017 16:57:55 -0700 Subject: [PATCH 076/171] Lasers and teleport scale with avatar --- interface/src/raypick/LaserPointer.cpp | 16 +++++++++++++--- interface/src/raypick/LaserPointer.h | 3 ++- interface/src/raypick/LaserPointerManager.cpp | 4 ++-- interface/src/raypick/LaserPointerManager.h | 2 +- .../raypick/LaserPointerScriptingInterface.cpp | 9 +++++++-- interface/src/ui/overlays/Line3DOverlay.cpp | 10 +++++++++- interface/src/ui/overlays/Line3DOverlay.h | 3 +++ libraries/render-utils/src/GeometryCache.cpp | 5 +++-- libraries/render-utils/src/GeometryCache.h | 6 +++--- libraries/render-utils/src/glowLine.slf | 5 +++-- libraries/render-utils/src/glowLine.slv | 3 +++ .../controllerModules/farActionGrabEntity.js | 1 + .../controllers/controllerModules/farTrigger.js | 1 + .../controllers/controllerModules/inEditMode.js | 1 + .../controllerModules/overlayLaserInput.js | 1 + .../controllers/controllerModules/teleport.js | 4 ++++ .../controllerModules/webEntityLaserInput.js | 2 +- .../marketplace/shapes/modules/laser.js | 1 + 18 files changed, 59 insertions(+), 18 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 75b43a251b..50479a77dd 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -7,7 +7,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// +//// #include "LaserPointer.h" #include "Application.h" @@ -15,7 +15,7 @@ #include "RayPickScriptingInterface.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) : + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), @@ -23,6 +23,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende _centerEndY(centerEndY), _lockEnd(lockEnd), _distanceScaleEnd(distanceScaleEnd), + _scaleWithAvatar(scaleWithAvatar), _rayPickUID(DependencyManager::get()->createRayPick(rayProps)) { @@ -151,6 +152,9 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } } } + + float avatarScale = DependencyManager::get()->getMyAvatar()->getAvatarScale(); + QVariant end = vec3toVariant(endVec); if (!renderState.getPathID().isNull()) { QVariantMap pathProps; @@ -158,6 +162,11 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter pathProps.insert("end", end); pathProps.insert("visible", true); pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays()); + if (_scaleWithAvatar) { + auto glowScaleProp = qApp->getOverlays().getProperty(renderState.getPathID(), "glowScale").value; + float glowScale = glowScaleProp.isValid() ? avatarScale * glowScaleProp.toFloat() : avatarScale; + pathProps.insert("glowScale", glowScale); + } qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps); } if (!renderState.getEndID().isNull()) { @@ -165,7 +174,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter glm::quat faceAvatarRotation = DependencyManager::get()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))); glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); if (_distanceScaleEnd) { - dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); + dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec); endProps.insert("dimensions", vec3toVariant(dim)); } if (_centerEndY) { @@ -211,6 +220,7 @@ void LaserPointer::update() { if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; + qDebug() << &_currentRenderState; updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index f2350c7199..592ba978df 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -60,7 +60,7 @@ public: typedef std::unordered_map> DefaultRenderStateMap; LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled); ~LaserPointer(); QUuid getRayUID() { return _rayPickUID; } @@ -91,6 +91,7 @@ private: bool _centerEndY; bool _lockEnd; bool _distanceScaleEnd; + bool _scaleWithAvatar; std::pair _objectLockEnd { std::pair(QUuid(), false)}; const QUuid _rayPickUID; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 9d58cc2587..868491f166 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -11,9 +11,9 @@ #include "LaserPointerManager.h" QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) { + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) { QUuid result; - std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled); + std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled); if (!laserPointer->getRayUID().isNull()) { result = QUuid::createUuid(); withWriteLock([&] { _laserPointers[result] = laserPointer; }); diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index e302318483..9283b7ac89 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -25,7 +25,7 @@ class LaserPointerManager : protected ReadWriteLockable { public: QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled); void removeLaserPointer(const QUuid& uid); void enableLaserPointer(const QUuid& uid) const; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index e8d28bfab2..a47605fa1f 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -7,7 +7,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// +//// #include "LaserPointerScriptingInterface.h" @@ -51,6 +51,11 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert enabled = propertyMap["enabled"].toBool(); } + bool scaleWithAvatar = false; + if (propertyMap["scaleWithAvatar"].isValid()) { + scaleWithAvatar = propertyMap["scaleWithAvatar"].toBool(); + } + LaserPointer::RenderStateMap renderStates; if (propertyMap["renderStates"].isValid()) { QList renderStateVariants = propertyMap["renderStates"].toList(); @@ -80,7 +85,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert } } - return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled); + return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled); } void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index bdb35d4f49..7ac79f081a 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "AbstractViewStateInterface.h" @@ -35,6 +36,7 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : _endParentJointIndex = line3DOverlay->getEndJointIndex(); _glow = line3DOverlay->getGlow(); _glowWidth = line3DOverlay->getGlowWidth(); + _glowScale = line3DOverlay->getGlowScale(); } Line3DOverlay::~Line3DOverlay() { @@ -145,7 +147,7 @@ void Line3DOverlay::render(RenderArgs* args) { geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID); } else { // renderGlowLine handles both glow = 0 and glow > 0 cases - geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _geometryCacheID); + geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _glowScale, _geometryCacheID); } } } @@ -244,6 +246,12 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) { setGlowWidth(glowWidth.toFloat()); } + auto glowScale = properties["glowScale"]; + if (glowScale.isValid()) { + float gscale = glowScale.toFloat(); + setGlowScale(gscale); + } + } QVariant Line3DOverlay::getProperty(const QString& property) { diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index bcb65b1f1e..250d823598 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -33,6 +33,7 @@ public: glm::vec3 getEnd() const; const float& getGlow() const { return _glow; } const float& getGlowWidth() const { return _glowWidth; } + const float& getGlowScale() const { return _glowScale; } // setters void setStart(const glm::vec3& start); @@ -43,6 +44,7 @@ public: void setGlow(const float& glow) { _glow = glow; } void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; } + void setGlowScale(const float& glowScale) { _glowScale = glowScale; } void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; @@ -72,6 +74,7 @@ private: float _glow { 0.0 }; float _glowWidth { 0.0 }; + float _glowScale{ 1.0 }; int _geometryCacheID; }; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index fa00737e3c..90b3ca402d 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1868,7 +1868,7 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color, float glowIntensity, float glowWidth, int id) { + const glm::vec4& color, float glowIntensity, float glowWidth, float glowScale, int id) { // Disable glow lines on OSX #ifndef Q_OS_WIN @@ -1931,9 +1931,10 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const vec4 p1; vec4 p2; vec4 color; + float scale; }; - LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color }; + LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color, glowScale }; details.uniformBuffer->resize(sizeof(LineData)); details.uniformBuffer->setSubData(0, lineData); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index cd8c43f1df..862331b743 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -248,7 +248,7 @@ public: renderWireCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - // Dynamic geometry + // //Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); size_t getShapeTriangleCount(Shape shape); @@ -314,10 +314,10 @@ public: const glm::vec4& color1, const glm::vec4& color2, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color, float glowIntensity, float glowWidth, int id); + const glm::vec4& color, float glowIntensity, float glowWidth, float glowScale, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, int id) - { renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, id); } + { renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, 1.0f, id); } void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, int id) { renderDashedLine(batch, start, end, color, 0.05f, 0.025f, id); } diff --git a/libraries/render-utils/src/glowLine.slf b/libraries/render-utils/src/glowLine.slf index 73e14bd319..be1c6842e3 100644 --- a/libraries/render-utils/src/glowLine.slf +++ b/libraries/render-utils/src/glowLine.slf @@ -10,8 +10,9 @@ // in vec4 _color; -in float distanceFromCenter; +in float _scale; +in float distanceFromCenter; out vec4 _fragColor; void main(void) { @@ -21,7 +22,7 @@ void main(void) { float alpha = 1.0 - abs(distanceFromCenter); // Convert from a linear alpha curve to a sharp peaked one - alpha = _color.a * pow(alpha, 10.0); + alpha = _color.a * pow(alpha, 10.0/_scale); // Drop everything where the curve falls off to nearly nothing if (alpha <= 0.05) { diff --git a/libraries/render-utils/src/glowLine.slv b/libraries/render-utils/src/glowLine.slv index fd3a85d254..7b69943b7a 100644 --- a/libraries/render-utils/src/glowLine.slv +++ b/libraries/render-utils/src/glowLine.slv @@ -16,14 +16,17 @@ layout(std140) uniform lineData { vec4 p1; vec4 p2; vec4 color; + float scale; }; out vec4 _color; +out float _scale; // the distance from the center in 'quad space' out float distanceFromCenter; void main(void) { _color = color; + _scale = scale; TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index e34855d521..2ee308ddb4 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -584,6 +584,7 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: renderStates, faceAvatar: true, distanceScaleEnd: true, + scaleWithAvatar: true, defaultRenderStates: defaultRenderStates }); } diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index de60e2e227..ab950cbbdf 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -190,6 +190,7 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: renderStates, faceAvatar: true, distanceScaleEnd: true, + scaleWithAvatar: true, defaultRenderStates: defaultRenderStates }); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index f9ec38d22a..4520a91d74 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -237,6 +237,7 @@ Script.include("/~/system/libraries/utils.js"); posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, faceAvatar: true, + scaleWithAvatar: true, defaultRenderStates: defaultRenderStates }); diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 1c83f38d9b..e87e6e000a 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -371,6 +371,7 @@ Script.include("/~/system/libraries/controllers.js"); posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, faceAvatar: true, + scaleWithAvatar: true, defaultRenderStates: defaultRenderStates }); diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 0364e4f9b4..c4fbe781b9 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -153,6 +153,7 @@ Script.include("/~/system/libraries/controllers.js"); joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", filter: RayPick.PICK_ENTITIES, faceAvatar: true, + scaleWithAvatar: true, centerEndY: false, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates @@ -161,6 +162,7 @@ Script.include("/~/system/libraries/controllers.js"); joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, faceAvatar: true, + scaleWithAvatar: true, centerEndY: false, renderStates: teleportRenderStates }); @@ -168,6 +170,7 @@ Script.include("/~/system/libraries/controllers.js"); joint: "Avatar", filter: RayPick.PICK_ENTITIES, faceAvatar: true, + scaleWithAvatar: true, centerEndY: false, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates @@ -176,6 +179,7 @@ Script.include("/~/system/libraries/controllers.js"); joint: "Avatar", filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, faceAvatar: true, + scaleWithAvatar: true, centerEndY: false, renderStates: teleportRenderStates }); diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 39969df614..eafe7c3462 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -88,7 +88,6 @@ Script.include("/~/system/libraries/controllers.js"); {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} ]; - // triggered when stylus presses a web overlay/entity var HAPTIC_STYLUS_STRENGTH = 1.0; var HAPTIC_STYLUS_DURATION = 20.0; @@ -452,6 +451,7 @@ Script.include("/~/system/libraries/controllers.js"); posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, faceAvatar: true, + scaleWithAvatar: true, defaultRenderStates: defaultRenderStates }); } diff --git a/unpublishedScripts/marketplace/shapes/modules/laser.js b/unpublishedScripts/marketplace/shapes/modules/laser.js index 1efc38b65a..beefa8a2f4 100644 --- a/unpublishedScripts/marketplace/shapes/modules/laser.js +++ b/unpublishedScripts/marketplace/shapes/modules/laser.js @@ -150,6 +150,7 @@ Laser = function (side) { } function update(hand) { + return; var handPosition, handOrientation, deltaOrigin, From e37010565fd77ff0e4778d5c44d3d70831abe467 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 7 Nov 2017 16:55:07 -0800 Subject: [PATCH 077/171] changed fileDialog return value to be compatible with musvis --- interface/src/Application.cpp | 4 ---- libraries/ui/src/OffscreenUi.cpp | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d099af9ea0..0b580ddb5d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2702,7 +2702,6 @@ bool Application::importFromZIP(const QString& filePath) { return true; } -<<<<<<< HEAD bool Application::importFromFBX(const QString& filePath) { qDebug() << "An fbx file has been dropped in: " << filePath; QUrl empty; @@ -2715,9 +2714,6 @@ bool Application::importFromFBX(const QString& filePath) { return true; } -======= -// thread-safe ->>>>>>> 85efe5265d1e31eccae22571e407b938030c8f6e void Application::onPresent(quint32 frameCount) { bool expected = false; if (_pendingIdleEvent.compare_exchange_strong(expected, true)) { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 297ed9ca50..96272c4f1f 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -720,7 +720,8 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) { return QString(); } qCDebug(uiLogging) << result.toString(); - return result.toUrl().toLocalFile(); + // originally was result.toUrl().toLocalFile();, but toLocalFile() is not working + return result.toString(); } ModalDialogListener* OffscreenUi::fileDialogAsync(const QVariantMap& properties) { From 9a09ffe12f4f9a3d82990f329aa61048ed5814de Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 7 Nov 2017 17:10:57 -0800 Subject: [PATCH 078/171] removed old fbx code --- interface/src/Application.cpp | 45 +++++++++-------------------------- interface/src/Application.h | 1 - 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b580ddb5d..1ca58311d4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -355,8 +355,7 @@ const QHash Application::_acceptedExtensi { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, - { ZIP_EXTENSION, &Application::importFromZIP }, - { FBX_EXTENSION, &Application::importFromFBX } + { ZIP_EXTENSION, &Application::importFromZIP } }; class DeadlockWatchdogThread : public QThread { @@ -2702,17 +2701,7 @@ bool Application::importFromZIP(const QString& filePath) { return true; } -bool Application::importFromFBX(const QString& filePath) { - qDebug() << "An fbx file has been dropped in: " << filePath; - QUrl empty; - // handle Blocks download from Marketplace - if (filePath.contains("vr.google.com/downloads")) { - addAssetToWorldFromURL(filePath); - } else { - addAssetToWorld(filePath, "", false, false); - } - return true; -} +// thread-safe void Application::onPresent(quint32 frameCount) { bool expected = false; @@ -6250,11 +6239,7 @@ void Application::addAssetToWorldFromURL(QString url) { if (url.contains("vr.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { - if (url.contains(".fbx")) { - filename.remove("?noDownload=false"); - } else { - filename.remove(".zip?noDownload=false"); - } + filename.remove(".zip?noDownload=false"); } else { filename.remove(".zip"); } @@ -6281,7 +6266,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { auto result = request->getResult(); QString filename; - bool isBlocksOBJ = false; + bool isBlocks = false; if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. @@ -6289,15 +6274,11 @@ void Application::addAssetToWorldFromURLRequestFinished() { if (url.contains("vr.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { - if (url.contains(".fbx")) { - filename.remove("?noDownload=false"); - } else { - filename.remove(".zip?noDownload=false"); - } + filename.remove(".zip?noDownload=false"); } else { filename.remove(".zip"); } - isBlocksOBJ = true; + isBlocks = true; } if (result == ResourceRequest::Success) { @@ -6314,11 +6295,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { tempFile.write(request->getData()); addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key. tempFile.close(); - if (url.contains(".fbx")) { - addAssetToWorld(downloadPath, "", false, false); - } else { - qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocksOBJ); - } + qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocks); } else { QString errorInfo = "Couldn't open temporary file for download"; qWarning(interfaceapp) << errorInfo; @@ -6348,7 +6325,7 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) { addAssetToWorldError(filename, "Couldn't unzip file " + filename + "."); } -void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocksOBJ) { +void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, bool isBlocks) { // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString path = filePath; @@ -6357,7 +6334,7 @@ void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip, QString assetFolder = zipFile.section("/", -1); assetFolder.remove(".zip"); mapping = "/" + assetFolder + "/" + filename; - } else if (isBlocksOBJ) { + } else if (isBlocks) { qCDebug(interfaceapp) << "Path to asset folder: " << zipFile; QString assetFolder = zipFile.section('/', -1); assetFolder.remove(".zip?noDownload=false"); @@ -6750,12 +6727,12 @@ void Application::onAssetToWorldMessageBoxClosed() { } -void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocksOBJ) { +void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip, bool isBlocks) { if (autoAdd) { if (!unzipFile.isEmpty()) { for (int i = 0; i < unzipFile.length(); i++) { qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i); - addAssetToWorld(unzipFile.at(i), zipFile, isZip, isBlocksOBJ); + addAssetToWorld(unzipFile.at(i), zipFile, isZip, isBlocks); } } else { addAssetToWorldUnzipFailure(zipFile); diff --git a/interface/src/Application.h b/interface/src/Application.h index 03e256fba7..fbfb3979be 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -472,7 +472,6 @@ private: bool importJSONFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString); bool importFromZIP(const QString& filePath); - bool importFromFBX(const QString& filePath); bool nearbyEntitiesAreReadyForPhysics(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); From 1ceec174052aa7295aa170738c74cb8a3bea34e0 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 7 Nov 2017 17:12:39 -0800 Subject: [PATCH 079/171] missed an fbx block --- interface/src/Application.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1ca58311d4..4f051697ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2702,7 +2702,6 @@ bool Application::importFromZIP(const QString& filePath) { } // thread-safe - void Application::onPresent(quint32 frameCount) { bool expected = false; if (_pendingIdleEvent.compare_exchange_strong(expected, true)) { @@ -6467,13 +6466,6 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { // Close progress message box. addAssetToWorldInfoDone(filenameFromPath(filePath)); } - - // Delete temporary directories created from downloads - if (filePath.contains(".fbx")) { - QString tempPath = filePath.remove(filePath.section("/", -1)); - qCDebug(interfaceapp) << "Removing temporary path: " << tempPath; - QDir(tempPath).removeRecursively(); - } } void Application::addAssetToWorldCheckModelSize() { From ebe5d51ee8164eda2a6b2aca528df10c5b0fc49a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Nov 2017 14:25:10 +1300 Subject: [PATCH 080/171] Label models.json.gz paths in server Content tab with operating system --- domain-server/resources/web/content/index.shtml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/content/index.shtml b/domain-server/resources/web/content/index.shtml index e1ba5499b6..0e48c1eff8 100644 --- a/domain-server/resources/web/content/index.shtml +++ b/domain-server/resources/web/content/index.shtml @@ -19,12 +19,13 @@ Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.
Note: Your domain's content will be replaced by the content you upload, but the backup files of your domain's content will not immediately be changed.

-

- If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:
-

C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
-
/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
-
/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz
-

+

If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:

+ +
C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
+ +
/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
+ +
/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz


From ee3900be4f7104841244222be95af1f9a7f22b04 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 7 Nov 2017 18:26:41 -0700 Subject: [PATCH 081/171] Corrections --- interface/src/raypick/LaserPointer.cpp | 31 ++++++++++++------- interface/src/raypick/LaserPointer.h | 10 +++--- interface/src/raypick/LaserPointerManager.cpp | 4 +-- interface/src/raypick/LaserPointerManager.h | 2 +- .../LaserPointerScriptingInterface.cpp | 2 +- interface/src/ui/overlays/Line3DOverlay.h | 2 +- libraries/render-utils/src/GeometryCache.h | 2 +- .../marketplace/shapes/modules/laser.js | 1 - 8 files changed, 30 insertions(+), 24 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index af09e50cb6..ee0336438c 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -7,7 +7,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -//// +// #include "LaserPointer.h" #include "Application.h" @@ -15,7 +15,7 @@ #include "RayPickScriptingInterface.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), @@ -121,7 +121,8 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter glm::vec3 endVec; if (((defaultState || !_lockEnd) && _lockEndObject.id.isNull()) || type == IntersectionType::HUD) { endVec = pickRay.origin + pickRay.direction * distance; - } else { + } + else { if (!_lockEndObject.id.isNull()) { glm::vec3 pos; glm::quat rot; @@ -132,7 +133,8 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value); dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value); registrationPoint = glm::vec3(0.5f); - } else { + } + else { EntityItemProperties props = DependencyManager::get()->getEntityProperties(_lockEndObject.id); glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition()); glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat; @@ -143,17 +145,20 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); - } else { + } + else { if (type == IntersectionType::ENTITY) { endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; - } else if (type == IntersectionType::OVERLAY) { + } + else if (type == IntersectionType::OVERLAY) { endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); - } else if (type == IntersectionType::AVATAR) { + } + else if (type == IntersectionType::AVATAR) { endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); } } } - + float avatarScale = DependencyManager::get()->getMyAvatar()->getAvatarScale(); QVariant end = vec3toVariant(endVec); @@ -180,7 +185,8 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } if (_centerEndY) { endProps.insert("position", end); - } else { + } + else { glm::vec3 currentUpVector = faceAvatarRotation * Vectors::UP; endProps.insert("position", vec3toVariant(endVec + glm::vec3(currentUpVector.x * 0.5f * dim.y, currentUpVector.y * 0.5f * dim.y, currentUpVector.z * 0.5f * dim.y))); } @@ -221,13 +227,14 @@ void LaserPointer::update() { if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_lockEndObject.id.isNull())) { float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; - qDebug() << &_currentRenderState; updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); - } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { + } + else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true); - } else if (!_currentRenderState.empty()) { + } + else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); disableRenderState(_defaultRenderStates[_currentRenderState].second); } diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index e0c6f631c0..7d44194be4 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -22,9 +22,9 @@ class RayPickResult; struct LockEndObject { - QUuid id { QUuid() }; - bool isOverlay { false }; - glm::mat4 offsetMat { glm::mat4() }; + QUuid id{ QUuid() }; + bool isOverlay{ false }; + glm::mat4 offsetMat{ glm::mat4() }; }; class RenderState { @@ -89,8 +89,8 @@ public: private: bool _renderingEnabled; - float _laserLength { 0.0f }; - std::string _currentRenderState { "" }; + float _laserLength{ 0.0f }; + std::string _currentRenderState{ "" }; RenderStateMap _renderStates; DefaultRenderStateMap _defaultRenderStates; bool _faceAvatar; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 143451d0d3..868491f166 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -113,9 +113,9 @@ void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector } } -void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat) const { +void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { auto laserPointer = find(uid); if (laserPointer) { - laserPointer->setLockEndUUID(objectID, isOverlay, offsetMat); + laserPointer->setLockEndUUID(objectID, isOverlay); } } diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 3f8f962679..9283b7ac89 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -39,7 +39,7 @@ public: void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const; + void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; void update(); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index a47605fa1f..eb69d610ad 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -7,7 +7,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -//// +// #include "LaserPointerScriptingInterface.h" diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index 250d823598..39e6436683 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -74,7 +74,7 @@ private: float _glow { 0.0 }; float _glowWidth { 0.0 }; - float _glowScale{ 1.0 }; + float _glowScale { 1.0 }; int _geometryCacheID; }; diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 862331b743..a325026914 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -248,7 +248,7 @@ public: renderWireCubeInstance(args, batch, glm::vec4(color, 1.0f), pipeline); } - // //Dynamic geometry + // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); size_t getShapeTriangleCount(Shape shape); diff --git a/unpublishedScripts/marketplace/shapes/modules/laser.js b/unpublishedScripts/marketplace/shapes/modules/laser.js index beefa8a2f4..1efc38b65a 100644 --- a/unpublishedScripts/marketplace/shapes/modules/laser.js +++ b/unpublishedScripts/marketplace/shapes/modules/laser.js @@ -150,7 +150,6 @@ Laser = function (side) { } function update(hand) { - return; var handPosition, handOrientation, deltaOrigin, From 536bf6f81d5e763cd4bde37bf08ec4571a655fdb Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 7 Nov 2017 18:34:33 -0700 Subject: [PATCH 082/171] Corrections --- interface/src/raypick/LaserPointer.cpp | 26 +++++++++----------------- interface/src/raypick/LaserPointer.h | 10 +++++----- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index ee0336438c..5f2549deea 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -15,7 +15,7 @@ #include "RayPickScriptingInterface.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : _renderingEnabled(enabled), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), @@ -121,8 +121,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter glm::vec3 endVec; if (((defaultState || !_lockEnd) && _lockEndObject.id.isNull()) || type == IntersectionType::HUD) { endVec = pickRay.origin + pickRay.direction * distance; - } - else { + } else { if (!_lockEndObject.id.isNull()) { glm::vec3 pos; glm::quat rot; @@ -133,8 +132,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter rot = quatFromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "rotation").value); dim = vec3FromVariant(qApp->getOverlays().getProperty(_lockEndObject.id, "dimensions").value); registrationPoint = glm::vec3(0.5f); - } - else { + } else { EntityItemProperties props = DependencyManager::get()->getEntityProperties(_lockEndObject.id); glm::mat4 entityMat = createMatFromQuatAndPos(props.getRotation(), props.getPosition()); glm::mat4 finalPosAndRotMat = entityMat * _lockEndObject.offsetMat; @@ -145,15 +143,12 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); - } - else { + } else { if (type == IntersectionType::ENTITY) { endVec = DependencyManager::get()->getEntityTransform(objectID)[3]; - } - else if (type == IntersectionType::OVERLAY) { + } else if (type == IntersectionType::OVERLAY) { endVec = vec3FromVariant(qApp->getOverlays().getProperty(objectID, "position").value); - } - else if (type == IntersectionType::AVATAR) { + } else if (type == IntersectionType::AVATAR) { endVec = DependencyManager::get()->getAvatar(objectID)->getPosition(); } } @@ -185,8 +180,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } if (_centerEndY) { endProps.insert("position", end); - } - else { + } else { glm::vec3 currentUpVector = faceAvatarRotation * Vectors::UP; endProps.insert("position", vec3toVariant(endVec + glm::vec3(currentUpVector.x * 0.5f * dim.y, currentUpVector.y * 0.5f * dim.y, currentUpVector.z * 0.5f * dim.y))); } @@ -229,12 +223,10 @@ void LaserPointer::update() { float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); - } - else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { + } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true); - } - else if (!_currentRenderState.empty()) { + } else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); disableRenderState(_defaultRenderStates[_currentRenderState].second); } diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 7d44194be4..e0c6f631c0 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -22,9 +22,9 @@ class RayPickResult; struct LockEndObject { - QUuid id{ QUuid() }; - bool isOverlay{ false }; - glm::mat4 offsetMat{ glm::mat4() }; + QUuid id { QUuid() }; + bool isOverlay { false }; + glm::mat4 offsetMat { glm::mat4() }; }; class RenderState { @@ -89,8 +89,8 @@ public: private: bool _renderingEnabled; - float _laserLength{ 0.0f }; - std::string _currentRenderState{ "" }; + float _laserLength { 0.0f }; + std::string _currentRenderState { "" }; RenderStateMap _renderStates; DefaultRenderStateMap _defaultRenderStates; bool _faceAvatar; From 8c5f97f3d10d4af6d86fb1d9c550c797eb2e03ea Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 7 Nov 2017 20:25:24 -0700 Subject: [PATCH 083/171] More corrections --- interface/src/raypick/LaserPointerManager.cpp | 4 ++-- interface/src/raypick/LaserPointerManager.h | 2 +- interface/src/ui/overlays/Line3DOverlay.cpp | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 868491f166..143451d0d3 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -113,9 +113,9 @@ void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector } } -void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { +void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat) const { auto laserPointer = find(uid); if (laserPointer) { - laserPointer->setLockEndUUID(objectID, isOverlay); + laserPointer->setLockEndUUID(objectID, isOverlay, offsetMat); } } diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 9283b7ac89..3f8f962679 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -39,7 +39,7 @@ public: void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; + void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const; void update(); diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 7ac79f081a..0dc8fddd04 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -12,7 +12,6 @@ #include #include -#include #include "AbstractViewStateInterface.h" From 055470296dba9ececec0efde03c0e0039141a243 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Nov 2017 17:13:40 +1300 Subject: [PATCH 084/171] Move current location in GOTO dialog and add placeholder text to input --- .../qml/hifi/tablet/TabletAddressDialog.qml | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 4d9a83817a..4e546ffa0d 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -11,6 +11,7 @@ import Hifi 1.0 import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../../controls" import "../../styles" @@ -205,16 +206,16 @@ StackView { anchors { top: parent.top; left: addressLineContainer.left; - right: addressLineContainer.right; } } HifiStyles.FiraSansRegular { id: location; anchors { - left: addressLineContainer.left; - leftMargin: 8; - verticalCenter: addressLineContainer.verticalCenter; + left: notice.right + leftMargin: 8 + right: addressLineContainer.right + verticalCenter: notice.verticalCenter } font.pixelSize: addressLine.font.pixelSize; color: "gray"; @@ -222,7 +223,7 @@ StackView { visible: addressLine.text.length === 0 } - TextInput { + TextField { id: addressLine width: addressLineContainer.width - addressLineContainer.anchors.leftMargin - addressLineContainer.anchors.rightMargin; anchors { @@ -230,7 +231,6 @@ StackView { leftMargin: 8; verticalCenter: addressLineContainer.verticalCenter; } - font.pixelSize: hifi.fonts.pixelSize * 0.75 onTextChanged: { updateLocationText(text.length > 0); } @@ -238,6 +238,17 @@ StackView { addressBarDialog.keyboardEnabled = false; toggleOrGo(); } + placeholderText: "Type domain address here" + verticalAlignment: TextInput.AlignBottom + style: TextFieldStyle { + textColor: hifi.colors.text + placeholderTextColor: "gray" + font { + family: hifi.fonts.fontFamily + pixelSize: hifi.fonts.pixelSize * 0.75 + } + background: Item {} + } } Rectangle { From 0d21e0be11d24cb5daaa1c93b8419fde3be67d5c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Nov 2017 17:14:17 +1300 Subject: [PATCH 085/171] Delete old, no longer used file --- interface/resources/qml/AddressBarDialog.qml | 532 ------------------- 1 file changed, 532 deletions(-) delete mode 100644 interface/resources/qml/AddressBarDialog.qml diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml deleted file mode 100644 index 60d2bacc62..0000000000 --- a/interface/resources/qml/AddressBarDialog.qml +++ /dev/null @@ -1,532 +0,0 @@ -// -// AddressBarDialog.qml -// -// Created by Austin Davis on 2015/04/14 -// Copyright 2015 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 Hifi 1.0 -import QtQuick 2.4 -import "controls" -import "styles" -import "windows" -import "hifi" -import "hifi/toolbars" -import "styles-uit" as HifiStyles -import "controls-uit" as HifiControls - -Window { - id: root - HifiConstants { id: hifi } - HifiStyles.HifiConstants { id: hifiStyleConstants } - - objectName: "AddressBarDialog" - title: "Go To:" - - shown: false - destroyOnHidden: false - resizable: false - pinnable: false; - - width: addressBarDialog.implicitWidth - height: addressBarDialog.implicitHeight - property int gap: 14 - - onShownChanged: { - addressBarDialog.keyboardEnabled = HMD.active; - addressBarDialog.observeShownChanged(shown); - } - Component.onCompleted: { - root.parentChanged.connect(center); - center(); - } - Component.onDestruction: { - root.parentChanged.disconnect(center); - } - - function center() { - // Explicitly center in order to avoid warnings at shutdown - anchors.centerIn = parent; - } - - function resetAfterTeleport() { - storyCardFrame.shown = root.shown = false; - } - function goCard(targetString) { - if (0 !== targetString.indexOf('hifi://')) { - storyCardHTML.url = addressBarDialog.metaverseServerUrl + targetString; - storyCardFrame.shown = true; - return; - } - addressLine.text = targetString; - toggleOrGo(true); - clearAddressLineTimer.start(); - } - property var allStories: []; - property int cardWidth: 212; - property int cardHeight: 152; - property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/"; - property bool isCursorVisible: false // Override default cursor visibility. - - AddressBarDialog { - id: addressBarDialog - - property bool keyboardEnabled: false - property bool keyboardRaised: false - property bool punctuationMode: false - - implicitWidth: backgroundImage.width - implicitHeight: scroll.height + gap + backgroundImage.height + (keyboardEnabled ? keyboard.height : 0); - - // The buttons have their button state changed on hover, so we have to manually fix them up here - onBackEnabledChanged: backArrow.buttonState = addressBarDialog.backEnabled ? 1 : 0; - onForwardEnabledChanged: forwardArrow.buttonState = addressBarDialog.forwardEnabled ? 1 : 0; - onReceivedHifiSchemeURL: resetAfterTeleport(); - - // Update location after using back and forward buttons. - onHostChanged: updateLocationTextTimer.start(); - - ListModel { id: suggestions } - - ListView { - id: scroll - height: cardHeight + scroll.stackedCardShadowHeight - property int stackedCardShadowHeight: 10; - spacing: gap; - clip: true; - anchors { - left: backgroundImage.left - right: swipe.left - bottom: backgroundImage.top - } - model: suggestions; - orientation: ListView.Horizontal; - delegate: Card { - width: cardWidth; - height: cardHeight; - goFunction: goCard; - userName: model.username; - placeName: model.place_name; - hifiUrl: model.place_name + model.path; - thumbnail: model.thumbnail_url; - imageUrl: model.image_url; - action: model.action; - timestamp: model.created_at; - onlineUsers: model.online_users; - storyId: model.metaverseId; - drillDownToPlace: model.drillDownToPlace; - shadowHeight: scroll.stackedCardShadowHeight; - hoverThunk: function () { ListView.view.currentIndex = index; } - unhoverThunk: function () { ListView.view.currentIndex = -1; } - } - highlightMoveDuration: -1; - highlightMoveVelocity: -1; - highlight: Rectangle { color: "transparent"; border.width: 4; border.color: hifiStyleConstants.colors.blueHighlight; z: 1; } - } - Image { // Just a visual indicator that the user can swipe the cards over to see more. - id: swipe; - source: "../images/swipe-chevron.svg"; - width: 72; - visible: suggestions.count > 3; - anchors { - right: backgroundImage.right; - top: scroll.top; - } - MouseArea { - anchors.fill: parent - onClicked: scroll.currentIndex = (scroll.currentIndex < 0) ? 3 : (scroll.currentIndex + 3) - } - } - - Row { - spacing: 2 * hifi.layout.spacing; - anchors { - top: parent.top; - left: parent.left; - leftMargin: 150; - topMargin: -30; - } - property var selected: allTab; - TextButton { - id: allTab; - text: "ALL"; - property string includeActions: 'snapshot,concurrency'; - selected: allTab === selectedTab; - action: tabSelect; - } - TextButton { - id: placeTab; - text: "PLACES"; - property string includeActions: 'concurrency'; - selected: placeTab === selectedTab; - action: tabSelect; - } - TextButton { - id: snapsTab; - text: "SNAPS"; - property string includeActions: 'snapshot'; - selected: snapsTab === selectedTab; - action: tabSelect; - } - } - - Image { - id: backgroundImage - source: "../images/address-bar-856.svg" - width: 856 - height: 100 - anchors { - bottom: parent.keyboardEnabled ? keyboard.top : parent.bottom; - } - property int inputAreaHeight: 70 - property int inputAreaStep: (height - inputAreaHeight) / 2 - - ToolbarButton { - id: homeButton - imageURL: "../images/home.svg" - onClicked: { - addressBarDialog.loadHome(); - root.shown = false; - } - anchors { - left: parent.left - leftMargin: homeButton.width / 2 - verticalCenter: parent.verticalCenter - } - } - - ToolbarButton { - id: backArrow; - imageURL: "../images/backward.svg"; - onClicked: addressBarDialog.loadBack(); - anchors { - left: homeButton.right - verticalCenter: parent.verticalCenter - } - } - ToolbarButton { - id: forwardArrow; - imageURL: "../images/forward.svg"; - onClicked: addressBarDialog.loadForward(); - anchors { - left: backArrow.right - verticalCenter: parent.verticalCenter - } - } - - HifiStyles.RalewayLight { - id: notice; - font.pixelSize: hifi.fonts.pixelSize * 0.50; - anchors { - top: parent.top - topMargin: parent.inputAreaStep + 12 - left: addressLine.left - right: addressLine.right - } - } - HifiStyles.FiraSansRegular { - id: location; - font.pixelSize: addressLine.font.pixelSize; - color: "gray"; - clip: true; - anchors.fill: addressLine; - visible: addressLine.text.length === 0 - } - TextInput { - id: addressLine - focus: true - anchors { - top: parent.top - bottom: parent.bottom - left: forwardArrow.right - right: parent.right - leftMargin: forwardArrow.width - rightMargin: forwardArrow.width / 2 - topMargin: parent.inputAreaStep + (2 * hifi.layout.spacing) - bottomMargin: parent.inputAreaStep - } - font.pixelSize: hifi.fonts.pixelSize * 0.75 - cursorVisible: false - onTextChanged: { - filterChoicesByText(); - updateLocationText(text.length > 0); - if (!isCursorVisible && text.length > 0) { - isCursorVisible = true; - cursorVisible = true; - } - } - onActiveFocusChanged: { - cursorVisible = isCursorVisible && focus; - } - MouseArea { - // If user clicks in address bar show cursor to indicate ability to enter address. - anchors.fill: parent - onClicked: { - isCursorVisible = true; - parent.cursorVisible = true; - parent.forceActiveFocus(); - } - } - } - } - - Timer { - // Delay updating location text a bit to avoid flicker of content and so that connection status is valid. - id: updateLocationTextTimer - running: false - interval: 500 // ms - repeat: false - onTriggered: updateLocationText(false); - } - - Timer { - // Delay clearing address line so as to avoid flicker of "not connected" being displayed after entering an address. - id: clearAddressLineTimer - running: false - interval: 100 // ms - repeat: false - onTriggered: { - addressLine.text = ""; - isCursorVisible = false; - } - } - - Window { - width: 938 - height: 625 - HifiControls.WebView { - anchors.fill: parent; - id: storyCardHTML; - } - id: storyCardFrame; - - shown: false; - destroyOnCloseButton: false; - pinnable: false; - - anchors { - verticalCenter: backgroundImage.verticalCenter; - horizontalCenter: scroll.horizontalCenter; - } - z: 100 - } - - HifiControls.Keyboard { - id: keyboard - raised: parent.keyboardEnabled // Ignore keyboardRaised; keep keyboard raised if enabled (i.e., in HMD). - numeric: parent.punctuationMode - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - } - } - } - - function getRequest(url, cb) { // cb(error, responseOfCorrectContentType) of url. General for 'get' text/html/json, but without redirects. - // TODO: make available to other .qml. - var request = new XMLHttpRequest(); - // QT bug: apparently doesn't handle onload. Workaround using readyState. - request.onreadystatechange = function () { - var READY_STATE_DONE = 4; - var HTTP_OK = 200; - if (request.readyState >= READY_STATE_DONE) { - var error = (request.status !== HTTP_OK) && request.status.toString() + ':' + request.statusText, - response = !error && request.responseText, - contentType = !error && request.getResponseHeader('content-type'); - if (!error && contentType.indexOf('application/json') === 0) { - try { - response = JSON.parse(response); - } catch (e) { - error = e; - } - } - cb(error, response); - } - }; - request.open("GET", url, true); - request.send(); - } - - function identity(x) { - return x; - } - - function handleError(url, error, data, cb) { // cb(error) and answer truthy if needed, else falsey - if (!error && (data.status === 'success')) { - return; - } - if (!error) { // Create a message from the data - error = data.status + ': ' + data.error; - } - if (typeof(error) === 'string') { // Make a proper Error object - error = new Error(error); - } - error.message += ' in ' + url; // Include the url. - cb(error); - return true; - } - function resolveUrl(url) { - return (url.indexOf('/') === 0) ? (addressBarDialog.metaverseServerUrl + url) : url; - } - - function makeModelData(data) { // create a new obj from data - // ListModel elements will only ever have those properties that are defined by the first obj that is added. - // So here we make sure that we have all the properties we need, regardless of whether it is a place data or user story. - var name = data.place_name, - tags = data.tags || [data.action, data.username], - description = data.description || "", - thumbnail_url = data.thumbnail_url || ""; - return { - place_name: name, - username: data.username || "", - path: data.path || "", - created_at: data.created_at || "", - action: data.action || "", - thumbnail_url: resolveUrl(thumbnail_url), - image_url: resolveUrl(data.details.image_url), - - metaverseId: (data.id || "").toString(), // Some are strings from server while others are numbers. Model objects require uniformity. - - tags: tags, - description: description, - online_users: data.details.concurrency || 0, - drillDownToPlace: false, - - searchText: [name].concat(tags, description || []).join(' ').toUpperCase() - } - } - function suggestable(place) { - if (place.action === 'snapshot') { - return true; - } - return (place.place_name !== AddressManager.placename); // Not our entry, but do show other entry points to current domain. - } - property var selectedTab: allTab; - function tabSelect(textButton) { - selectedTab = textButton; - fillDestinations(); - } - property var placeMap: ({}); - function addToSuggestions(place) { - var collapse = allTab.selected && (place.action !== 'concurrency'); - if (collapse) { - var existing = placeMap[place.place_name]; - if (existing) { - existing.drillDownToPlace = true; - return; - } - } - suggestions.append(place); - if (collapse) { - placeMap[place.place_name] = suggestions.get(suggestions.count - 1); - } else if (place.action === 'concurrency') { - suggestions.get(suggestions.count - 1).drillDownToPlace = true; // Don't change raw place object (in allStories). - } - } - property int requestId: 0; - function getUserStoryPage(pageNumber, cb) { // cb(error) after all pages of domain data have been added to model - var options = [ - 'now=' + new Date().toISOString(), - 'include_actions=' + selectedTab.includeActions, - 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), - 'require_online=true', - 'protocol=' + encodeURIComponent(AddressManager.protocolVersion()), - 'page=' + pageNumber - ]; - var url = metaverseBase + 'user_stories?' + options.join('&'); - var thisRequestId = ++requestId; - getRequest(url, function (error, data) { - if ((thisRequestId !== requestId) || handleError(url, error, data, cb)) { - return; - } - var stories = data.user_stories.map(function (story) { // explicit single-argument function - return makeModelData(story, url); - }); - allStories = allStories.concat(stories); - stories.forEach(makeFilteredPlaceProcessor()); - if ((data.current_page < data.total_pages) && (data.current_page <= 10)) { // just 10 pages = 100 stories for now - return getUserStoryPage(pageNumber + 1, cb); - } - cb(); - }); - } - function makeFilteredPlaceProcessor() { // answer a function(placeData) that adds it to suggestions if it matches - var words = addressLine.text.toUpperCase().split(/\s+/).filter(identity), - data = allStories; - function matches(place) { - if (!words.length) { - return suggestable(place); - } - return words.every(function (word) { - return place.searchText.indexOf(word) >= 0; - }); - } - return function (place) { - if (matches(place)) { - addToSuggestions(place); - } - }; - } - function filterChoicesByText() { - suggestions.clear(); - placeMap = {}; - allStories.forEach(makeFilteredPlaceProcessor()); - } - - function fillDestinations() { - allStories = []; - suggestions.clear(); - placeMap = {}; - getUserStoryPage(1, function (error) { - console.log('user stories query', error || 'ok', allStories.length); - }); - } - - function updateLocationText(enteringAddress) { - if (enteringAddress) { - notice.text = "Go to a place, @user, path or network address"; - notice.color = hifiStyleConstants.colors.baseGrayHighlight; - } else { - notice.text = AddressManager.isConnected ? "Your location:" : "Not Connected"; - notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.baseGrayHighlight : hifiStyleConstants.colors.redHighlight; - // Display hostname, which includes ip address, localhost, and other non-placenames. - location.text = (AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''); - } - } - - onVisibleChanged: { - updateLocationText(false); - if (visible) { - addressLine.forceActiveFocus(); - fillDestinations(); - } - } - - function toggleOrGo(fromSuggestions) { - if (addressLine.text !== "") { - addressBarDialog.loadAddress(addressLine.text, fromSuggestions) - } - root.shown = false; - } - - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Escape: - case Qt.Key_Back: - root.shown = false - clearAddressLineTimer.start(); - event.accepted = true - break - case Qt.Key_Enter: - case Qt.Key_Return: - toggleOrGo() - clearAddressLineTimer.start(); - event.accepted = true - break - } - } -} From 39604363eaeefb11ceae5c3870b117c0a21bcc5b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 8 Nov 2017 11:38:20 +0100 Subject: [PATCH 086/171] Optimized performance of bloom by reducing blur resolution and merging some downsampling passes with blur passes --- libraries/render-utils/src/BloomApply.slf | 2 +- libraries/render-utils/src/BloomEffect.cpp | 116 +++++++++++++----- libraries/render-utils/src/BloomEffect.h | 19 ++- libraries/render-utils/src/BloomThreshold.slf | 28 ++++- libraries/render/src/render/BlurTask.cpp | 32 +++-- libraries/render/src/render/BlurTask.h | 7 +- libraries/render/src/render/ResampleTask.cpp | 4 +- libraries/render/src/render/ResampleTask.h | 3 +- 8 files changed, 151 insertions(+), 60 deletions(-) diff --git a/libraries/render-utils/src/BloomApply.slf b/libraries/render-utils/src/BloomApply.slf index 17f13b1187..953258e8ab 100644 --- a/libraries/render-utils/src/BloomApply.slf +++ b/libraries/render-utils/src/BloomApply.slf @@ -23,5 +23,5 @@ void main(void) { vec4 blur1 = texture(blurMap1, varTexCoord0); vec4 blur2 = texture(blurMap2, varTexCoord0); - outFragColor = vec4((blur0.rgb+blur1.rgb+blur2.rgb)/3.0, intensity); + outFragColor = vec4((blur0.rgb+blur1.rgb+blur2.rgb)*intensity, 1.0f); } diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 69bc790c59..9d9367a6d5 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -21,8 +21,9 @@ #define BLOOM_BLUR_LEVEL_COUNT 3 -BloomThreshold::BloomThreshold() { - +BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) : + _downsamplingFactor(downsamplingFactor) { + assert(downsamplingFactor > 0); } void BloomThreshold::configure(const Config& config) { @@ -41,9 +42,13 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons assert(inputFrameBuffer->hasColor()); auto inputBuffer = inputFrameBuffer->getRenderBuffer(0); - auto bufferSize = glm::ivec2(inputBuffer->getDimensions()); + auto bufferSize = gpu::Vec2u(inputBuffer->getDimensions()); - if (!_outputBuffer || _outputBuffer->getSize() != inputFrameBuffer->getSize()) { + // Downsample resolution + bufferSize.x /= _downsamplingFactor; + bufferSize.y /= _downsamplingFactor; + + if (!_outputBuffer || _outputBuffer->getSize() != bufferSize) { auto colorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(inputBuffer->getTexelFormat(), bufferSize.x, bufferSize.y, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); @@ -68,13 +73,15 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons _pipeline = gpu::Pipeline::create(program, state); } + glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); + batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, args->_viewport)); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setPipeline(_pipeline); batch.setFramebuffer(_outputBuffer); @@ -117,8 +124,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + state->setDepthTest(gpu::State::DepthTest(false, false)); _pipeline = gpu::Pipeline::create(program, state); } @@ -127,26 +133,70 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In const auto blur0FB = inputs.get1(); const auto blur1FB = inputs.get2(); const auto blur2FB = inputs.get3(); + const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y }; gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setFramebuffer(frameBuffer); - batch.setViewportTransform(args->_viewport); + batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); batch.setPipeline(_pipeline); - batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport)); batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0)); batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0)); batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0)); - batch._glUniform1f(INTENSITY_SLOT, _intensity); + batch._glUniform1f(INTENSITY_SLOT, _intensity / 3.0f); batch.draw(gpu::TRIANGLE_STRIP, 4); }); } +void BloomDraw::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + const auto frameBuffer = inputs.get0(); + const auto bloomFrameBuffer = inputs.get1(); + + if (frameBuffer && bloomFrameBuffer) { + const auto framebufferSize = frameBuffer->getSize(); + + if (!_pipeline) { + auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); + auto ps = gpu::StandardShaderLib::getDrawTextureOpaquePS(); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + gpu::State::ZERO, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _pipeline = gpu::Pipeline::create(program, state); + } + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.enableStereo(false); + + batch.setFramebuffer(frameBuffer); + + batch.setViewportTransform(args->_viewport); + batch.setProjectionTransform(glm::mat4()); + batch.resetViewTransform(); + batch.setPipeline(_pipeline); + + batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport)); + batch.setResourceTexture(0, bloomFrameBuffer->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + } +} + DebugBloom::DebugBloom() { } @@ -161,6 +211,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In RenderArgs* args = renderContext->args; const auto frameBuffer = inputs.get0(); + const auto combinedBlurBuffer = inputs.get4(); const auto framebufferSize = frameBuffer->getSize(); const auto level0FB = inputs.get1(); const auto level1FB = inputs.get2(); @@ -216,6 +267,11 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In batch.setModelTransform(modelTransform); batch.setResourceTexture(0, levelTextures[2]); batch.draw(gpu::TRIANGLE_STRIP, 4); + + modelTransform.postTranslate(glm::vec3(2.0f, 0.0f, 0.0f)); + batch.setModelTransform(modelTransform); + batch.setResourceTexture(0, combinedBlurBuffer->getRenderBuffer(0)); + batch.draw(gpu::TRIANGLE_STRIP, 4); } else { auto viewport = args->_viewport; auto blurLevel = _mode - DebugBloomConfig::MODE_LEVEL0; @@ -258,7 +314,7 @@ void BloomConfig::setSize(float value) { assert(blurJobIt != task->_jobs.end()); auto& gaussianBlur = blurJobIt->edit(); auto gaussianBlurParams = gaussianBlur.getParameters(); - gaussianBlurParams->setFilterGaussianTaps((BLUR_MAX_NUM_TAPS - 1) / 2, sigma); + gaussianBlurParams->setFilterGaussianTaps(5, sigma); // Gaussian blur increases at each level to have a slower rolloff on the edge // of the response sigma *= 1.5f; @@ -280,32 +336,24 @@ void Bloom::configure(const Config& config) { } void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { - const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs); - const auto bloomHalfInputBuffer = task.addJob("BloomHalf", bloomInputBuffer); - const auto bloomQuarterInputBuffer = task.addJob("BloomQuarter", bloomHalfInputBuffer); + // Start by computing threshold of color buffer input at quarter resolution + const auto bloomInputBuffer = task.addJob("BloomThreshold", inputs, 4U); -#if 1 - // Multi-scale blur - const auto blurFB0 = task.addJob("BloomBlur0", bloomQuarterInputBuffer); - const auto halfBlurFB0 = task.addJob("BloomHalfBlur0", blurFB0); - const auto blurFB1 = task.addJob("BloomBlur1", halfBlurFB0, true); - const auto halfBlurFB1 = task.addJob("BloomHalfBlur1", blurFB1); - const auto blurFB2 = task.addJob("BloomBlur2", halfBlurFB1, true); -#else - // Multi-scale downsampling debug - const auto blurFB0 = bloomQuarterInputBuffer; - const auto blurFB1 = task.addJob("BloomHalfBlur1", blurFB0); - const auto blurFB2 = task.addJob("BloomHalfBlur2", blurFB1); - // This is only needed so as not to crash as we expect to have the three blur jobs - task.addJob("BloomBlur0", bloomHalfInputBuffer, true); - task.addJob("BloomBlur1", blurFB1, true); - task.addJob("BloomBlur2", blurFB2, true); -#endif + // Multi-scale blur, each new blur is half resolution of the previous pass + const auto blurFB0 = task.addJob("BloomBlur0", bloomInputBuffer, true); + const auto blurFB1 = task.addJob("BloomBlur1", blurFB0, true, 2U); + const auto blurFB2 = task.addJob("BloomBlur2", blurFB1, true, 2U); const auto& input = inputs.get(); const auto& frameBuffer = input[1]; - const auto applyInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2).asVarying(); + // Mix all blur levels at quarter resolution + const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying(); task.addJob("BloomApply", applyInput); - task.addJob("DebugBloom", applyInput); + // And them blend result in additive manner on top of final color buffer + const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying(); + task.addJob("BloomDraw", drawInput); + + const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, bloomInputBuffer).asVarying(); + task.addJob("DebugBloom", debugInput); } diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index fdc2d1a0ba..76ce1b8f52 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -54,7 +54,7 @@ public: using Config = BloomThresholdConfig; using JobModel = render::Job::ModelIO; - BloomThreshold(); + BloomThreshold(unsigned int downsamplingFactor); void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); @@ -64,6 +64,7 @@ private: gpu::FramebufferPointer _outputBuffer; gpu::PipelinePointer _pipeline; float _threshold; + unsigned int _downsamplingFactor; }; @@ -96,6 +97,20 @@ private: float _intensity{ 1.0f }; }; +class BloomDraw { +public: + using Inputs = render::VaryingSet2; + using JobModel = render::Job::ModelI; + + BloomDraw() {} + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); + +private: + + gpu::PipelinePointer _pipeline; +}; + class DebugBloomConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int mode MEMBER mode NOTIFY dirty) @@ -121,7 +136,7 @@ signals: class DebugBloom { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet5; using Config = DebugBloomConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index 14d20dd684..e4b96618df 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -16,12 +16,30 @@ uniform float threshold; in vec2 varTexCoord0; out vec4 outFragColor; +#define DOWNSAMPLING_FACTOR 4 +#define SAMPLE_COUNT (DOWNSAMPLING_FACTOR/2) + void main(void) { - vec4 color = texture(colorMap, varTexCoord0); - float luminance = (color.r+color.g+color.b) / 3.0; - float mask = clamp((luminance-threshold)*0.25, 0, 1); + vec2 deltaX = dFdx(varTexCoord0) / SAMPLE_COUNT; + vec2 deltaY = dFdy(varTexCoord0) / SAMPLE_COUNT; + vec2 startUv = varTexCoord0; + vec4 maskedColor = vec4(0,0,0,0); - color *= mask; + for (int y=0 ; y 0); } bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFramebuffer, Resources& blurringResources) { if (!sourceFramebuffer) { return false; } - if (_blurredFramebuffer && _blurredFramebuffer->getSize() != sourceFramebuffer->getSize()) { + + auto blurBufferSize = sourceFramebuffer->getSize(); + + blurBufferSize.x /= _downsampleFactor; + blurBufferSize.y /= _downsampleFactor; + + if (_blurredFramebuffer && _blurredFramebuffer->getSize() != blurBufferSize) { _blurredFramebuffer.reset(); } @@ -158,7 +164,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra // _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); //} auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); - auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); + auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), blurBufferSize.x, blurBufferSize.y, gpu::Texture::SINGLE_MIP, blurringSampler); _blurredFramebuffer->setRenderBuffer(0, blurringTarget); } @@ -167,7 +173,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra blurringResources.blurringTexture = _blurredFramebuffer->getRenderBuffer(0); if (_generateOutputFramebuffer) { - if (_outputFramebuffer && _outputFramebuffer->getSize() != sourceFramebuffer->getSize()) { + if (_outputFramebuffer && _outputFramebuffer->getSize() != blurBufferSize) { _outputFramebuffer.reset(); } @@ -181,7 +187,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra _outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); }*/ auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); - auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), gpu::Texture::SINGLE_MIP, blurringSampler); + auto blurringTarget = gpu::Texture::createRenderBuffer(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), blurBufferSize.x, blurBufferSize.y, gpu::Texture::SINGLE_MIP, blurringSampler); _outputFramebuffer->setRenderBuffer(0, blurringTarget); } @@ -195,8 +201,8 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra return true; } -BlurGaussian::BlurGaussian(bool generateOutputFramebuffer) : - _inOutResources(generateOutputFramebuffer) +BlurGaussian::BlurGaussian(bool generateOutputFramebuffer, unsigned int downsampleFactor) : + _inOutResources(generateOutputFramebuffer, downsampleFactor) { _parameters = std::make_shared(); } @@ -276,8 +282,8 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra auto blurHPipeline = getBlurHPipeline(); glm::ivec4 viewport { 0, 0, blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight() }; - _parameters->setWidthHeight(viewport.z, viewport.w, args->isStereo()); - glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions()); + glm::ivec2 textureSize = blurredFramebuffer->getSize(); + _parameters->setWidthHeight(blurredFramebuffer->getWidth(), blurredFramebuffer->getHeight(), args->isStereo()); _parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, viewport)); gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { @@ -310,7 +316,7 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra BlurGaussianDepthAware::BlurGaussianDepthAware(bool generateOutputFramebuffer, const BlurParamsPointer& params) : - _inOutResources(generateOutputFramebuffer), + _inOutResources(generateOutputFramebuffer, 1U), _parameters((params ? params : std::make_shared())) { } diff --git a/libraries/render/src/render/BlurTask.h b/libraries/render/src/render/BlurTask.h index cbee3e35f1..e8d268dc63 100644 --- a/libraries/render/src/render/BlurTask.h +++ b/libraries/render/src/render/BlurTask.h @@ -72,7 +72,7 @@ using BlurParamsPointer = std::shared_ptr; class BlurInOutResource { public: - BlurInOutResource(bool generateOutputFramebuffer = false); + BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor); struct Resources { gpu::TexturePointer sourceTexture; @@ -85,8 +85,9 @@ public: gpu::FramebufferPointer _blurredFramebuffer; - // the output framebuffer defined if the job needs to output the result in a new framebuffer and not in place in th einput buffer + // the output framebuffer defined if the job needs to output the result in a new framebuffer and not in place in the input buffer gpu::FramebufferPointer _outputFramebuffer; + unsigned int _downsampleFactor{ 1U }; bool _generateOutputFramebuffer{ false }; }; @@ -115,7 +116,7 @@ public: using Config = BlurGaussianConfig; using JobModel = Job::ModelIO; - BlurGaussian(bool generateOutputFramebuffer = false); + BlurGaussian(bool generateOutputFramebuffer = false, unsigned int downsampleFactor = 1U); void configure(const Config& config); void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer); diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index 929db50c31..65c0ff45b9 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -17,6 +17,8 @@ using namespace render; +gpu::PipelinePointer HalfDownsample::_pipeline; + HalfDownsample::HalfDownsample() { } @@ -57,7 +59,7 @@ void HalfDownsample::run(const RenderContextPointer& renderContext, const gpu::F gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); + state->setDepthTest(gpu::State::DepthTest(false, false)); _pipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 70cb9a54bb..da2b7b3537 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -30,7 +30,8 @@ namespace render { protected: - gpu::PipelinePointer _pipeline; + static gpu::PipelinePointer _pipeline; + gpu::FramebufferPointer _destinationFrameBuffer; gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); From bbcb0b2d9b82dce3d233d4e207f4419af115d7b3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 8 Nov 2017 13:49:18 +0100 Subject: [PATCH 087/171] Fixed highlight in stereo mode, including HMD (testing on simulator) --- libraries/gpu/src/gpu/Transform.slh | 12 ++++++++---- libraries/render-utils/src/Highlight_aabox.slv | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 9feca4a3c9..b9b8544601 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -193,13 +193,17 @@ TransformObject getTransformObject() { } <@endfunc@> -<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> - { // transformModelToClipPos +<@func transformModelToMonoClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> + { // transformModelToMonoClipPos vec4 eyeWAPos; <$transformModelToEyeWorldAlignedPos($cameraTransform$, $objectTransform$, $modelPos$, eyeWAPos)$> - <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; - + } +<@endfunc@> + +<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> + { // transformModelToClipPos + <$transformModelToMonoClipPos($cameraTransform$, $objectTransform$, $modelPos$, $clipPos$)$> <$transformStereoClipsSpace($cameraTransform$, $clipPos$)$> } <@endfunc@> diff --git a/libraries/render-utils/src/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv index 1a46ccd9c7..4927db9610 100644 --- a/libraries/render-utils/src/Highlight_aabox.slv +++ b/libraries/render-utils/src/Highlight_aabox.slv @@ -93,11 +93,12 @@ void main(void) { // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, pos, gl_Position)$> + <$transformModelToMonoClipPos(cam, obj, pos, gl_Position)$> // Offset the vertex to take into account the outline width pos.xyz += UNIT_BOX_NORMALS[triangleIndex]; vec4 offsetPosition; - <$transformModelToClipPos(cam, obj, pos, offsetPosition)$> + <$transformModelToMonoClipPos(cam, obj, pos, offsetPosition)$> gl_Position.xy += normalize(offsetPosition.xy-gl_Position.xy) * outlineWidth * gl_Position.w; + <$transformStereoClipsSpace(cam, gl_Position)$> } From 5e32298183caa1cc7ef8f1a05d372d545cf6bef8 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 8 Nov 2017 18:43:59 +0100 Subject: [PATCH 088/171] Rework as script=only solution --- interface/src/Application.cpp | 18 ++++-------------- interface/src/Application.h | 4 ---- scripts/developer/debugging/debugWindow.js | 10 ++++++++++ 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 13765e41d3..4f051697ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5781,7 +5781,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater); - connect(scriptEngine.data(), &ScriptEngine::finished, this, &Application::cleanupRunningScripts); scriptEngine->registerGlobalObject("Overlays", &_overlays); qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue); @@ -6195,15 +6194,10 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const } void Application::showScriptLogs() { - if (!_runningScripts.contains("debugWindow.js")) { - auto scriptEngines = DependencyManager::get(); - QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); - defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); - ScriptEnginePointer sePointer = scriptEngines->loadScript(defaultScriptsLoc.toString()); - _runningScripts["debugWindow.js"] = sePointer; - } else { - qWarning() << "Scripts Log already running"; - } + auto scriptEngines = DependencyManager::get(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); + defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/debugging/debugWindow.js"); + scriptEngines->loadScript(defaultScriptsLoc.toString()); } void Application::showAssetServerWidget(QString filePath) { @@ -7302,10 +7296,6 @@ void Application::switchDisplayMode() { _previousHMDWornStatus = currentHMDWornStatus; } -void Application::cleanupRunningScripts(const QString& fileNameString, ScriptEnginePointer) { - _runningScripts.remove(QUrl(fileNameString).fileName()); -} - void Application::startHMDStandBySession() { _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index c651ea6d5b..fbfb3979be 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -440,8 +440,6 @@ private slots: void handleSandboxStatus(QNetworkReply* reply); void switchDisplayMode(); - - void cleanupRunningScripts(const QString& fileNameString, ScriptEnginePointer); private: static void initDisplay(); void init(); @@ -712,7 +710,5 @@ private: std::atomic _pendingIdleEvent { false }; std::atomic _pendingRenderEvent { false }; - - QHash _runningScripts; }; #endif // hifi_Application_h diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index b16739b2b8..4390cf1f77 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -10,13 +10,23 @@ (function() { // BEGIN LOCAL_SCOPE +//check if script already running. +var scriptData = ScriptDiscoveryService.getRunning(); +var scripts = scriptData.filter(function (datum) { return datum.name === 'debugWindow.js'; }); +if (scripts.length >= 2) { + //2nd instance of the script is too much + return; +} + // Set up the qml ui var qml = Script.resolvePath('debugWindow.qml'); + var window = new OverlayWindow({ title: 'Debug Window', source: qml, width: 400, height: 900, }); + window.setPosition(25, 50); window.closed.connect(function() { Script.stop(); }); From b7163bb8fc1bf1e9425ae3a2c12e487f14f84ccd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 10:24:26 -0800 Subject: [PATCH 089/171] Frontend changes --- interface/resources/qml/hifi/commerce/wallet/WalletHome.qml | 3 ++- interface/src/commerce/Ledger.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index ff89f01943..9b244d66ca 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -212,7 +212,8 @@ Item { RalewayRegular { id: noActivityText; - text: "No activity yet.


Looking for a little spending money?
Click the button below to apply for your free HFC!"; + text: "The Wallet app is in closed Beta.

To request entry and receive free HFC, please contact " + + "info@highfidelity.com with your High Fidelity account username and the email address registered to that account."; // Text size size: 24; // Style diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index ed862384dc..01c11347fd 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -43,7 +43,6 @@ QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) { #define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply& reply) { emit NAME##Result(failResponse(#NAME, reply)); } #define Handler(NAME) ApiHandler(NAME) FailHandler(NAME) Handler(buy) -Handler(receiveAt) Handler(balance) Handler(inventory) @@ -99,6 +98,7 @@ void Ledger::receiveAtSuccess(QNetworkReply& reply) { wallet->setMustRegenerateKeypair(true); } } +void Ledger::receiveAtFailure(QNetworkReply& reply) { failResponse("receiveAt", reply); } bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { From 72fa0823ba05a21bf04af4358070e70c09843ca6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 10:40:47 -0800 Subject: [PATCH 090/171] Logic changes --- .../qml/hifi/commerce/wallet/WalletHome.qml | 21 +++---------------- interface/src/commerce/Wallet.cpp | 6 +++++- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 9b244d66ca..fd7ce0fdfd 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -218,30 +218,15 @@ Item { size: 24; // Style color: hifi.colors.blueAccent; - anchors.top: parent.top; - anchors.topMargin: 26; anchors.left: parent.left; + anchors.leftMargin: 12; anchors.right: parent.right; + anchors.rightMargin: 12; + anchors.verticalCenter: parent.verticalCenter; height: paintedHeight; wrapMode: Text.WordWrap; horizontalAlignment: Text.AlignHCenter; } - - // "Apply" button - HifiControlsUit.Button { - id: changePassphraseButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.top: noActivityText.bottom; - anchors.topMargin: 25; - anchors.horizontalCenter: parent.horizontalCenter; - width: 180; - height: 40; - text: "Apply Now"; - onClicked: { - Qt.openUrlExternally("https://www.highfidelity.com/"); - } - } } ListView { diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index b746b58015..fa72d02cca 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -324,12 +324,16 @@ Wallet::Wallet() { connect(ledger.data(), &Ledger::accountResult, this, [&]() { auto wallet = DependencyManager::get(); + auto ledger = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint status; - if (_mustRegenerateKeypair) { + if (_mustRegenerateKeypair || (!_passphrase->isEmpty() && _publicKeys.count() == 0)) { + qCDebug(commerce) << "Regenerating keys and resetting user_hfc_account. _mustRegenerateKeypair:" + << _mustRegenerateKeypair << "_publicKeys.count():" << _publicKeys.count(); _mustRegenerateKeypair = false; resetKeysOnly(); + ledger->reset(); generateKeyPair(); } From 3190fe1f325dd7851a605abc6df7d9fc88ad7745 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 11:44:21 -0800 Subject: [PATCH 091/171] Use keyfilepath instead of cached public keys --- .../qml/hifi/commerce/wallet/WalletHome.qml | 4 ++ interface/src/commerce/Ledger.cpp | 4 +- interface/src/commerce/QmlCommerce.cpp | 5 +++ interface/src/commerce/QmlCommerce.h | 1 + interface/src/commerce/Wallet.cpp | 45 +++++++++++-------- 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index fd7ce0fdfd..44d3d54f58 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -43,6 +43,10 @@ Item { calculatePendingAndInvalidated(); } + + if (transactionHistoryModel.count === 0) { + commerce.setMustRegenerateKeypair(true); + } refreshTimer.start(); } } diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 01c11347fd..519c906fd8 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -94,7 +94,9 @@ void Ledger::receiveAtSuccess(QNetworkReply& reply) { QByteArray response = reply.readAll(); QJsonObject data = QJsonDocument::fromJson(response).object(); - if (data["status"] == "fail") { // Not on "The List" for receiving HFC + // ZRF FIXME! Change to something like `data["status"] == fail` + // Not on "The List" for receiving HFC + if (true) { wallet->setMustRegenerateKeypair(true); } } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index f29e46d843..ebd2d9ae7c 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -57,6 +57,11 @@ void QmlCommerce::getWalletAuthenticatedStatus() { emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase()); } +void QmlCommerce::setMustRegenerateKeypair(const bool& val) { + auto wallet = DependencyManager::get(); + wallet->setMustRegenerateKeypair(val); +} + void QmlCommerce::getSecurityImage() { auto wallet = DependencyManager::get(); wallet->getSecurityImage(); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index d4f4aa35d2..a4e2ab8f42 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -54,6 +54,7 @@ protected: Q_INVOKABLE void getKeyFilePathIfExists(); Q_INVOKABLE void getSecurityImage(); Q_INVOKABLE void getWalletAuthenticatedStatus(); + Q_INVOKABLE void setMustRegenerateKeypair(const bool& val); Q_INVOKABLE void chooseSecurityImage(const QString& imageFile); Q_INVOKABLE void setPassphrase(const QString& passphrase); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index fa72d02cca..07861d0633 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -328,9 +328,9 @@ Wallet::Wallet() { auto walletScriptingInterface = DependencyManager::get(); uint status; - if (_mustRegenerateKeypair || (!_passphrase->isEmpty() && _publicKeys.count() == 0)) { + if (_mustRegenerateKeypair || getKeyFilePath() == "") { qCDebug(commerce) << "Regenerating keys and resetting user_hfc_account. _mustRegenerateKeypair:" - << _mustRegenerateKeypair << "_publicKeys.count():" << _publicKeys.count(); + << _mustRegenerateKeypair << "keyFilePath:" << getKeyFilePath(); _mustRegenerateKeypair = false; resetKeysOnly(); ledger->reset(); @@ -535,25 +535,32 @@ bool Wallet::generateKeyPair() { // FIXME: initialize OpenSSL elsewhere soon initialize(); - qCInfo(commerce) << "Generating keypair."; - auto keyPair = generateRSAKeypair(); - - writeBackupInstructions(); - - // TODO: redo this soon -- need error checking and so on - writeSecurityImage(_securityImage, keyFilePath()); + qCInfo(commerce) << "Generating keypair..."; + QPair keyPair = generateRSAKeypair(); QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last(); - QString key = keyPair.first->toBase64(); - _publicKeys.push_back(key); - qCDebug(commerce) << "public key:" << key; + if (keyPair.first) { + writeBackupInstructions(); - // It's arguable whether we want to change the receiveAt every time, but: - // 1. It's certainly needed the first time, when createIfNeeded answers true. - // 2. It is maximally private, and we can step back from that later if desired. - // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. - auto ledger = DependencyManager::get(); - QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); - return ledger->receiveAt(key, oldKey, machineFingerprint); + // TODO: redo this soon -- need error checking and so on + if (_securityImage) { + writeSecurityImage(_securityImage, keyFilePath()); + } + + QString key = keyPair.first->toBase64(); + _publicKeys.push_back(key); + qCDebug(commerce) << "public key:" << key; + + // It's arguable whether we want to change the receiveAt every time, but: + // 1. It's certainly needed the first time, when createIfNeeded answers true. + // 2. It is maximally private, and we can step back from that later if desired. + // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. + auto ledger = DependencyManager::get(); + QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + return ledger->receiveAt(key, oldKey, machineFingerprint); + } else { + qCDebug(commerce) << "Failure generating keys!"; + return false; + } } QStringList Wallet::listPublicKeys() { From 7995f50fab0cc1cd945b3deb572567ea2cb74c45 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 12:52:53 -0800 Subject: [PATCH 092/171] Fix seeding --- interface/src/commerce/Ledger.cpp | 2 +- interface/src/commerce/Wallet.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 519c906fd8..b344e00430 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -111,7 +111,7 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QSt } QJsonObject transaction; - transaction["hfc_key"] = hfc_key; + transaction["public_key"] = hfc_key; transaction["machine_fingerprint"] = machine_fingerprint; QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 07861d0633..05c356cea9 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -333,8 +333,8 @@ Wallet::Wallet() { << _mustRegenerateKeypair << "keyFilePath:" << getKeyFilePath(); _mustRegenerateKeypair = false; resetKeysOnly(); - ledger->reset(); - generateKeyPair(); + ledger->reset(); // Hits `reset_user_hfc_account` endpoint + generateKeyPair(); // Hits `receive_at` endpoint } if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { From 02625a6e28d63c0f6fb7f488eb3b1d310a3d8703 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 8 Nov 2017 21:53:42 +0100 Subject: [PATCH 093/171] Remove script from engine --- scripts/developer/debugging/debugWindow.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 4390cf1f77..068efb351b 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -15,6 +15,7 @@ var scriptData = ScriptDiscoveryService.getRunning(); var scripts = scriptData.filter(function (datum) { return datum.name === 'debugWindow.js'; }); if (scripts.length >= 2) { //2nd instance of the script is too much + ScriptDiscoveryService.stopScript(scripts[1].url); return; } From 38fde43009e4221030b89285791f9e397d6f2548 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 13:19:47 -0800 Subject: [PATCH 094/171] ...simplify your life --- .../qml/hifi/commerce/wallet/WalletHome.qml | 4 -- interface/src/commerce/Ledger.cpp | 13 +--- interface/src/commerce/QmlCommerce.cpp | 5 -- interface/src/commerce/QmlCommerce.h | 1 - interface/src/commerce/Wallet.cpp | 61 +++++++------------ interface/src/commerce/Wallet.h | 5 -- 6 files changed, 22 insertions(+), 67 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 44d3d54f58..fd7ce0fdfd 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -43,10 +43,6 @@ Item { calculatePendingAndInvalidated(); } - - if (transactionHistoryModel.count === 0) { - commerce.setMustRegenerateKeypair(true); - } refreshTimer.start(); } } diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index b344e00430..49ae1bc18c 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -43,6 +43,7 @@ QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) { #define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply& reply) { emit NAME##Result(failResponse(#NAME, reply)); } #define Handler(NAME) ApiHandler(NAME) FailHandler(NAME) Handler(buy) +Handler(receiveAt) Handler(balance) Handler(inventory) @@ -89,18 +90,6 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure); } -void Ledger::receiveAtSuccess(QNetworkReply& reply) { - auto wallet = DependencyManager::get(); - QByteArray response = reply.readAll(); - QJsonObject data = QJsonDocument::fromJson(response).object(); - - // ZRF FIXME! Change to something like `data["status"] == fail` - // Not on "The List" for receiving HFC - if (true) { - wallet->setMustRegenerateKeypair(true); - } -} -void Ledger::receiveAtFailure(QNetworkReply& reply) { failResponse("receiveAt", reply); } bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index ebd2d9ae7c..f29e46d843 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -57,11 +57,6 @@ void QmlCommerce::getWalletAuthenticatedStatus() { emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase()); } -void QmlCommerce::setMustRegenerateKeypair(const bool& val) { - auto wallet = DependencyManager::get(); - wallet->setMustRegenerateKeypair(val); -} - void QmlCommerce::getSecurityImage() { auto wallet = DependencyManager::get(); wallet->getSecurityImage(); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index a4e2ab8f42..d4f4aa35d2 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -54,7 +54,6 @@ protected: Q_INVOKABLE void getKeyFilePathIfExists(); Q_INVOKABLE void getSecurityImage(); Q_INVOKABLE void getWalletAuthenticatedStatus(); - Q_INVOKABLE void setMustRegenerateKeypair(const bool& val); Q_INVOKABLE void chooseSecurityImage(const QString& imageFile); Q_INVOKABLE void setPassphrase(const QString& passphrase); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 05c356cea9..9bc8dc9e43 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -324,19 +324,9 @@ Wallet::Wallet() { connect(ledger.data(), &Ledger::accountResult, this, [&]() { auto wallet = DependencyManager::get(); - auto ledger = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint status; - if (_mustRegenerateKeypair || getKeyFilePath() == "") { - qCDebug(commerce) << "Regenerating keys and resetting user_hfc_account. _mustRegenerateKeypair:" - << _mustRegenerateKeypair << "keyFilePath:" << getKeyFilePath(); - _mustRegenerateKeypair = false; - resetKeysOnly(); - ledger->reset(); // Hits `reset_user_hfc_account` endpoint - generateKeyPair(); // Hits `receive_at` endpoint - } - if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) { status = (uint)WalletStatus::WALLET_STATUS_NOT_SET_UP; } else if (!wallet->walletIsAuthenticatedWithPassphrase()) { @@ -535,32 +525,25 @@ bool Wallet::generateKeyPair() { // FIXME: initialize OpenSSL elsewhere soon initialize(); - qCInfo(commerce) << "Generating keypair..."; - QPair keyPair = generateRSAKeypair(); + qCInfo(commerce) << "Generating keypair."; + auto keyPair = generateRSAKeypair(); + + writeBackupInstructions(); + + // TODO: redo this soon -- need error checking and so on + writeSecurityImage(_securityImage, keyFilePath()); QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last(); - if (keyPair.first) { - writeBackupInstructions(); + QString key = keyPair.first->toBase64(); + _publicKeys.push_back(key); + qCDebug(commerce) << "public key:" << key; - // TODO: redo this soon -- need error checking and so on - if (_securityImage) { - writeSecurityImage(_securityImage, keyFilePath()); - } - - QString key = keyPair.first->toBase64(); - _publicKeys.push_back(key); - qCDebug(commerce) << "public key:" << key; - - // It's arguable whether we want to change the receiveAt every time, but: - // 1. It's certainly needed the first time, when createIfNeeded answers true. - // 2. It is maximally private, and we can step back from that later if desired. - // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. - auto ledger = DependencyManager::get(); - QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); - return ledger->receiveAt(key, oldKey, machineFingerprint); - } else { - qCDebug(commerce) << "Failure generating keys!"; - return false; - } + // It's arguable whether we want to change the receiveAt every time, but: + // 1. It's certainly needed the first time, when createIfNeeded answers true. + // 2. It is maximally private, and we can step back from that later if desired. + // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. + auto ledger = DependencyManager::get(); + QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); + return ledger->receiveAt(key, oldKey, machineFingerprint); } QStringList Wallet::listPublicKeys() { @@ -678,13 +661,9 @@ QString Wallet::getKeyFilePath() { } } -void Wallet::resetKeysOnly() { +void Wallet::reset() { _publicKeys.clear(); - QFile keyFile(keyFilePath()); - keyFile.remove(); -} -void Wallet::reset() { delete _securityImage; _securityImage = nullptr; @@ -692,7 +671,9 @@ void Wallet::reset() { updateImageProvider(); _passphrase->clear(); - resetKeysOnly(); + + QFile keyFile(keyFilePath()); + keyFile.remove(); } bool Wallet::writeWallet(const QString& newPassphrase) { RSA* keys = readKeys(keyFilePath().toStdString().c_str()); diff --git a/interface/src/commerce/Wallet.h b/interface/src/commerce/Wallet.h index f0f13aaf6e..ed145df451 100644 --- a/interface/src/commerce/Wallet.h +++ b/interface/src/commerce/Wallet.h @@ -49,7 +49,6 @@ public: bool walletIsAuthenticatedWithPassphrase(); bool changePassphrase(const QString& newPassphrase); - void resetKeysOnly(); void reset(); void getWalletStatus(); @@ -60,8 +59,6 @@ public: WALLET_STATUS_READY }; - void setMustRegenerateKeypair(const bool& val) { _mustRegenerateKeypair = val; } - signals: void securityImageResult(bool exists); void keyFilePathIfExistsResult(const QString& path); @@ -86,8 +83,6 @@ private: bool writeBackupInstructions(); void account(); - - bool _mustRegenerateKeypair { false }; }; #endif // hifi_Wallet_h From c5c1ead4003efc2e638ddd85d3a7ddf6eb1d42de Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 9 Nov 2017 10:51:21 +1300 Subject: [PATCH 095/171] Fix GOTO dialog's connection status and location not always updating --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 6 +++--- interface/src/ui/AddressBarDialog.cpp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 4e546ffa0d..5f1fa2900c 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -84,7 +84,6 @@ StackView { anchors.centerIn = parent; } - function resetAfterTeleport() { //storyCardFrame.shown = root.shown = false; } @@ -135,7 +134,8 @@ StackView { bottom: parent.bottom } - onHostChanged: updateLocationTextTimer.start(); + onHostChanged: updateLocationTextTimer.restart(); + Rectangle { id: navBar width: parent.width @@ -358,7 +358,7 @@ StackView { // Delay updating location text a bit to avoid flicker of content and so that connection status is valid. id: updateLocationTextTimer running: false - interval: 500 // ms + interval: 1000 // ms repeat: false onTriggered: updateLocationText(false); } diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 8b5e255b06..1a23674fa3 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -40,6 +40,10 @@ AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(pare _backEnabled = !(DependencyManager::get()->getBackStack().isEmpty()); _forwardEnabled = !(DependencyManager::get()->getForwardStack().isEmpty()); connect(addressManager.data(), &AddressManager::hostChanged, this, &AddressBarDialog::hostChanged); + auto nodeList = DependencyManager::get(); + const DomainHandler& domainHandler = nodeList->getDomainHandler(); + connect(&domainHandler, &DomainHandler::connectedToDomain, this, &AddressBarDialog::hostChanged); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &AddressBarDialog::hostChanged); connect(DependencyManager::get().data(), &DialogsManager::setUseFeed, this, &AddressBarDialog::setUseFeed); connect(qApp, &Application::receivedHifiSchemeURL, this, &AddressBarDialog::receivedHifiSchemeURL); } From 796388dfb47d70080c1e0f59a35b939dc4e951a6 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 8 Nov 2017 14:50:15 -0800 Subject: [PATCH 096/171] reverted a line to match current master --- libraries/ui/src/OffscreenUi.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 96272c4f1f..297ed9ca50 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -720,8 +720,7 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) { return QString(); } qCDebug(uiLogging) << result.toString(); - // originally was result.toUrl().toLocalFile();, but toLocalFile() is not working - return result.toString(); + return result.toUrl().toLocalFile(); } ModalDialogListener* OffscreenUi::fileDialogAsync(const QVariantMap& properties) { From 45b9a150dca0954fccb817a6c3f0582ae95c2dc5 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 8 Nov 2017 15:21:48 -0800 Subject: [PATCH 097/171] updated blocks url refs in application to fix download issue --- interface/src/Application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f051697ad..b21588958e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2693,7 +2693,7 @@ bool Application::importFromZIP(const QString& filePath) { qDebug() << "A zip file has been dropped in: " << filePath; QUrl empty; // handle Blocks download from Marketplace - if (filePath.contains("vr.google.com/downloads")) { + if (filePath.contains("poly.google.com/downloads")) { addAssetToWorldFromURL(filePath); } else { qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true, false); @@ -6235,7 +6235,7 @@ void Application::addAssetToWorldFromURL(QString url) { if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. } - if (url.contains("vr.google.com/downloads")) { + if (url.contains("poly.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { filename.remove(".zip?noDownload=false"); @@ -6270,7 +6270,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { if (url.contains("filename")) { filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. } - if (url.contains("vr.google.com/downloads")) { + if (url.contains("poly.google.com/downloads")) { filename = url.section('/', -1); if (url.contains("noDownload")) { filename.remove(".zip?noDownload=false"); From dac2ae19a427fc64450c129cd7481d145102d463 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Wed, 8 Nov 2017 12:24:16 -0500 Subject: [PATCH 098/171] [Case 6569] Add protection for dynamic vs static collision type (details below). When creating a model, it was possible to elect Exact collision with the dynamic property even though this combination is prohibited. This combination would silently fail rather than notifying the user of the error. This commit implements safeguards against the invalid combination: * If the user elects the Exact collision type and the dynamic field is unchecked, then dynamic field is disabled. * If the user elects a different collision type and the dynamic filed is unchecked, then the dynamic field is enabled. * If the user has checked the dynamic field and subsequently elects the Exact collision type, then the selection is void and the previous collision selection is retained; however, an error dialog is presented informing the user of the error. Changes Committed: modified: interface/resources/qml/hifi/tablet/NewModelDialog.qml --- .../qml/hifi/tablet/NewModelDialog.qml | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 47d28486a9..e6459fe7bb 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -11,8 +11,11 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs + import "../../styles-uit" import "../../controls-uit" +import "../dialogs" Rectangle { id: newModelDialog @@ -25,6 +28,15 @@ Rectangle { property bool punctuationMode: false property bool keyboardRasied: false + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); + } + Item { id: column1 anchors.rightMargin: 10 @@ -98,7 +110,6 @@ Rectangle { CheckBox { id: dynamic text: qsTr("Dynamic") - } Row { @@ -139,15 +150,39 @@ Rectangle { ComboBox { id: collisionType + + property int priorIndex: 0 + property string staticMeshCollisionText: "Exact - All polygons" + property var collisionArray: ["No Collision", + "Basic - Whole model", + "Good - Sub-meshes", + staticMeshCollisionText, + "Box", + "Sphere"] + width: 200 z: 100 transformOrigin: Item.Center - model: ["No Collision", - "Basic - Whole model", - "Good - Sub-meshes", - "Exact - All polygons", - "Box", - "Sphere"] + model: collisionArray + + onCurrentIndexChanged: { + if (collisionArray[currentIndex] === staticMeshCollisionText) { + + if (dynamic.checked) { + currentIndex = priorIndex; + + errorMessageBox("Models with Automatic Collisions set to \"" + staticMeshCollisionText + "\" cannot be dynamic."); + //--EARLY EXIT--( Can't have a static mesh model that's dynamic ) + return; + } + + dynamic.enabled = false; + } else { + dynamic.enabled = true; + } + + priorIndex = currentIndex; + } } Row { From a057cb914f65c37b3ac7b4a823488c9068ae8e1c Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Wed, 8 Nov 2017 14:18:04 -0500 Subject: [PATCH 099/171] [Case 6569] Fixes clipping of cancel button by window edge. Changes Committed: modified: interface/resources/qml/hifi/tablet/NewModelDialog.qml --- interface/resources/qml/hifi/tablet/NewModelDialog.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index e6459fe7bb..da77464325 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -128,6 +128,7 @@ Rectangle { Text { id: text2 width: 160 + x: dynamic.width / 2 color: "#ffffff" text: qsTr("Models with automatic collisions set to 'Exact' cannot be dynamic, and should not be used as floors") wrapMode: Text.WordWrap @@ -190,10 +191,10 @@ Rectangle { width: 200 height: 400 spacing: 5 - - anchors { - rightMargin: 15 - } + + anchors.horizontalCenter: column3.horizontalCenter + anchors.horizontalCenterOffset: -20 + Button { id: button1 text: qsTr("Add") From 0e90c92cf5038c732cc2449fd39a4b840da9eee6 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Wed, 8 Nov 2017 18:35:12 -0500 Subject: [PATCH 100/171] [Case 6569] Minor: Break up line to pass column count guidelines. Changes Committed: modified: interface/resources/qml/hifi/tablet/NewModelDialog.qml --- interface/resources/qml/hifi/tablet/NewModelDialog.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index da77464325..3debc8b9e7 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -172,7 +172,8 @@ Rectangle { if (dynamic.checked) { currentIndex = priorIndex; - errorMessageBox("Models with Automatic Collisions set to \"" + staticMeshCollisionText + "\" cannot be dynamic."); + errorMessageBox("Models with Automatic Collisions set to \"" + + staticMeshCollisionText + "\" cannot be dynamic."); //--EARLY EXIT--( Can't have a static mesh model that's dynamic ) return; } From c1b5d009934ba5f8529807abd4bf2d5e96b58547 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 15:41:24 -0800 Subject: [PATCH 101/171] Converted 'Background Blend' control to a slider. --- scripts/system/html/entityProperties.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 7fdeee67d3..0b96b59ddb 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -587,8 +587,8 @@

- - + +
From 5c7ebc0af3151e3fe93117f39565fc30751b0b89 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 16:44:05 -0800 Subject: [PATCH 102/171] Converted 'Glare Angle' control to a slider. --- scripts/system/html/entityProperties.html | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 0b96b59ddb..dba6b7e792 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -587,8 +587,11 @@

- - + + + + +
@@ -612,8 +615,11 @@

- - + + + +
+
From 7cb9514feb96eb5440f42001009f17a040cd58f3 Mon Sep 17 00:00:00 2001 From: Nissim Hadar Date: Wed, 8 Nov 2017 16:50:44 -0800 Subject: [PATCH 103/171] Converted 'Glare Angle' control to a slider. --- scripts/system/html/entityProperties.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index dba6b7e792..9453b476ee 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -557,8 +557,8 @@
- < - /div> + +
From 19b7c6e025113eceeb40d2b1fbb1ce39543a011e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 8 Nov 2017 17:14:14 -0800 Subject: [PATCH 104/171] Remove machine fingerprint from receiveAt --- interface/src/commerce/Ledger.cpp | 10 ++-------- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/Wallet.cpp | 4 +--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 49ae1bc18c..904847cb5f 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -90,7 +90,7 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure); } -bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint) { +bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) { auto accountManager = DependencyManager::get(); if (!accountManager->isLoggedIn()) { qCWarning(commerce) << "Cannot set receiveAt when not logged in."; @@ -99,13 +99,7 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key, const QSt return false; // We know right away that we will fail, so tell the caller. } - QJsonObject transaction; - transaction["public_key"] = hfc_key; - transaction["machine_fingerprint"] = machine_fingerprint; - QJsonDocument transactionDoc{ transaction }; - auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); - - signedSend("transaction", transactionString, old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); + signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure"); return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in. } diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index 54f3f780f3..42eb0ffc49 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -26,7 +26,7 @@ class Ledger : public QObject, public Dependency { public: void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false); - bool receiveAt(const QString& hfc_key, const QString& old_key, const QString& machine_fingerprint); + bool receiveAt(const QString& hfc_key, const QString& old_key); void balance(const QStringList& keys); void inventory(const QStringList& keys); void history(const QStringList& keys); diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 9bc8dc9e43..85632ff8f1 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -16,7 +16,6 @@ #include "ui/ImageProvider.h" #include "scripting/HMDScriptingInterface.h" -#include #include #include #include @@ -542,8 +541,7 @@ bool Wallet::generateKeyPair() { // 2. It is maximally private, and we can step back from that later if desired. // 3. It maximally exercises all the machinery, so we are most likely to surface issues now. auto ledger = DependencyManager::get(); - QString machineFingerprint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); - return ledger->receiveAt(key, oldKey, machineFingerprint); + return ledger->receiveAt(key, oldKey); } QStringList Wallet::listPublicKeys() { From 1791ed01ca050d9c9ff505610a12c7b8871c9d07 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 8 Nov 2017 18:35:26 -0700 Subject: [PATCH 105/171] add width param to vertex shader --- interface/src/raypick/LaserPointer.cpp | 11 ++++++----- interface/src/ui/overlays/Line3DOverlay.cpp | 10 +--------- interface/src/ui/overlays/Line3DOverlay.h | 3 --- libraries/render-utils/src/GeometryCache.cpp | 6 +++--- libraries/render-utils/src/GeometryCache.h | 4 ++-- libraries/render-utils/src/glowLine.slf | 3 +-- libraries/render-utils/src/glowLine.slv | 6 ++---- 7 files changed, 15 insertions(+), 28 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 5f2549deea..14af9b336f 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -14,6 +14,8 @@ #include "avatar/AvatarManager.h" #include "RayPickScriptingInterface.h" +static const float DEFAULT_LASER_POINTER_SIZE = 0.02f; + LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : _renderingEnabled(enabled), @@ -163,11 +165,10 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter pathProps.insert("end", end); pathProps.insert("visible", true); pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays()); - if (_scaleWithAvatar) { - auto glowScaleProp = qApp->getOverlays().getProperty(renderState.getPathID(), "glowScale").value; - float glowScale = glowScaleProp.isValid() ? avatarScale * glowScaleProp.toFloat() : avatarScale; - pathProps.insert("glowScale", glowScale); - } + + float glowWidth = _scaleWithAvatar ? DEFAULT_LASER_POINTER_SIZE * avatarScale : DEFAULT_LASER_POINTER_SIZE; + pathProps.insert("glowWidth", glowWidth); + qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps); } if (!renderState.getEndID().isNull()) { diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 0dc8fddd04..82a3c46727 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -35,7 +35,6 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : _endParentJointIndex = line3DOverlay->getEndJointIndex(); _glow = line3DOverlay->getGlow(); _glowWidth = line3DOverlay->getGlowWidth(); - _glowScale = line3DOverlay->getGlowScale(); } Line3DOverlay::~Line3DOverlay() { @@ -146,7 +145,7 @@ void Line3DOverlay::render(RenderArgs* args) { geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID); } else { // renderGlowLine handles both glow = 0 and glow > 0 cases - geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _glowScale, _geometryCacheID); + geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _geometryCacheID); } } } @@ -244,13 +243,6 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) { if (glowWidth.isValid()) { setGlowWidth(glowWidth.toFloat()); } - - auto glowScale = properties["glowScale"]; - if (glowScale.isValid()) { - float gscale = glowScale.toFloat(); - setGlowScale(gscale); - } - } QVariant Line3DOverlay::getProperty(const QString& property) { diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index 39e6436683..bcb65b1f1e 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -33,7 +33,6 @@ public: glm::vec3 getEnd() const; const float& getGlow() const { return _glow; } const float& getGlowWidth() const { return _glowWidth; } - const float& getGlowScale() const { return _glowScale; } // setters void setStart(const glm::vec3& start); @@ -44,7 +43,6 @@ public: void setGlow(const float& glow) { _glow = glow; } void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; } - void setGlowScale(const float& glowScale) { _glowScale = glowScale; } void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; @@ -74,7 +72,6 @@ private: float _glow { 0.0 }; float _glowWidth { 0.0 }; - float _glowScale { 1.0 }; int _geometryCacheID; }; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 90b3ca402d..ebf0f13d97 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1868,7 +1868,7 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color, float glowIntensity, float glowWidth, float glowScale, int id) { + const glm::vec4& color, float glowIntensity, float glowWidth, int id) { // Disable glow lines on OSX #ifndef Q_OS_WIN @@ -1931,10 +1931,10 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const vec4 p1; vec4 p2; vec4 color; - float scale; + float width; }; - LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color, glowScale }; + LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color, glowWidth }; details.uniformBuffer->resize(sizeof(LineData)); details.uniformBuffer->setSubData(0, lineData); } diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index a325026914..cd8c43f1df 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -314,10 +314,10 @@ public: const glm::vec4& color1, const glm::vec4& color2, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, - const glm::vec4& color, float glowIntensity, float glowWidth, float glowScale, int id); + const glm::vec4& color, float glowIntensity, float glowWidth, int id); void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, int id) - { renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, 1.0f, id); } + { renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, id); } void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, int id) { renderDashedLine(batch, start, end, color, 0.05f, 0.025f, id); } diff --git a/libraries/render-utils/src/glowLine.slf b/libraries/render-utils/src/glowLine.slf index be1c6842e3..6a7a6157a4 100644 --- a/libraries/render-utils/src/glowLine.slf +++ b/libraries/render-utils/src/glowLine.slf @@ -10,7 +10,6 @@ // in vec4 _color; -in float _scale; in float distanceFromCenter; out vec4 _fragColor; @@ -22,7 +21,7 @@ void main(void) { float alpha = 1.0 - abs(distanceFromCenter); // Convert from a linear alpha curve to a sharp peaked one - alpha = _color.a * pow(alpha, 10.0/_scale); + alpha = _color.a * pow(alpha, 10.0); // Drop everything where the curve falls off to nearly nothing if (alpha <= 0.05) { diff --git a/libraries/render-utils/src/glowLine.slv b/libraries/render-utils/src/glowLine.slv index 7b69943b7a..4532ed7b9f 100644 --- a/libraries/render-utils/src/glowLine.slv +++ b/libraries/render-utils/src/glowLine.slv @@ -16,17 +16,15 @@ layout(std140) uniform lineData { vec4 p1; vec4 p2; vec4 color; - float scale; + float width; }; out vec4 _color; -out float _scale; // the distance from the center in 'quad space' out float distanceFromCenter; void main(void) { _color = color; - _scale = scale; TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); @@ -42,7 +40,7 @@ void main(void) { // Find the vector from the eye to one of the points vec3 v2 = normalize(p1eye.xyz); // The orthogonal vector is the cross product of these two - vec3 orthogonal = cross(v1, v2) * 0.02; + vec3 orthogonal = cross(v1, v2) * width; // Deteremine which end to emit based on the vertex id (even / odd) vec4 eye = (0 == gl_VertexID % 2) ? p1eye : p2eye; From 6d019b43029d579ea1f01502f13b9b743492a5dd Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 8 Nov 2017 18:16:42 -0800 Subject: [PATCH 106/171] Update the audio codecs --- cmake/externals/hifiAudioCodec/CMakeLists.txt | 76 +++++++++---------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/cmake/externals/hifiAudioCodec/CMakeLists.txt b/cmake/externals/hifiAudioCodec/CMakeLists.txt index a30396c6fd..808a6174ca 100644 --- a/cmake/externals/hifiAudioCodec/CMakeLists.txt +++ b/cmake/externals/hifiAudioCodec/CMakeLists.txt @@ -5,43 +5,41 @@ set(EXTERNAL_NAME hifiAudioCodec) string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -if (NOT ANDROID) - - if (WIN32 OR APPLE) - ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-1.zip - URL_MD5 23ec3fe51eaa155ea159a4971856fc13 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 - ) - else () - ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux.zip - URL_MD5 7d37914a18aa4de971d2f45dd3043bde - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD 1 - ) - endif() - - # Hide this external target (for ide users) - set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - - ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - - set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) - - if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL) - elseif(APPLE) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) - elseif(NOT ANDROID) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) - endif() - +if (WIN32) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-win-2.0.zip) + set(DOWNLOAD_MD5 9199d4dbd6b16bed736b235efe980e67) +elseif (APPLE) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-mac-2.0.zip) + set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba) +elseif (UNIX) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip) + set(DOWNLOAD_MD5 988194f22f8d064c53d548259f426dce) +elseif (ANDROID) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip) + set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683) +else() + return() +endif() + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL ${DOWNLOAD_URL} + URL_MD5 ${DOWNLOAD_MD5} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE INTERNAL) + +if (WIN32) + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/audio.lib CACHE TYPE INTERNAL) +else() + set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/Release/libaudio.a CACHE TYPE INTERNAL) endif() From bccd6df57c14c6586218597db4fcc9bc61a4676f Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 9 Nov 2017 11:19:28 +0100 Subject: [PATCH 107/171] Fixed warning on Mac and Ubuntu --- libraries/render/src/render/BlurTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 54ec531c8b..2be6f8fad2 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -137,8 +137,8 @@ void BlurParams::setLinearDepthPosFar(float farPosDepth) { BlurInOutResource::BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor) : -_generateOutputFramebuffer(generateOutputFramebuffer), -_downsampleFactor(downsampleFactor) { + _downsampleFactor(downsampleFactor), + _generateOutputFramebuffer(generateOutputFramebuffer) { assert(downsampleFactor > 0); } From 4f7ed38e98e2c49a3764a608dabaee7cbb8bfaaa Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 9 Nov 2017 11:26:08 +0100 Subject: [PATCH 108/171] Fixed potential link errors on Mac --- libraries/render-utils/src/BackgroundStage.cpp | 1 + libraries/render-utils/src/BackgroundStage.h | 2 +- libraries/render-utils/src/HazeStage.cpp | 1 + libraries/render-utils/src/HazeStage.h | 2 +- libraries/render-utils/src/LightStage.cpp | 1 + libraries/render-utils/src/LightStage.h | 2 +- libraries/render/src/render/HighlightStage.cpp | 1 + libraries/render/src/render/HighlightStage.h | 2 +- libraries/render/src/render/TransitionStage.cpp | 1 + libraries/render/src/render/TransitionStage.h | 2 +- 10 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/BackgroundStage.cpp b/libraries/render-utils/src/BackgroundStage.cpp index 2ea3683c4a..2d2c0ed150 100644 --- a/libraries/render-utils/src/BackgroundStage.cpp +++ b/libraries/render-utils/src/BackgroundStage.cpp @@ -14,6 +14,7 @@ #include std::string BackgroundStage::_stageName { "BACKGROUND_STAGE"}; +const BackgroundStage::Index BackgroundStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const { auto found = _backgroundMap.find(background); diff --git a/libraries/render-utils/src/BackgroundStage.h b/libraries/render-utils/src/BackgroundStage.h index eab7c94f0d..4e0e09db5b 100644 --- a/libraries/render-utils/src/BackgroundStage.h +++ b/libraries/render-utils/src/BackgroundStage.h @@ -27,7 +27,7 @@ public: static const std::string& getName() { return _stageName; } using Index = render::indexed_container::Index; - static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + static const Index INVALID_INDEX; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } using BackgroundPointer = model::SunSkyStagePointer; diff --git a/libraries/render-utils/src/HazeStage.cpp b/libraries/render-utils/src/HazeStage.cpp index 7a12ee3c8a..016282d16f 100644 --- a/libraries/render-utils/src/HazeStage.cpp +++ b/libraries/render-utils/src/HazeStage.cpp @@ -14,6 +14,7 @@ #include std::string HazeStage::_stageName { "HAZE_STAGE"}; +const HazeStage::Index HazeStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; FetchHazeStage::FetchHazeStage() { _haze = std::make_shared(); diff --git a/libraries/render-utils/src/HazeStage.h b/libraries/render-utils/src/HazeStage.h index 102f299d8f..c355f06644 100644 --- a/libraries/render-utils/src/HazeStage.h +++ b/libraries/render-utils/src/HazeStage.h @@ -28,7 +28,7 @@ public: static const std::string& getName() { return _stageName; } using Index = render::indexed_container::Index; - static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + static const Index INVALID_INDEX; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } using HazePointer = model::HazePointer; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 079c63f367..c280abfeaf 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -14,6 +14,7 @@ #include "LightStage.h" std::string LightStage::_stageName { "LIGHT_STAGE"}; +const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; LightStage::LightStage() { } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 66d73c9a6e..c26f504658 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -32,7 +32,7 @@ public: static const std::string& getName() { return _stageName; } using Index = render::indexed_container::Index; - static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + static const Index INVALID_INDEX; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } using LightPointer = model::LightPointer; diff --git a/libraries/render/src/render/HighlightStage.cpp b/libraries/render/src/render/HighlightStage.cpp index 6821504649..ade3844321 100644 --- a/libraries/render/src/render/HighlightStage.cpp +++ b/libraries/render/src/render/HighlightStage.cpp @@ -3,6 +3,7 @@ using namespace render; std::string HighlightStage::_name("Highlight"); +const HighlightStage::Index HighlightStage::INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; HighlightStage::Index HighlightStage::addHighlight(const std::string& selectionName, const HighlightStyle& style) { Highlight outline{ selectionName, style }; diff --git a/libraries/render/src/render/HighlightStage.h b/libraries/render/src/render/HighlightStage.h index 7600f1f724..b35fff654c 100644 --- a/libraries/render/src/render/HighlightStage.h +++ b/libraries/render/src/render/HighlightStage.h @@ -35,7 +35,7 @@ namespace render { static const std::string& getName() { return _name; } using Index = render::indexed_container::Index; - static const Index INVALID_INDEX{ render::indexed_container::INVALID_INDEX }; + static const Index INVALID_INDEX; using HighlightIdList = render::indexed_container::Indices; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } diff --git a/libraries/render/src/render/TransitionStage.cpp b/libraries/render/src/render/TransitionStage.cpp index 33ef829c64..9ddc72f4db 100644 --- a/libraries/render/src/render/TransitionStage.cpp +++ b/libraries/render/src/render/TransitionStage.cpp @@ -5,6 +5,7 @@ using namespace render; std::string TransitionStage::_name("Transition"); +const TransitionStage::Index TransitionStage::INVALID_INDEX{ indexed_container::INVALID_INDEX }; TransitionStage::Index TransitionStage::addTransition(ItemID itemId, Transition::Type type, ItemID boundId) { Transition transition; diff --git a/libraries/render/src/render/TransitionStage.h b/libraries/render/src/render/TransitionStage.h index 226d531d8b..1d10a5dedb 100644 --- a/libraries/render/src/render/TransitionStage.h +++ b/libraries/render/src/render/TransitionStage.h @@ -25,7 +25,7 @@ namespace render { static const std::string& getName() { return _name; } using Index = indexed_container::Index; - static const Index INVALID_INDEX{ indexed_container::INVALID_INDEX }; + static const Index INVALID_INDEX; using TransitionIdList = indexed_container::Indices; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } From 5507bcea3c0e1e90bfc1abf9b2c9251ce42b3568 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 9 Nov 2017 10:34:01 -0800 Subject: [PATCH 109/171] Remove hack for missing inttypes.h header on VS2010 --- libraries/avatars/src/AvatarData.h | 14 -------------- libraries/octree/src/OctreeQuery.h | 14 -------------- 2 files changed, 28 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 89fe270af1..d8169bb8f7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -15,21 +15,7 @@ #include #include #include - -/* VS2010 defines stdint.h, but not inttypes.h */ -#if defined(_MSC_VER) -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef signed long long int64_t; -typedef unsigned long long quint64; -#define PRId64 "I64d" -#else #include -#endif #include #include diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 81a63a696c..fc9ea525e6 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -12,21 +12,7 @@ #ifndef hifi_OctreeQuery_h #define hifi_OctreeQuery_h -/* VS2010 defines stdint.h, but not inttypes.h */ -#if defined(_MSC_VER) -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef signed long long int64_t; -typedef unsigned long long quint64; -#define PRId64 "I64d" -#else #include -#endif - #include #include From 9a1386bf0d9c1ee157f6b4ec199eb2c9c3479b87 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 9 Nov 2017 10:34:52 -0800 Subject: [PATCH 110/171] Fix build errors on Linux --- cmake/externals/hifiAudioCodec/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/hifiAudioCodec/CMakeLists.txt b/cmake/externals/hifiAudioCodec/CMakeLists.txt index 808a6174ca..298f666304 100644 --- a/cmake/externals/hifiAudioCodec/CMakeLists.txt +++ b/cmake/externals/hifiAudioCodec/CMakeLists.txt @@ -13,7 +13,7 @@ elseif (APPLE) set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba) elseif (UNIX) set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip) - set(DOWNLOAD_MD5 988194f22f8d064c53d548259f426dce) + set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481) elseif (ANDROID) set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip) set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683) From 9724a5e5b83d98e591e24b2f23110b025657a6ae Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 9 Nov 2017 10:53:36 -0800 Subject: [PATCH 111/171] Fix for address sanitizer warning This fixes a potential null pointer dereference. --- libraries/animation/src/Rig.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index acf7bf81d8..3dad4e3fb6 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -303,7 +303,9 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) { _rigToGeometryTransform = glm::inverse(_geometryToRigTransform); // rebuild cached default poses - buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); + if (_animSkeleton) { + buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); + } } } From 10f484c668263fa15855e220448680c68e816942 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 9 Nov 2017 12:21:23 -0700 Subject: [PATCH 112/171] 6944 Avatar scale is saved across domains --- interface/src/avatar/MyAvatar.cpp | 14 +++++++++++++- interface/src/avatar/MyAvatar.h | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 76205bdde9..0dfcf93a65 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -135,7 +135,7 @@ MyAvatar::MyAvatar(QThread* thread) : connect(&domainHandler, &DomainHandler::settingsReceived, this, &MyAvatar::restrictScaleFromDomainSettings); // when we leave a domain we lift whatever restrictions that domain may have placed on our scale - connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::clearScaleRestriction); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::leaveDomain); _bodySensorMatrix = deriveBodyFromHMDSensor(); @@ -2279,6 +2279,18 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings settings.endGroup(); } +void MyAvatar::leaveDomain() { + clearScaleRestriction(); + saveAvatarScale(); +} + +void MyAvatar::saveAvatarScale() { + Settings settings; + settings.beginGroup("Avatar"); + settings.setValue("scale", _targetScale); + settings.endGroup(); +} + void MyAvatar::clearScaleRestriction() { _domainMinimumScale = MIN_AVATAR_SCALE; _domainMaximumScale = MAX_AVATAR_SCALE; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 288e6dd638..9133b967fa 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -561,6 +561,8 @@ public slots: float getDomainMinScale(); float getDomainMaxScale(); + void leaveDomain(); + void setGravity(float gravity); float getGravity(); @@ -638,6 +640,8 @@ private: virtual int parseDataFromBuffer(const QByteArray& buffer) override; virtual glm::vec3 getSkeletonPosition() const override; + void saveAvatarScale(); + glm::vec3 getScriptedMotorVelocity() const { return _scriptedMotorVelocity; } float getScriptedMotorTimescale() const { return _scriptedMotorTimescale; } QString getScriptedMotorFrame() const; From 119c66289931b385982ee4bb56f5126ef4c0e0cf Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 9 Nov 2017 11:46:19 -0800 Subject: [PATCH 113/171] fixed null file path in file dialog call --- libraries/ui/src/OffscreenUi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 297ed9ca50..252c08a1f0 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -720,7 +720,7 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) { return QString(); } qCDebug(uiLogging) << result.toString(); - return result.toUrl().toLocalFile(); + return result.toString(); } ModalDialogListener* OffscreenUi::fileDialogAsync(const QVariantMap& properties) { From 2c542b73a06bb011b95e4b1bd76e0fa8d3f1fd49 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Nov 2017 10:22:35 +1300 Subject: [PATCH 114/171] Fix particles emitter rendering not updating when edit textures URL --- libraries/entities/src/ParticleEffectEntityItem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index b216144ded..c2e29dd44f 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -97,7 +97,8 @@ bool operator==(const Properties& a, const Properties& b) { (a.maxParticles == b.maxParticles) && (a.emission == b.emission) && (a.polar == b.polar) && - (a.azimuth == b.azimuth); + (a.azimuth == b.azimuth) && + (a.textures == b.textures); } bool operator!=(const Properties& a, const Properties& b) { From c53c356842090db17e55cb39595f3e2394e14afa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Nov 2017 10:23:35 +1300 Subject: [PATCH 115/171] Display "no preview available" for ATP images in particles UI --- scripts/system/particle_explorer/hifi-entity-ui.js | 11 ++++++++++- scripts/system/particle_explorer/particle-style.css | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/system/particle_explorer/hifi-entity-ui.js b/scripts/system/particle_explorer/hifi-entity-ui.js index a1d02e287d..abf9e3cce6 100644 --- a/scripts/system/particle_explorer/hifi-entity-ui.js +++ b/scripts/system/particle_explorer/hifi-entity-ui.js @@ -482,14 +482,23 @@ HifiEntityUI.prototype = { textureImage.className = "texture-image no-texture"; var image = document.createElement("img"); var imageLoad = _.debounce(function (url) { - if (url.length > 0) { + if (url.slice(0, 5).toLowerCase() === "atp:/") { + image.src = ""; + image.style.display = "none"; + textureImage.classList.remove("with-texture"); textureImage.classList.remove("no-texture"); + textureImage.classList.add("no-preview"); + } else if (url.length > 0) { + textureImage.classList.remove("no-texture"); + textureImage.classList.remove("no-preview"); textureImage.classList.add("with-texture"); image.src = url; image.style.display = "block"; } else { image.src = ""; image.style.display = "none"; + textureImage.classList.remove("with-texture"); + textureImage.classList.remove("no-preview"); textureImage.classList.add("no-texture"); } self.webBridgeSync(group.id, url); diff --git a/scripts/system/particle_explorer/particle-style.css b/scripts/system/particle_explorer/particle-style.css index e8b71fdba0..1e2801c19f 100644 --- a/scripts/system/particle_explorer/particle-style.css +++ b/scripts/system/particle_explorer/particle-style.css @@ -119,6 +119,10 @@ hr.splitter:last-of-type{ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAABhNJREFUeNrsnVFy4joQRVsSCwAqBMwqsrRsIavMEkICoeAf2+8j1R5ZGDBgpLzoUDVVmTT2dc8It/paOpi3t7faOSciImVZyn6/l6qqRETEWivj8VistYPFd7ud1HUtIiLGGBmPx5JKX0RkMplIzvmPnHNijBERaS7Ef1lrB40bY1oXgH5a/ZH+8P7+LlVVycfHR/MGa60URdGcYOi4MUaKomhGaGx9EZHlcplMP2X+Ly8vPwOgLEtxzklVVVJVVfOznqAsy9YFXhuvqqq5AF/Lj+srtr7+LpV+yvz1mNF+vxcRkdVqJdZaeXp6ap1ws9m0TjibzVoj6lJ8vV6fjJdlKev1ujViU+j7t8tc8p9Op1KWpYw06L9JL0Av0r9l+jXl3nhd11JV1VE8tn5YM3PI3xjzoxVOGvyDU7zQj6s/0tGmI++amtNV087F9Wf/FnVPzRtCXz8RdV1nlb/efUbaJy4Wi0FqzjU1yRgjs9ls0Jp3jb6IyPPzczL9lPkvFot/dwCtB/om/x9oyJoXxps65NW8mPpdNTeX/JtBEtYE/+AUL/Tj6g/qA3TVnD41a6g++Bp9rYOp9FPnH80HOBcvy1I2m81D++BL+o/2AX5r/vgA+AD4AOif8AH8EdpVcy71sX3jWp/8W2AKff/TkUv+Oufr9AF0YuKc66xJ18T7eNP3nP9WfZ0EzufzJPqp8y+KQuq67vYBdETqCDpVU/rEw5oUnr+rD46h73/qUuinzh8fAP22D6AjxznXcqq6akrf+KmaFB6vf4+t7/sAelfIJf/GB9jtdmKMkdVq1dQM3zg4VVNU/NY+1Bgjh8Oh6YM1+dj6X19fzXwgp/wbH0DFtS7oyf0RdKqmhPFr+1RdseKfP7a+Px/IKX98APTbPoDOJrv60L417d54TH3V8lfS5pT/yfUA6/X6qOZcqkm3xrUm6X9CTH3fB0ihnzr/Ix9A/3T1qbfWpGvjMfX9T0UK/dT54wOg/88H8EfGPTVr6D740frhLDmn/Hv5AH1qku9t31KTzh3/aP1LPsBfzr+XDxCO0K6ack/N6qp5MfUv+QB/Of/ePsCQfWmfc6EfV3/kjzZrrRwOh9YtKHSm/LjOH3yrMTzej4c1y//51PHoP0a/tR7AOSdFURw9rz5VU049zw7jl2qWrosP++BY+iI/+wJS6afMv9kXoA6gvimsieHzZr/m6MTp3PPuc3G9SP95OPpx9JtOgT4cHwA+QCJ9+ADwAeADsC+AfQHo/4b1APAB4APAB4APAB8APgB9OD4AfAD4AFFqEnwA+AD4APgA6P86HwA+AHyAZhIBHwA+AHwA+AD04X/eB4APAB8APgB8APgA8AHow/P0AeADwAeADwAfAD4AfAD68Px8APgA8AHgA8AHgA8AH0DO70/v6lHvjaOfVn8U/iLcXx5OUML96X49vRTX3/nPw9FPo9+sB5hMJuKck+VyeVRTrLWtdfNdcf95eldNCuOfn5+tSYy/Pz+2voi0fICc8p/P5z93gJAPEN4+wufN4evaePj99eH+ePTj6p/1Abp60kt9Ksf/v46HDwAfAD6A/6gUPgD7AtgXwPP4DNcDwAeADwAfAD4AfAD4ADyPz289AHyA+Pqp84cPIPAB8AHwAfAB8AHgA7Q+HfAB4APAB4APAB+APjw3HwA+AHwA+ADwAeADwAegD8/TB4APAB8APgB8APgA8AHow/PzAeADwAeADwAfAD4AfACJ//316KfVH/mjLeb31+vx/kWhH0+/tR7AOSdFUUT9/nq9oK4+OJa+iLT25+eUf7MvIOQDxPr+en2F++PRj6PfdAr04fgA8AES6cMHgA8AH4B9AewLQP83rAeADwAfAD4AfAD4APAB6MPxAeADwAeIUpPgA8AHwAfAB0D/1/kA8AHgAzSTCPgA8AHgA8AHoA//8z4AfAD4APAB4APAB4APQB+epw8AHwA+AHwA+ADwAeAD0Ifn5wPAB4APAB8APgB8gBz5AOb19bX2TYLpdNpqQ7bbbctJGjJeVZVst9vWLSu2/vf3t+Sc/yicFIRr0C7Fu76f/lw8XBePflr9/wYAqWwWUSLcO54AAAAASUVORK5CYII='); } -.texture-image.no-texture{ +.texture-image.no-texture { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAB81JREFUeNrsnTGPm0oXht97FWm2Ch2pTEeHpUihsyvTuXO67Ta/IPkr+Qfp3MWdO7Zad0SKZDo6XIWOrTzV9xVXZ8SygGHXG4/t96lW68GGw8vMmZlzDv98+/btfyBXy780wXXzTv74/fs3rXFFfPz4kT0AoQAoAJqAAiAUAKEACAVAKABCARAKgFAAhAIgFAChAAgFQCgAQgEQCoBQAIQCIBQAoQAIBUAoAHLmvDv3C7i7u4PjOMiyDOv1+mC75XKJoiga2wRBAN/34TgOHMdBWZYoigJpmiLPcwrARhzHAQD4vg/P81pvlLRrwvM8zGYz00ZrbY5xHAe+7yPPc9zf36MsSwrAVmazGX78+DHoGM/zsFgsAAB5nmOz2ZgeQimF8XiMMAxNu+VyaQRCH8Ai8jyH4zgIw7D3MUopzOdzAECaplitVk+GB601kiTBz58/obWG4ziIoohOoI38+vULABCGYWd3X2U6nUIphbIsEcdxa7uiKPDw8GCGGtd1KQDbKMsSWZZBKYXJZNLrGN/3zdN/iDRNTdcvx1EAFqGUwmazeeIQduG6LpRSAIAsy3r9hrRjD2BxL5AkiXEI+8wetNa9PXtp13eIoQBOQJIkxmHrcgjlJkov8JKpJwVgIVpr47CFYdh6g/f7/ZM5/9CehgKwmDRNURQFlFKYTqeNN/rx8dH0AH2faBn7KYAzQKZ1QRCYZd0qf/78MX+PRqNe3ymO5W63owBsR9bwZShoGirEq++zeBQEweBZAwVwYh4eHqC1RhAErQ6jOHVdK3yu65qhJE1TDgHn5BDKTW6auxdFYdYOgiDAYrF40k4phTAM8fnzZyilUBRF54rhOfIOF06SJMYPaPt8v99jOp3C8zx4nget9bPZQ5ZlF3fzL0IAZVke9OLv7+/Njl/brCHLMozHY4xGI3z48MH0EEVRIMuyi40H+EdqBbNS6HXBSqGEAiAUAAVAE1AAhAIgFAChAAgFQCgAQgGQq+Eom0GLxeJgGHYVSdCUhM02yrI0qV5hGGIymaAsy9b0LNd1cXt7CwDYbDa98wOA/zKLVquVSQGr/nYTbe2iKDIh53JtZVmiLEvsdjtst9tn5z7EDmfXA3QFXdaTMbvYbrdm568tgkdueJ7njbt3QwJA+8YJ1tsFQQDXdXFzc2N2E0Uwk8kEX758eXbMEDtY2QOsVqtn//v69SsAYL1eH9xK7dNGgjuiKMJ4PH4WmSN7+QBMFu/3798bn1oAzz47NvVrqmYgz2azRpv1scNV+wDVaN969y6JIEmSWBmyJenlIgZbcgvOzgmUqJxqkmY18ldCvGwkz/MntQcogBcgETrVMV98Aptvfh1JTKEAXsBms4HWGp7nYT6fw3Ec5Hlufbi253lQSkFr3VqmhgLoQVmW2G63ZigQx8/2my/FKCR17WLWAV7LfD5vzOFLkqS1W0/T1HT9RVFY5/jNZjMz3ouvorVGHMet9QheYoer7AGq478Y2LaiDTc3N3Bd90megSwG2YQVPcDQ+a/ccK01ttutWSWsetl/i7bfq16TzP1lGFgul0exw9X2AJLGJV3joRXCl3rnXbUDhmQKl2WJ9XoNrbV1vdXZCUCWWqvVQGR8HFIgqmuaKUiCSJcA+nrzWmvzdA/ZN6EAKlTz/eXmA3iSuXOoNEzfBRsA+PTpU+PnUjxSfnvo9/ZNR6cAakjFj2rqd3VtQJ6u1z5h1e+SdYbqdK5aWHLImC0OoFQgpRN4YPoD/LfRVC8C2TQlkhVC3/dfVDG0/l1xHCOKIvi+b572atJoURSdtYnbfAHxV0aj0TP/oY8dzqYH6OscHXK26tO+rqcujmNTIKqtJkDfc0vTFMvl8smu436/R57niOO4NSbh0HfLkFHtpYbY4dgwOfRKYXIooQAIBUAB0AQUAKEACAVAKABCARAKgFAA5Gp4s93AKIrw/v17ExsnFEWB/X6P3W6HLMtaN0+GJkwOad+W2FlPLq3GHFSRdq85h2PYyGoByG6cvJOnHiEryZJSg7e+s1ZNmOyzSza0ffWYJsIwbMzk7Tp+6Dm81kZWC0BoCnSU7dowDE2K12q1alT60EDJYwVWKqUQRdHgPf9jnfMQG52dDyA5fLKnLlGztiB5Bn1eP3fuNvr31IaWZM9jhHIdEwk5G1Jk4hxtdPJZQJZlJrLWlnBpx3FMmrnrup3RReduIyumgXJxtryRUxw4mQXIO4Yv0UZWCMDWN3I2vX7u0mxk1RtDmp6yoQmTbe27kjK7iOMYt7e3CIIA2+22VyLIWyZ5Hrsnsmol0Jac+fo51QtSXJKNrOgBuvLsTrUOUO8FxAP3ff/gTXiLc3irt5aevAdQSpmpja0vZqq+fm4ymfz18i5vaaOTC0DSvapv8rQRmRY6joPxeHwxNjqpAGSpUwx8ikKJQ5AyNFKb4BJsdBIfwPM8BEFgFjXSNG3debMJSUv7GyuWf8tGby6Aaq2c+qvaJce/a3p2ioTJQ73A3d3di6aBbef8WhtZKQDJ6K1fTJ7neHx8PFjWTcbbvvPePm8QbVtc6ft/+UwKUdfbDT3n19roGDA59EphciihAAgFQAHQBBQAoQAIBUAoAEIBEAqAUACEAiAUAKEACAVAKABCARAKgFAAhAIgFAChAAgFQC4CkxgiceKEPQC5Iv4/APgB2O7x8IXXAAAAAElFTkSuQmCC'); } + +.texture-image.no-preview { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA8sSURBVHhe7Z3rbxXFG8d7B9SWthRabLmIYlHkIEXKJdXYBEXxHtEXprwxxsR3/jG+8PLCaDDGeAkmKsTEoCUVKoVCA6WNtLS2UEUKBSy0tKW/D+eZM9nu7tmz55z+mC2Zz4tl9tk5c2bnO/PMM2dnS+6nn36aYzFH7vvvv6+SFhMoAY4fPy7nljvG448/zjFPTiymsAIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjmLhQgPz+/pKRk3rx56jzaRHFf0ObNmxctWkTi7Nmzp0+fFqNm+/btRUVFP/30kzp3UFtbu27duqVLl+bl3e5Y169f7+rqam1tvXnzpmSIFNHdF1RTU7M6TkNDQ0FBgbImWLVqFZfUSQKyvfzyy88991x1dfXU1NSFCxdGRkbuueeeurq6pqam0tJSlS96RNcFSQvSo9V5IC+88MIDDzwwOjr6448/fvTRR19++eVnn322Z8+ev//+u7i4+M0331ywYIHKGjGiK8Aff/zBMRaL5ebmiiUZjz322MqVK/Ez33333ZkzZxgBYh8eHt67d++lS5do/W3btokxakRXANxIf38/3mPNmjXKlARxpkeOHKGtxaIZHx9vaWkhwfTg9WZRILoCgIQG0r7JKC8vlxm7s7NTLC6YyW/cuFFYWIiPUqYoEWkB+vr6cOJLlizBwyiTB2l9vA0xj1hcTE9PDw4OkiA6EkukiLQAcOzYMY4bN26UUy8LFy7k+O+//8qpL1euXOF43333yWmkiLoATKqEQwSmlZWVyjQTIiWOwZG+npYjSNQFwIG0tbWRqK+vF4sL1r0qlZzJyUmOYXLeeaIuAHR3d+PfmQbE27hgguUY3LgS/0RzHMwBAei/R48ezcvL8x0EOCiOxEJy6osoJ1JFjTkgAHR0dExMTBDLexe0EvsTKQUMgsWLF3OUWChqzA0BGARoQBN7wyHWa6Ojo1x6+OGHlWkmaEOoeuvWrXPnzilTlJgbAgBeiEEQi8W8Pf3kyZMct27d6v0JGsf15JNPkmA5lmyhYJY5IwAenNmYBW1RUZEyJSBMYiYoLi7etWtXWVmZsubkkHPHjh2EsCjX3NysrBFjzggANDSeRJ04wEF9//33rLYqKip27979yiuvNDY2Pvvss2+//TZ+ieBn//79V69eVbkjRv6WLVv4hxW/nEcB+iyuo6ura3x8XJnicIqToV8zGpgSlDXO2NhYZ2cnV+WnIVZtTLxEn+fPn9+3b180p9+qqiqOd9ub8ihH67M8xuPT65mf1YXocXe+KY+PGhoa6unp4Rjl1tfcbQLMOawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGyfy3oNdff72mpkadJLh27Vpvb29LS8vExIRYdu7c6dpLOz09ffPmTXLypadOnVLWnJzGxsZYLKZOPHR0dDQ3N7/33nv5+fkff/yx7/PFBQsWvPPOO5T/4YcfLly4sKmpaXBw8Ntvv5Wr7777bsAOUbINDw+Th5IpX1kTyGcPHz7c2tqqTHG4NW7wzz//9N2tHczs/BY0NjZ2PQFVLy4uXr9+/UsvvaQuJxgfH1eZ4tkKCwsrKiq2b9/u3XbozOkEzaamps6ePUueZHvcsOfl5ZFHtkH4oorzQOFU7MqVKzS0S6fy8nKxeDvckiVLOGbza2u22yW/+eYbOo46ie9Te/XVV5ctW7Z8+fK//vpLWXNyfvjhB2ctaaaGhoYNGzZs3bq1q6tLWeP88ssvdCh14oFLDz30EA3tuxFRhBGRkvHJJ5+olB8XLlxg6NCs/f39ypRo93/++Wfp0qWMP+fuCnna7N2TGp5ZngMQ48iRIyQefPBBsfhy69atgwcPjo6OlpSU+G42SQaicv80tPfBJBbslBwsQDBDQ0McpVk1CMBAx2HyFa79jUhFfeRTmTH7k7DsEky5DxBPffHiRRKytS0kNMTAwAAN4d0tigX7+fPnfaeHkEjlxbFoEIAvlTFRXV0tRhBnNTIy4hwT6TL7Asgz2zBvBUlO/K+chkQc1IoVK+RUI5YzZ87IaWZIX3buMpIJAP+Jroxv5zQgOmW52WL2BZDtyv/995+cJkMeHHJX6T42wcPgZ5gJ1HkCsWTjf4C+TCuXlpZqFyctLl6etpZpIH5F6eScAjNglgVg+n3iiSdIuHoiI/f2S19xamtrN23a9NprrzEVt7W1uSKWtWvXPu2HuhzfHkF/pFfef//9ypSTQxoLPi3lw3dV3Ez4UnU5/nicJpZuBAigvTzfyyU9DWQfAkG2UdCLL76oPeC99947f/58Et3d3cQMYhTk0b8TejGhfXt7uzpPgCfxuhf49ddfVSonp6enhyhr1apVeHyxkOYYxv8QJauUA9yaXpEQCKEH8zAJThGA1pd7lLamM0mCPNhl73vGZDsCGK10FgGffvnyZZYqP//8s7qcgCY7EUemMvz+F198ceDAAaZiyaA5duwYixov6nIcaWhpdEHSfIucBqCKm4m8hSDIBhHp3URoMgHEr9wefHoaYChw71qbjMlWgK+//pp1o/DBBx98/vnnLBfp3epyAmI4ujDs3bv3t99+I/J5/vnnfd++4/7pj17U5TjohzsuKysTL8yRNM5HwqpgVHEzce7KoYlpUynZO83qaYAOxzGbFYCQrQAsXOkXgrc7+4IYuA5WwgHvvaSEVuMoKy859vb23r6QNbQ+zof2Je2cAAQ9DYhCWU4AMPtRUBhko2B9fX1aiwAnEu3IakCOYfxPSFgN4HnwP7h7xHA6GT0NyFScZQgEZgRgimYyKCwsrKurU6Y0weHIbwO0FEfGX5bxuBPp8kR0jAPX22d8EY2Oa6qqqiJt3gVlzKFDhzjGYjFaUCzpgs/BGzQ2NnJkWg7pAMMg8Y/8Wul1Mn19fUiONtl3fzAmAP0XN8IgcM0EGzZs2JkElSOBTAMsLDiGnwBUWR74XpUjvuxiJS/TgK8AdBpUz34CAGMCgPy27hoEdC5Zr3lRORIQ8krYMzExMTAwIMaUqLI8iE/XyCCgj+NnxKLRoWf2/gcyfyBDGDNv3jw6csCP70C0QPvSUq6tzgKelK5EUxJZElazlFMX/PB6efkIJXsD0IKCgsrKSuclmpi1t6S9uBy6lJzMy1My5ae892DExdn/R8wYd+fu6DmHFcAwVgDDWAEMYwUwjBXAMFYAw1gBDGMFMIwVwDBp/xSxZs2aqqqqsbGxw4cPK1PiD2W0t7cne0K9ePHitWvXXr9+Xf4aKFRWVj7yyCMkKIfSxKgpLS1lpT4yMqIrxinGU6dOBf95OGH16tXV1dWuSmrkmbs6iTM5OXnjxo2enh7560Oap+O7MZz7AVzIF6kTPwI+m+FPEbT1+vXrN2/eXFJSokzxfXAYH330UXXuYd26dWRw/uoZi8WwgPPZukYKdO5vJI0FDdR5IL6V1KxYseL2FzvYuHFjQ0NDU1OTa7uRXFUnftTU1EieZKh8yUlPALott3T58mXSiC9GkJ/mA/aDyo1JNsjPz6fdr169OjU15SxnVqioqCgrK/NW0oXefrF///4DBw5QN2r1zDPPFBcXqxyhOXnypBTlReVITnoCyP20tLS4Gq6/v58hvGjRIudfi9HIrqnR0VG9jWfZsmXz58/nnoeGhiQt9llBVxIXFCCA3n7R3d3d0dFBY3EXRUVF4hjTAq8oRXlROZKTtgATExN9fX0DAwMyGsQ+PT0te3V8b1iMztqIpbe3l6JkNIh9VtCVpEGdlUyJPOjnI3J6Z0hDALkZbozuL63pbG6vReMSQFqcEcOACPhUZoj/kUrKPonwhcvTlTDbimeRNASQt1mkp9N5uUPn+y2Dg4M4Ge7f1eOQTR4taf+zcuVKfI6UI5sbli9f7pyfs0GaWwpnmLoqGYxswwr/dHNWSEMA7o37kfdecK+4b+luchUv5NudnS0iiEU/Rmfg5+XlBb/QEZ7gSjoh0CpPwOy1adMmQrVz58653tgJAz1MFTQT79+w8xJWACZSvobeoWN2r9MXAWSfmkb8u8v/UIjuaOk6igCkrYMrqXnqqad2JyAA3bZtG8N037593n2VKamvr1cFzaS2tlblSE5YAeQenLvPpJc57w0ng0thYaL3u0mLcGN6Bwf+p7CwkOmRfiqWixcv4rsIqLP3QmEqqRkeHqZWQK8njMH1U+233nor5FLDCcs3KcpFypckIOz2dLkHhiqrG7EAlZYmlqAb6Oksaoj65W+6iWOhG+pdU1IOGjjLQSGGF5nlD1BmTMhKCq2trXpcAkOT5RuV37Fjx1dffaWs4Whvb3f9DbvwhBoBdE8aiASr5y0O5B0j519MlVvSDt21/iooKBCPxFEVEYcGwhhmwAYgrUwiZSV9YUQeOnQI31VVVZXWe4NZEkoAqT3tyIrRibwQ6Ww4Qho6mvgTmoNG4ZZ0/EO70/cZ7+rzDojc+VTGe3VBur+3kvq/MInnCgINqD+JDLxQxqQWIDc3VzoyHYSB5uT333/HfUtDS2agCYhqWN8CpxKwyiVpI/XhmUhQJBkyQz7rrWRbWxvu3lXJZMhw0RW+A6QWQLoz9+DyoYI3hmFlzxHN+CAJp/+RAMk5SWqyjIXE/ySrJOsyjikLp+OzaiEKohxl+v+TWgCpt2+rgTfOu3TpEoENrQ/OcBP/w0RHyMGUKxYnrAbod84IyheCa/K4YH4KrqSvAK6i6urq3njjDcbu6dOnXTVUOWZCf1KX48opqweZOwNIEQVp/6PXTS7w77SyDHC9C5NeT0RBorOz0+V/5PcWL5OTk0hFkEq2EydOKKsHJlWVcoCjl8KTVVJUd1XStyjmp4MHD6qTBLt27VIpB3v27NEDZUMcSbugbrhBdeJHij9dTDyAvFQrWaMQXyLS+Pj4tWvX9PAn/kV5hgJhJXYxMgLIQDm+u3SBeZgOKJM2/YuhwJSoN+SWlJTQiJTphTZlzRlQSXBWkjUwsan6cBy+iLD9+PHjzc3Nzv22RLQqhwfEphBukx6mTH6wEEn2kOru/NPFc4gMn4hZZhcrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYawAhrECGMYKYBgrgGGsAIaxAhjGCmAYK4BhrACGsQIYxgpgGCuAYdS2FIsp7AgwSk7O/wCqCi/+JioQYgAAAABJRU5ErkJggg=='); +} From c324f342b4bae05044f9c072127dc8c009b85761 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 9 Nov 2017 13:39:13 -0800 Subject: [PATCH 116/171] Fix to check ANDROID before UNIX --- cmake/externals/hifiAudioCodec/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/externals/hifiAudioCodec/CMakeLists.txt b/cmake/externals/hifiAudioCodec/CMakeLists.txt index 298f666304..e3ba36a440 100644 --- a/cmake/externals/hifiAudioCodec/CMakeLists.txt +++ b/cmake/externals/hifiAudioCodec/CMakeLists.txt @@ -11,12 +11,12 @@ if (WIN32) elseif (APPLE) set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-mac-2.0.zip) set(DOWNLOAD_MD5 21649881e7d5dc94f922179be96f76ba) -elseif (UNIX) - set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip) - set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481) elseif (ANDROID) set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-android-2.0.zip) set(DOWNLOAD_MD5 aef2a852600d498d58aa586668191683) +elseif (UNIX) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/codecSDK-linux-2.0.zip) + set(DOWNLOAD_MD5 67fb7755f9bcafb98a9fceea53bc7481) else() return() endif() From ad661cb34563844d52f69f7f19b06bf74184ffe2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 10 Nov 2017 10:50:07 +1300 Subject: [PATCH 117/171] Don't remove entities from list when try to delete locked entity --- scripts/system/edit.js | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 15f1c2f6c1..88f50cb080 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1424,24 +1424,29 @@ function deleteSelectedEntities() { for (var i = 0; i < newSortedSelection.length; i++) { var entityID = newSortedSelection[i]; var initialProperties = SelectionManager.savedProperties[entityID]; - var children = Entities.getChildrenIDs(entityID); - var childList = []; - recursiveDelete(children, childList, deletedIDs); - savedProperties.push({ - entityID: entityID, - properties: initialProperties, - children: childList - }); - deletedIDs.push(entityID); - Entities.deleteEntity(entityID); + if (!initialProperties.locked) { + var children = Entities.getChildrenIDs(entityID); + var childList = []; + recursiveDelete(children, childList, deletedIDs); + savedProperties.push({ + entityID: entityID, + properties: initialProperties, + children: childList + }); + deletedIDs.push(entityID); + Entities.deleteEntity(entityID); + } } - SelectionManager.clearSelections(); - pushCommandForSelections([], savedProperties); - entityListTool.webView.emitScriptEvent(JSON.stringify({ - type: "deleted", - ids: deletedIDs - })); + if (savedProperties.length > 0) { + SelectionManager.clearSelections(); + pushCommandForSelections([], savedProperties); + + entityListTool.webView.emitScriptEvent(JSON.stringify({ + type: "deleted", + ids: deletedIDs + })); + } } } From 355b465109cfa92dd49d944d8d5b32e89526436b Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 9 Nov 2017 16:05:53 -0700 Subject: [PATCH 118/171] make leaveDomain slot private --- interface/src/avatar/MyAvatar.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9133b967fa..e4e8f8d02c 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -561,8 +561,6 @@ public slots: float getDomainMinScale(); float getDomainMaxScale(); - void leaveDomain(); - void setGravity(float gravity); float getGravity(); @@ -624,6 +622,9 @@ signals: void attachmentsChanged(); void scaleChanged(); +private slots: + void leaveDomain(); + private: bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut); From 7dfdc8da59fc80f006dd0dfba683259d2a0c03fd Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 9 Nov 2017 17:50:38 -0700 Subject: [PATCH 119/171] Redesign and clean of unused lineWidths --- interface/src/raypick/LaserPointer.cpp | 12 ++++++++---- interface/src/raypick/LaserPointer.h | 4 ++++ interface/src/ui/overlays/Base3DOverlay.cpp | 12 ------------ interface/src/ui/overlays/Base3DOverlay.h | 3 --- interface/src/ui/overlays/Line3DOverlay.cpp | 15 +++++++++------ interface/src/ui/overlays/Line3DOverlay.h | 8 +++++--- .../tests/performance/rayPickPerformance.js | 1 - scripts/system/chat.js | 3 +-- .../controllerModules/farActionGrabEntity.js | 3 --- .../controllerModules/farTrigger.js | 3 --- .../controllerModules/hudOverlayPointer.js | 3 --- .../controllerModules/inEditMode.js | 3 --- .../controllerModules/overlayLaserInput.js | 3 --- .../controllerModules/webEntityLaserInput.js | 3 --- .../system/libraries/entitySelectionTool.js | 19 ++----------------- scripts/system/pal.js | 1 - scripts/tutorials/entity_scripts/pistol.js | 3 +-- .../DomainContent/Toybox/bow/bow.js | 2 -- .../DomainContent/Toybox/bow/createBow.js | 1 - .../DomainContent/Toybox/hiddenEntityReset.js | 1 - .../DomainContent/Toybox/masterReset.js | 1 - .../DomainContent/Toybox/pistol/pistol.js | 3 +-- unpublishedScripts/marketplace/bow/bow.js | 2 -- .../marketplace/laser/laserPointerApp.js | 1 - .../marketplace/shapes/modules/laser.js | 1 - .../marketplace/shortbow/bow/bow.js | 2 -- 26 files changed, 31 insertions(+), 82 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 14af9b336f..4ef5613b79 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -97,6 +97,10 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta if (endDim.isValid()) { _renderStates[state].setEndDim(vec3FromVariant(endDim)); } + QVariant lineWidth = pathProps.toMap()["lineWidth"]; + if (lineWidth.isValid()) { + _renderStates[state].setLineWidth(lineWidth.toFloat()); + } }); } @@ -165,10 +169,9 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter pathProps.insert("end", end); pathProps.insert("visible", true); pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays()); - - float glowWidth = _scaleWithAvatar ? DEFAULT_LASER_POINTER_SIZE * avatarScale : DEFAULT_LASER_POINTER_SIZE; - pathProps.insert("glowWidth", glowWidth); - + if (_scaleWithAvatar) { + pathProps.insert("lineWidth", renderState.getLineWidth() * avatarScale); + } qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps); } if (!renderState.getEndID().isNull()) { @@ -268,6 +271,7 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons } if (!_pathID.isNull()) { _pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool(); + _lineWidth = qApp->getOverlays().getProperty(_pathID, "lineWidth").value.toFloat(); } if (!_endID.isNull()) { _endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index e0c6f631c0..d38070c05c 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -43,6 +43,9 @@ public: void setEndDim(const glm::vec3& endDim) { _endDim = endDim; } const glm::vec3& getEndDim() const { return _endDim; } + void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; } + const float& getLineWidth() const { return _lineWidth; } + void deleteOverlays(); private: @@ -54,6 +57,7 @@ private: bool _endIgnoreRays; glm::vec3 _endDim; + float _lineWidth; }; diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 42425932df..a2f400900e 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -16,13 +16,11 @@ #include "Application.h" -const float DEFAULT_LINE_WIDTH = 1.0f; const bool DEFAULT_IS_SOLID = false; const bool DEFAULT_IS_DASHED_LINE = false; Base3DOverlay::Base3DOverlay() : SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()), - _lineWidth(DEFAULT_LINE_WIDTH), _isSolid(DEFAULT_IS_SOLID), _isDashedLine(DEFAULT_IS_DASHED_LINE), _ignoreRayIntersection(false), @@ -34,7 +32,6 @@ Base3DOverlay::Base3DOverlay() : Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : Overlay(base3DOverlay), SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()), - _lineWidth(base3DOverlay->_lineWidth), _isSolid(base3DOverlay->_isSolid), _isDashedLine(base3DOverlay->_isDashedLine), _ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection), @@ -153,12 +150,6 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { setLocalOrientation(quatFromVariant(properties["orientation"])); needRenderItemUpdate = true; } - - if (properties["lineWidth"].isValid()) { - setLineWidth(properties["lineWidth"].toFloat()); - needRenderItemUpdate = true; - } - if (properties["isSolid"].isValid()) { setIsSolid(properties["isSolid"].toBool()); } @@ -225,9 +216,6 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "localRotation" || property == "localOrientation") { return quatToVariant(getLocalOrientation()); } - if (property == "lineWidth") { - return _lineWidth; - } if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") { return _isSolid; } diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 436cfbf97b..0c73214259 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -35,7 +35,6 @@ public: // TODO: consider implementing registration points in this class glm::vec3 getCenter() const { return getPosition(); } - float getLineWidth() const { return _lineWidth; } bool getIsSolid() const { return _isSolid; } bool getIsDashedLine() const { return _isDashedLine; } bool getIsSolidLine() const { return !_isDashedLine; } @@ -44,7 +43,6 @@ public: bool getDrawHUDLayer() const { return _drawHUDLayer; } bool getIsGrabbable() const { return _isGrabbable; } - void setLineWidth(float lineWidth) { _lineWidth = lineWidth; } void setIsSolid(bool isSolid) { _isSolid = isSolid; } void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; } void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; } @@ -80,7 +78,6 @@ protected: virtual void setRenderTransform(const Transform& transform); const Transform& getRenderTransform() const { return _renderTransform; } - float _lineWidth; bool _isSolid; bool _isDashedLine; bool _ignoreRayIntersection; diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 82a3c46727..c3d9de859c 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -6,7 +6,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// +//// #include "Line3DOverlay.h" @@ -33,8 +33,8 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) : _length = line3DOverlay->getLength(); _endParentID = line3DOverlay->getEndParentID(); _endParentJointIndex = line3DOverlay->getEndJointIndex(); + _lineWidth = line3DOverlay->getLineWidth(); _glow = line3DOverlay->getGlow(); - _glowWidth = line3DOverlay->getGlowWidth(); } Line3DOverlay::~Line3DOverlay() { @@ -145,7 +145,7 @@ void Line3DOverlay::render(RenderArgs* args) { geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID); } else { // renderGlowLine handles both glow = 0 and glow > 0 cases - geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _geometryCacheID); + geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _lineWidth, _geometryCacheID); } } } @@ -239,9 +239,9 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) { } } - auto glowWidth = properties["glowWidth"]; - if (glowWidth.isValid()) { - setGlowWidth(glowWidth.toFloat()); + auto lineWidth = properties["lineWidth"]; + if (lineWidth.isValid()) { + setLineWidth(lineWidth.toFloat()); } } @@ -261,6 +261,9 @@ QVariant Line3DOverlay::getProperty(const QString& property) { if (property == "length") { return QVariant(getLength()); } + if (property == "lineWidth") { + return _lineWidth; + } return Base3DOverlay::getProperty(property); } diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index bcb65b1f1e..2a3c7caa99 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -13,6 +13,8 @@ #include "Base3DOverlay.h" +static const float DEFAULT_LINE_WIDTH = 0.02f; + class Line3DOverlay : public Base3DOverlay { Q_OBJECT using Parent = Base3DOverlay; @@ -31,8 +33,8 @@ public: // getters glm::vec3 getStart() const; glm::vec3 getEnd() const; + const float& getLineWidth() const { return _lineWidth; } const float& getGlow() const { return _glow; } - const float& getGlowWidth() const { return _glowWidth; } // setters void setStart(const glm::vec3& start); @@ -41,8 +43,8 @@ public: void setLocalStart(const glm::vec3& localStart) { setLocalPosition(localStart); } void setLocalEnd(const glm::vec3& localEnd); + void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; } void setGlow(const float& glow) { _glow = glow; } - void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; } void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; @@ -70,8 +72,8 @@ private: glm::vec3 _direction; // in parent frame float _length { 1.0 }; // in parent frame + float _lineWidth { DEFAULT_LINE_WIDTH }; float _glow { 0.0 }; - float _glowWidth { 0.0 }; int _geometryCacheID; }; diff --git a/scripts/developer/tests/performance/rayPickPerformance.js b/scripts/developer/tests/performance/rayPickPerformance.js index b4faf4c1be..92d12c0e71 100644 --- a/scripts/developer/tests/performance/rayPickPerformance.js +++ b/scripts/developer/tests/performance/rayPickPerformance.js @@ -96,7 +96,6 @@ function rayCastTest() { color: color, alpha: 1, visible: visible, - lineWidth: 2, start: origin, end: Vec3.sum(origin,Vec3.multiply(5,direction)) }); diff --git a/scripts/system/chat.js b/scripts/system/chat.js index fa997e20cc..0cb414e23c 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -284,8 +284,7 @@ endParentJointIndex: yourJointIndex, end: yourJointPosition, color: identifyAvatarLineColor, - alpha: 1, - lineWidth: 1 + alpha: 1 }; avatarIdentifiers[yourAvatarID] = identifierParams; diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 0b00cfa303..8139302dfe 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -33,7 +33,6 @@ Script.include("/~/system/libraries/Xform.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -55,7 +54,6 @@ Script.include("/~/system/libraries/Xform.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -77,7 +75,6 @@ Script.include("/~/system/libraries/Xform.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index ab950cbbdf..9c72c3df4d 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -25,7 +25,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -47,7 +46,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -69,7 +67,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index 23802893a8..acddcaf246 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -31,7 +31,6 @@ alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawHUDLayer: true, parentID: MyAvatar.SELF_ID @@ -53,7 +52,6 @@ alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawHUDLayer: true, parentID: MyAvatar.SELF_ID @@ -75,7 +73,6 @@ alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawHUDLayer: true, parentID: MyAvatar.SELF_ID diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 4520a91d74..94233376c7 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -27,7 +27,6 @@ Script.include("/~/system/libraries/utils.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -49,7 +48,6 @@ Script.include("/~/system/libraries/utils.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -71,7 +69,6 @@ Script.include("/~/system/libraries/utils.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index e87e6e000a..2d27f160c1 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index eafe7c3462..36a36d38f3 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID @@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, solid: true, glow: 1.0, - lineWidth: 5, ignoreRayIntersection: true, // always ignore this drawInFront: true, // Even when burried inside of something, show it. parentID: MyAvatar.SELF_ID diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 3a422bcb8a..d947a1d397 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -339,7 +339,6 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - lineWidth: grabberLineWidth, drawInFront: true, borderSize: 1.4 }; @@ -352,7 +351,6 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - lineWidth: grabberLineWidth, drawInFront: true, borderSize: 1.4 }; @@ -365,7 +363,6 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - lineWidth: grabberLineWidth, drawInFront: true, borderSize: 1.4 }; @@ -378,14 +375,12 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - lineWidth: grabberLineWidth, drawInFront: true, borderSize: 1.4 }; var spotLightLineProperties = { - color: lightOverlayColor, - lineWidth: 1.5 + color: lightOverlayColor }; var highlightBox = Overlays.addOverlay("cube", { @@ -400,7 +395,6 @@ SelectionDisplay = (function() { solid: false, visible: false, dashed: true, - lineWidth: 2.0, ignoreRayIntersection: true, // this never ray intersects drawInFront: true }); @@ -416,8 +410,7 @@ SelectionDisplay = (function() { alpha: 1, solid: false, visible: false, - dashed: false, - lineWidth: 1.0 + dashed: false }); var selectionBoxes = []; @@ -466,7 +459,6 @@ SelectionDisplay = (function() { // var normalLine = Overlays.addOverlay("line3d", { // visible: true, - // lineWidth: 2.0, // start: { x: 0, y: 0, z: 0 }, // end: { x: 0, y: 0, z: 0 }, // color: { red: 255, green: 255, blue: 0 }, @@ -656,7 +648,6 @@ SelectionDisplay = (function() { var xRailOverlay = Overlays.addOverlay("line3d", { visible: false, - lineWidth: 1.0, start: Vec3.ZERO, end: Vec3.ZERO, color: { @@ -668,7 +659,6 @@ SelectionDisplay = (function() { }); var yRailOverlay = Overlays.addOverlay("line3d", { visible: false, - lineWidth: 1.0, start: Vec3.ZERO, end: Vec3.ZERO, color: { @@ -680,7 +670,6 @@ SelectionDisplay = (function() { }); var zRailOverlay = Overlays.addOverlay("line3d", { visible: false, - lineWidth: 1.0, start: Vec3.ZERO, end: Vec3.ZERO, color: { @@ -693,7 +682,6 @@ SelectionDisplay = (function() { var rotateZeroOverlay = Overlays.addOverlay("line3d", { visible: false, - lineWidth: 2.0, start: Vec3.ZERO, end: Vec3.ZERO, color: { @@ -706,7 +694,6 @@ SelectionDisplay = (function() { var rotateCurrentOverlay = Overlays.addOverlay("line3d", { visible: false, - lineWidth: 2.0, start: Vec3.ZERO, end: Vec3.ZERO, color: { @@ -1788,7 +1775,6 @@ SelectionDisplay = (function() { y: distance, z: 1 }, - lineWidth: 1.5, rotation: rotation, visible: true }); @@ -1994,7 +1980,6 @@ SelectionDisplay = (function() { solid: false, visible: false, dashed: false, - lineWidth: 1.0, ignoreRayIntersection: true })); } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 44ff7c2acd..b5551cf596 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -189,7 +189,6 @@ function HighlightedEntity(id, entityProperties) { green: 0x91, blue: 0x29 }, - lineWidth: 1.0, ignoreRayIntersection: true, drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene. }); diff --git a/scripts/tutorials/entity_scripts/pistol.js b/scripts/tutorials/entity_scripts/pistol.js index 1a570cc80f..62517f486d 100644 --- a/scripts/tutorials/entity_scripts/pistol.js +++ b/scripts/tutorials/entity_scripts/pistol.js @@ -350,8 +350,7 @@ end: ZERO_VECTOR, color: { red: 255, green: 0, blue: 0}, alpha: 1, - visible: true, - lineWidth: 2 + visible: true }); }, }; diff --git a/unpublishedScripts/DomainContent/Toybox/bow/bow.js b/unpublishedScripts/DomainContent/Toybox/bow/bow.js index 0c16bcbc7b..47335bcb6d 100644 --- a/unpublishedScripts/DomainContent/Toybox/bow/bow.js +++ b/unpublishedScripts/DomainContent/Toybox/bow/bow.js @@ -329,7 +329,6 @@ y: 0, z: 0 }, lineVectors[0]], - lineWidth: 5, color: this.stringData.currentColor }); @@ -339,7 +338,6 @@ y: 0, z: 0 }, lineVectors[1]], - lineWidth: 5, color: this.stringData.currentColor }); diff --git a/unpublishedScripts/DomainContent/Toybox/bow/createBow.js b/unpublishedScripts/DomainContent/Toybox/bow/createBow.js index f1ed9eb263..5a4275d96a 100644 --- a/unpublishedScripts/DomainContent/Toybox/bow/createBow.js +++ b/unpublishedScripts/DomainContent/Toybox/bow/createBow.js @@ -125,7 +125,6 @@ function createPreNotchString() { y: 0, z: 0 }, downOffset)], - lineWidth: 5, color: { red: 255, green: 255, diff --git a/unpublishedScripts/DomainContent/Toybox/hiddenEntityReset.js b/unpublishedScripts/DomainContent/Toybox/hiddenEntityReset.js index e2deec75ed..fe514f6dfc 100644 --- a/unpublishedScripts/DomainContent/Toybox/hiddenEntityReset.js +++ b/unpublishedScripts/DomainContent/Toybox/hiddenEntityReset.js @@ -450,7 +450,6 @@ y: 0, z: 0 }, downOffset)], - lineWidth: 5, color: { red: 255, green: 255, diff --git a/unpublishedScripts/DomainContent/Toybox/masterReset.js b/unpublishedScripts/DomainContent/Toybox/masterReset.js index 4ad9cce401..b621544621 100644 --- a/unpublishedScripts/DomainContent/Toybox/masterReset.js +++ b/unpublishedScripts/DomainContent/Toybox/masterReset.js @@ -427,7 +427,6 @@ MasterReset = function() { y: 0, z: 0 }, downOffset)], - lineWidth: 5, color: { red: 255, green: 255, diff --git a/unpublishedScripts/DomainContent/Toybox/pistol/pistol.js b/unpublishedScripts/DomainContent/Toybox/pistol/pistol.js index 5f57c6fc17..b408e4f464 100644 --- a/unpublishedScripts/DomainContent/Toybox/pistol/pistol.js +++ b/unpublishedScripts/DomainContent/Toybox/pistol/pistol.js @@ -346,8 +346,7 @@ end: { x: 0, y: 0, z: 0 }, color: COLORS.RED, alpha: 1, - visible: true, - lineWidth: 2 + visible: true }); }, }; diff --git a/unpublishedScripts/marketplace/bow/bow.js b/unpublishedScripts/marketplace/bow/bow.js index 818960e335..883eff113c 100644 --- a/unpublishedScripts/marketplace/bow/bow.js +++ b/unpublishedScripts/marketplace/bow/bow.js @@ -266,7 +266,6 @@ dimensions: { "x": 5, "y": 5, "z": 5 }, ignoreForCollisions: 1, linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ], - lineWidth: 5, name: STRING_NAME, parentID: this.entityID, localPosition: { "x": 0, "y": 0.6, "z": 0.1 }, @@ -287,7 +286,6 @@ resetStringToIdlePosition: function() { Entities.editEntity(this.stringID, { linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ], - lineWidth: 5, localPosition: { "x": 0, "y": 0.6, "z": 0.1 }, localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 }, }); diff --git a/unpublishedScripts/marketplace/laser/laserPointerApp.js b/unpublishedScripts/marketplace/laser/laserPointerApp.js index 515a2c3a76..aa049ea470 100644 --- a/unpublishedScripts/marketplace/laser/laserPointerApp.js +++ b/unpublishedScripts/marketplace/laser/laserPointerApp.js @@ -99,7 +99,6 @@ lifetime: 360, type: 'Line', glow: 1.0, - lineWidth: 5, alpha: 0.5, ignoreRayIntersection: true, drawInFront: true, diff --git a/unpublishedScripts/marketplace/shapes/modules/laser.js b/unpublishedScripts/marketplace/shapes/modules/laser.js index 1efc38b65a..d5feda0e1f 100644 --- a/unpublishedScripts/marketplace/shapes/modules/laser.js +++ b/unpublishedScripts/marketplace/shapes/modules/laser.js @@ -72,7 +72,6 @@ Laser = function (side) { } laserLine = Overlays.addOverlay("line3d", { - lineWidth: 5, alpha: 1.0, glow: 1.0, ignoreRayIntersection: true, diff --git a/unpublishedScripts/marketplace/shortbow/bow/bow.js b/unpublishedScripts/marketplace/shortbow/bow/bow.js index a8e76f76fd..5134fb6fd8 100644 --- a/unpublishedScripts/marketplace/shortbow/bow/bow.js +++ b/unpublishedScripts/marketplace/shortbow/bow/bow.js @@ -408,7 +408,6 @@ function getControllerLocation(controllerHand) { dimensions: { "x": 5, "y": 5, "z": 5 }, ignoreForCollisions: 1, linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ], - lineWidth: 5, color: { red: 153, green: 102, blue: 51 }, name: STRING_NAME, parentID: this.entityID, @@ -430,7 +429,6 @@ function getControllerLocation(controllerHand) { resetStringToIdlePosition: function() { Entities.editEntity(this.stringID, { linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ], - lineWidth: 5, localPosition: { "x": 0, "y": 0.6, "z": 0.1 }, localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 }, }); From 055fe16677ac075b508a593e84fe248c18ae3fda Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 9 Nov 2017 18:27:16 -0700 Subject: [PATCH 120/171] Allow script to change to mirror camera in HMD --- interface/src/Application.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58e433af84..228d39f87e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4423,12 +4423,7 @@ void Application::cameraModeChanged() { Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); break; case CAMERA_MODE_MIRROR: - if (isHMDMode()) { - _myCamera.setMode(_myCamera.getLastMode()); - qDebug() << "Mirror mode is not available"; - } else { - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); - } + Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); break; case CAMERA_MODE_INDEPENDENT: Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true); From 255a40ce3139868333d4b30a8c882e3f563f4b82 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 9 Nov 2017 18:38:04 -0700 Subject: [PATCH 121/171] Corrections --- interface/src/raypick/LaserPointer.cpp | 2 -- interface/src/ui/overlays/Line3DOverlay.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 4ef5613b79..6d29154be0 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -14,8 +14,6 @@ #include "avatar/AvatarManager.h" #include "RayPickScriptingInterface.h" -static const float DEFAULT_LASER_POINTER_SIZE = 0.02f; - LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) : _renderingEnabled(enabled), diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index c3d9de859c..a6b7242df2 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -6,7 +6,7 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -//// +// #include "Line3DOverlay.h" From a9fe3596cf4a8ab025e31a60e92faf49acabf6a3 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 27 Oct 2017 20:39:43 +0300 Subject: [PATCH 122/171] 4684 Add collapse button on the virtual keyboard --- interface/resources/images/lowerKeyboard.png | Bin 0 -> 1053 bytes interface/resources/qml/controls-uit/Key.qml | 12 +- .../resources/qml/controls-uit/Keyboard.qml | 121 ++++++++++++++++-- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 12 ++ libraries/ui/src/ui/OffscreenQmlSurface.h | 1 + 5 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 interface/resources/images/lowerKeyboard.png diff --git a/interface/resources/images/lowerKeyboard.png b/interface/resources/images/lowerKeyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..d379b028abf829efd35f3e78a7fb90db40636d5d GIT binary patch literal 1053 zcmV+&1mgRNP)tFHbFs&rYpO%1FH^loSdkut1DSVGXCX3uuo4szP~rIhvcBwXLM21Wip% zI668)XJ@A#85zO)`Z^8|4;43)fPcva1pD~-NM#Wj8L3lJQczo4i-LjzarMT=20T1G zpbQJTva%A{+1W@>PZyTP#>PMbW@l%yy1J@vZf=CR-%J4S%^4UNsEH#dCkGTYDJcoN zySw7(@$qrNb#QQ?l)t~fs2ULwp))cvke8Q-;^Jb2g@s{dWd$=cGeQLC>FKG#{=0I3 zV4agp&?97O<`eS0q5uEifhHiK|w)M%9cgU1|1z8 zEt~7=>cj;X7Z=#v+!XM=y}ejlTT@)mQutegmv?t}*96Mi)0#;w@f z+f(=V_d<@nW1oRr0IX180x}d55)x2fUoWBH=H^D$Fh4(!*49>Wg9$@9nByl)!9JO3 z=ZcC75r$w{v$QksM1}YF_eI_JGU^p@dj%~U5wP_!1_eLH|8{nE(9zL>fq?;rA=oAu zEZ-G~_9FQB_~@9J7&J6ApscJ+!iybtHhRMlETwh;*ScG?hzqGMsFXljXb+yo(}{@*QHRQK-&+Lm92XZC zn4YWi^YevBs?7hmpDl<9ZHQF2x3{l?%8`Km67ZJ5($90COFad1+}0?d|R25WXZCmL!hnefRiQ;P#iZ!iMQjRr!)?Y-|)& z=?q$)Dl(aA=a!ZhEH5uVx5uA;DE%1lw>kn-J~1&-*VNSTR{+!grY%Yv{A@CR#RY!= XNdg&R^>QXW00000NkvXXu0mjff;Z>0 literal 0 HcmV?d00001 diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index e54250c872..586a9c0225 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -5,6 +5,8 @@ Item { id: keyItem width: 45 height: 50 + + property int contentPadding: 4 property string glyph: "a" property bool toggle: false // does this button have the toggle behaivor? property bool toggled: false // is this button currently toggled? @@ -105,14 +107,8 @@ Item { color: "#121212" radius: 2 border.color: "#00000000" - anchors.right: parent.right - anchors.rightMargin: 4 - anchors.left: parent.left - anchors.leftMargin: 4 - anchors.bottom: parent.bottom - anchors.bottomMargin: 4 - anchors.top: parent.top - anchors.topMargin: 4 + anchors.fill: parent + anchors.margins: contentPadding } Text { diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 66a61742c9..7f73538c19 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -8,7 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.0 +import QtQuick 2.7 +import QtGraphicalEffects 1.0 import "." Rectangle { @@ -112,8 +113,6 @@ Rectangle { } Rectangle { - y: 0 - x: 0 height: showMirrorText ? mirrorTextHeight : 0 width: keyboardWidth color: "#252525" @@ -122,13 +121,18 @@ Rectangle { TextInput { id: mirrorText visible: showMirrorText - FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } - font.family: ralewaySemiBold.name - font.pointSize: 13.5 + FontLoader { id: font; source: "../../fonts/FiraSans-Regular.ttf"; } + font.family: font.name + font.pixelSize: 20 verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - color: "#FFFFFF"; - anchors.fill: parent + horizontalAlignment: Text.AlignLeft + color: "#00B4EF"; + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.right: lowerKeyboard.left + anchors.top: parent.top + anchors.bottom: parent.bottom + wrapMode: Text.WordWrap readOnly: false // we need this to allow control to accept QKeyEvent selectByMouse: false @@ -140,16 +144,107 @@ Rectangle { event.accepted = true; } } + + MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus + anchors.fill: parent + } } - MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus - anchors.fill: parent + Item { + id: lowerKeyboard + anchors.right: parent.right + anchors.rightMargin: keyboardRect.width - (key_Backspace.x + key_Backspace.width + key_Backspace.contentPadding) + width: key_Backspace.width * 2 + height: parent.height + + Rectangle { + id: roundedRect + color: "#121212" + radius: 6 + border.color: "#00000000" + anchors.fill: parent + anchors.margins: 4 + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + + onClicked: { + webEntity.lowerKeyboard(); + } + + onEntered: { + roundedRect.state = "mouseOver"; + } + + onExited: { + roundedRect.state = ""; + } + + onPressed: { + roundedRect.state = "mouseClicked"; + } + + onReleased: { + if (containsMouse) { + roundedRect.state = "mouseOver"; + } else { + roundedRect.state = ""; + } + } + } + + states: [ + State { + name: "mouseOver" + PropertyChanges { + target: roundedRect + color: "#121212" + border.width: 2 + border.color: "#00b4ef" + } + }, + State { + name: "mouseClicked" + PropertyChanges { + target: roundedRect + border.width: 2 + border.color: "#00b4ef" + } + PropertyChanges { + target: colorOverlay + color: '#00B4EF' + } + }, + State { + name: "mouseDepressed" + PropertyChanges { + target: roundedRect + color: "#0578b1" + border.width: 0 + } + } + ] + + Image { + id: buttonImage + anchors.centerIn: parent + source: "../../images/lowerKeyboard.png" // "file:///D:/AI/hifi-elderorb-vs2/interface/resources/images/lowerKeyboard.png"; + } + + ColorOverlay { + id: colorOverlay + anchors.fill: buttonImage + source: buttonImage + color: 'white' + } + } } } Rectangle { id: keyboardRect - x: 0 y: showMirrorText ? mirrorTextHeight : 0 width: keyboardWidth height: raisedHeight @@ -180,7 +275,7 @@ Rectangle { Key { width: 43; glyph: "i"; } Key { width: 43; glyph: "o"; } Key { width: 43; glyph: "p"; } - Key { width: 43; glyph: "←"; } + Key { width: 43; glyph: "←"; id: key_Backspace } } Row { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..8333e87799 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1082,7 +1082,19 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid } } +void OffscreenQmlSurface::lowerKeyboard() { + + QSignalBlocker blocker(_quickWindow); + + if (_currentFocusItem) { + _currentFocusItem->setFocus(false); + setKeyboardRaised(_currentFocusItem, false); + } +} + void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) { + qCDebug(uiLogging) << "setKeyboardRaised: " << object << ", raised: " << raised << ", numeric: " << numeric << ", password: " << passwordField; + #if Q_OS_ANDROID return; #endif diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..5acdeb4f40 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -84,6 +84,7 @@ public: void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false); Q_INVOKABLE void synthesizeKeyPress(QString key, QObject* targetOverride = nullptr); + Q_INVOKABLE void lowerKeyboard(); using TextureAndFence = std::pair; // Checks to see if a new texture is available. If one is, the function returns true and From fb14e4dc4d32db910efe383e4031602a8fb55b2e Mon Sep 17 00:00:00 2001 From: beholder Date: Sun, 29 Oct 2017 19:00:03 +0300 Subject: [PATCH 123/171] Fixed programmatical lowering of 'TabletAddressDialog' --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 4d9a83817a..649a8e6259 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -366,7 +366,7 @@ StackView { HifiControls.Keyboard { id: keyboard - raised: parent.keyboardEnabled + raised: parent.keyboardEnabled && parent.keyboardRaised numeric: parent.punctuationMode anchors { bottom: parent.bottom From eb4214fb4c840bb74fb1dec56e9b8f18b3b94370 Mon Sep 17 00:00:00 2001 From: beholder Date: Thu, 2 Nov 2017 03:35:32 +0300 Subject: [PATCH 124/171] add API for unfocusing input fields in HTML, unfocus WebEngine-based QML items on lowering keyboard --- interface/resources/qml/controls/FlickableWebViewCore.qml | 6 ++++++ interface/resources/qml/controls/TabletWebScreen.qml | 5 +++++ interface/resources/qml/controls/TabletWebView.qml | 5 +++++ interface/resources/qml/controls/WebView.qml | 5 +++++ 4 files changed, 21 insertions(+) diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index cbc4d19334..29944781c1 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -27,6 +27,12 @@ Item { id: hifi } + function unfocus() { + webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) { + console.log('unfocus completed: ', result); + }); + } + function onLoadingChanged(loadRequest) { if (WebEngineView.LoadStartedStatus === loadRequest.status) { diff --git a/interface/resources/qml/controls/TabletWebScreen.qml b/interface/resources/qml/controls/TabletWebScreen.qml index e06ff51569..501e321f0d 100644 --- a/interface/resources/qml/controls/TabletWebScreen.qml +++ b/interface/resources/qml/controls/TabletWebScreen.qml @@ -10,6 +10,11 @@ Item { property alias urlTag: webroot.urlTag property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardRaised: false + onKeyboardRaisedChanged: { + if(!keyboardRaised) { + webroot.unfocus(); + } + } property bool punctuationMode: false // FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 8cd61bc90b..477422cfa1 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -15,6 +15,11 @@ Item { property string scriptURL property bool keyboardEnabled: false property bool keyboardRaised: false + onKeyboardRaisedChanged: { + if(!keyboardRaised) { + webroot.unfocus(); + } + } property bool punctuationMode: false property bool passwordField: false property bool isDesktop: false diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 923c8f3fa1..931c64e1ef 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -12,6 +12,11 @@ Item { property alias urlTag: webroot.urlTag property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardRaised: false + onKeyboardRaisedChanged: { + if(!keyboardRaised) { + webroot.unfocus(); + } + } property bool punctuationMode: false property bool passwordField: false property alias flickable: webroot.interactive From db3ed81513f0cbe14cb24fe479de297b26cca6ec Mon Sep 17 00:00:00 2001 From: beholder Date: Tue, 7 Nov 2017 13:45:27 +0300 Subject: [PATCH 125/171] adjust to changed requirements: 1. The keyboard collapse button is moved to the lower right, replacing the keys there 2. The button next to m is a hyphen instead of a underscore, it turns to a underscore when the user clicks on shift 3. The input text at the top occupies the full width and is center aligned, when you start typing the text moves in both directions the left and the right --- interface/resources/fonts/hifi-glyphs.ttf | Bin 30784 -> 31232 bytes interface/resources/qml/controls-uit/Key.qml | 1 + .../resources/qml/controls-uit/Keyboard.qml | 120 +++--------------- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 4 + 4 files changed, 24 insertions(+), 101 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 3db48602b1eb845238497d2f3750fa7d281ccfbc..4cc5a0fe4f098a287c1df067c8bff37695f96d34 100644 GIT binary patch delta 802 zcmYjPO-vI}5dNk=lmNR(TfuH?y6rZQ(hzJ5t)>v;U-eJ~fe_RvE~V1Y)-Ducn~31S zXcQB}swWP5@J5ZMUQ9Tk(VIpNN(}MPgE8PmWAp$qt?5FvlQ-{uGjF~xGs!IfpxIwE z0|LNc7HaeagZ*9UTZM-}<_iGJ@uSCrc!3Ha^BMr(-Ph{rUJ6M74FVVlCq$`#_~T78`Ub5Y_&1FvHhyD8}rnuoujj`$cO1PxpE8Sr9J^D z&7rtOkpYcBtso0DbOJyXDxpG2@oL_gcNL3@wk?l;82kl=QHfVTj#GQon)Wpy7pmAj zcE|z&C+P!4p@t6CsD%LyFvEr>xX=nO{0QJ6g6P6IBruLCWH60uxQ;o@J0LVPRF%x=XM(dq_x=_JE_g*wR!6IQoa0L=bUNqdUh&|0kV=`pec?M z%w~t#>?i|yJ;Ue=TXhUm_s42&wpyJ$->e)b&#(ReB);&*WVf3rV6u}?SY(U_mIAE7 zz#idwr^0k?)2!AlJ;My_h@SGa$2Lvn#&KLzSX)*7fNL{`np&oGn^DBMq0wj acwCfH5qa}6Pq$?*&DE?nX4iK%Wc@Fk$FR}> delta 432 zcmYL^%`0pH7{-6^oHGX*-PHKVoqT11ntaA6w{&AHeAd0bA{-2p3@2yGna!oUWTShm z#D6e~&W5tEw6L&Xqq~@HT}demHd3QGl(*jAr=GW8&$IC)XOFUu0C{YnFc=R1?6YzX ztHG)Q0^OZmVUE$jQi1Y;A9albr@hM{qrmWNOgG~DSG(Z31kcQZZW`${3aq^X*$YdF z`P=;8ouKu?qCXnZ=Y045L%?64B^r&a>uSBEK>R>eG#0nYj*1>Y4naznR%Z2*sa79& zn?Z_Wx@B-DlOUl?pk+N4d2GEH24fn;F;>j@`Hr;@tA6nQcgqP(Z;xzGeQAFt*F$Em zZ?)w6^=QdI^3A&?<9xNh%b3(Sd(tF58CUt(fQvyUP+S#2m5xk5vU%tIO4X#(F1aGb zhr<2UICCnMM#UM`3KpHb)m+JHAViQhyUeUr8$!W0yU*N_E$5$ED9%g#K($X2<+5qt LBuadrIkn^)$9!hA diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index 586a9c0225..ebdfff36c0 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -11,6 +11,7 @@ Item { property bool toggle: false // does this button have the toggle behaivor? property bool toggled: false // is this button currently toggled? property alias mouseArea: mouseArea1 + property alias fontFamily: letter.font.family; function resetToggledMode(mode) { toggled = mode; diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 7f73538c19..5974ffe7bc 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -56,6 +56,8 @@ Rectangle { return ">"; } else if (str === "/") { return "?"; + } else if (str === "-") { + return "_"; } else { return str.toUpperCase(str); } @@ -68,6 +70,8 @@ Rectangle { return "."; } else if (str === "?") { return "/"; + } else if (str === "_") { + return "-"; } else { return str.toLowerCase(str); } @@ -86,7 +90,7 @@ Rectangle { onShiftModeChanged: { forEachKey(function (key) { - if (/[a-z]/i.test(key.glyph)) { + if (/[a-z-_]/i.test(key.glyph)) { if (shiftMode) { key.glyph = keyboardBase.toUpper(key.glyph); } else { @@ -125,11 +129,11 @@ Rectangle { font.family: font.name font.pixelSize: 20 verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignLeft + horizontalAlignment: Text.AlignHCenter color: "#00B4EF"; anchors.left: parent.left anchors.leftMargin: 10 - anchors.right: lowerKeyboard.left + anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom @@ -149,98 +153,6 @@ Rectangle { anchors.fill: parent } } - - Item { - id: lowerKeyboard - anchors.right: parent.right - anchors.rightMargin: keyboardRect.width - (key_Backspace.x + key_Backspace.width + key_Backspace.contentPadding) - width: key_Backspace.width * 2 - height: parent.height - - Rectangle { - id: roundedRect - color: "#121212" - radius: 6 - border.color: "#00000000" - anchors.fill: parent - anchors.margins: 4 - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - - onClicked: { - webEntity.lowerKeyboard(); - } - - onEntered: { - roundedRect.state = "mouseOver"; - } - - onExited: { - roundedRect.state = ""; - } - - onPressed: { - roundedRect.state = "mouseClicked"; - } - - onReleased: { - if (containsMouse) { - roundedRect.state = "mouseOver"; - } else { - roundedRect.state = ""; - } - } - } - - states: [ - State { - name: "mouseOver" - PropertyChanges { - target: roundedRect - color: "#121212" - border.width: 2 - border.color: "#00b4ef" - } - }, - State { - name: "mouseClicked" - PropertyChanges { - target: roundedRect - border.width: 2 - border.color: "#00b4ef" - } - PropertyChanges { - target: colorOverlay - color: '#00B4EF' - } - }, - State { - name: "mouseDepressed" - PropertyChanges { - target: roundedRect - color: "#0578b1" - border.width: 0 - } - } - ] - - Image { - id: buttonImage - anchors.centerIn: parent - source: "../../images/lowerKeyboard.png" // "file:///D:/AI/hifi-elderorb-vs2/interface/resources/images/lowerKeyboard.png"; - } - - ColorOverlay { - id: colorOverlay - anchors.fill: buttonImage - source: buttonImage - color: 'white' - } - } - } } Rectangle { @@ -253,6 +165,8 @@ Rectangle { anchors.bottom: parent.bottom anchors.bottomMargin: 0 + FontLoader { id: hiFiGlyphs; source: pathToFonts + "fonts/hifi-glyphs.ttf"; } + Column { id: columnAlpha width: keyboardWidth @@ -275,7 +189,7 @@ Rectangle { Key { width: 43; glyph: "i"; } Key { width: 43; glyph: "o"; } Key { width: 43; glyph: "p"; } - Key { width: 43; glyph: "←"; id: key_Backspace } + Key { width: 43; glyph: "←"; } } Row { @@ -316,7 +230,7 @@ Rectangle { Key { width: 43; glyph: "b"; } Key { width: 43; glyph: "n"; } Key { width: 43; glyph: "m"; } - Key { width: 43; glyph: "_"; } + Key { width: 43; glyph: "-"; } Key { width: 43; glyph: "/"; } Key { width: 43; glyph: "?"; } } @@ -335,8 +249,10 @@ Rectangle { Key { width: 231; glyph: " "; } Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } - Key { width: 43; glyph: "\u276C"; } - Key { width: 43; glyph: "\u276D"; } + Key { + fontFamily: hiFiGlyphs.name; + width: 86; glyph: "\ue02b"; + } } } @@ -423,8 +339,10 @@ Rectangle { Key { width: 231; glyph: " "; } Key { width: 43; glyph: ","; } Key { width: 43; glyph: "."; } - Key { width: 43; glyph: "\u276C"; } - Key { width: 43; glyph: "\u276D"; } + Key { + fontFamily: hiFiGlyphs.name; + width: 86; glyph: "\ue02b"; + } } } } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 8333e87799..24e1006083 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1038,6 +1038,7 @@ static const uint8_t BACKSPACE_SYMBOL[] = { 0xE2, 0x86, 0x90, 0x00 }; static const uint8_t LEFT_ARROW[] = { 0xE2, 0x9D, 0xAC, 0x00 }; static const uint8_t RIGHT_ARROW[] = { 0xE2, 0x9D, 0xAD, 0x00 }; static const uint8_t RETURN_SYMBOL[] = { 0xE2, 0x8F, 0x8E, 0x00 }; +static const uint8_t COLLAPSE_KEYBOARD[] = { 0xEE, 0x80, 0xAB, 0x00 }; static const char PUNCTUATION_STRING[] = "123"; static const char ALPHABET_STRING[] = "abc"; @@ -1061,6 +1062,9 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid if (equals(utf8Key, SHIFT_ARROW) || equals(utf8Key, NUMERIC_SHIFT_ARROW) || equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) { return; // ignore + } else if (equals(utf8Key, COLLAPSE_KEYBOARD)) { + lowerKeyboard(); + return; } else if (equals(utf8Key, BACKSPACE_SYMBOL)) { scanCode = Qt::Key_Backspace; keyString = "\x08"; From 4d11f9a434eb2530f3a5d3e413d256d779bdfea2 Mon Sep 17 00:00:00 2001 From: beholder Date: Tue, 7 Nov 2017 23:13:29 +0300 Subject: [PATCH 126/171] increase font pixel size for 'collapse keyboard' to 34px --- interface/resources/qml/controls-uit/Key.qml | 1 + interface/resources/qml/controls-uit/Keyboard.qml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index ebdfff36c0..314149ca6e 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -12,6 +12,7 @@ Item { property bool toggled: false // is this button currently toggled? property alias mouseArea: mouseArea1 property alias fontFamily: letter.font.family; + property alias fontPixelSize: letter.font.pixelSize function resetToggledMode(mode) { toggled = mode; diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 5974ffe7bc..1865e437e5 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -251,6 +251,7 @@ Rectangle { Key { width: 43; glyph: "."; } Key { fontFamily: hiFiGlyphs.name; + fontPixelSize: 34; width: 86; glyph: "\ue02b"; } } @@ -341,6 +342,7 @@ Rectangle { Key { width: 43; glyph: "."; } Key { fontFamily: hiFiGlyphs.name; + fontPixelSize: 34; width: 86; glyph: "\ue02b"; } } From 0bc95998c498dcd1de8fdb766fe97392c8f7e2ee Mon Sep 17 00:00:00 2001 From: beholder Date: Wed, 8 Nov 2017 02:05:58 +0300 Subject: [PATCH 127/171] a few more adjustments based on discussion with Mukul --- interface/resources/qml/controls-uit/Key.qml | 2 ++ interface/resources/qml/controls-uit/Keyboard.qml | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index 314149ca6e..b0e965e79f 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -13,6 +13,8 @@ Item { property alias mouseArea: mouseArea1 property alias fontFamily: letter.font.family; property alias fontPixelSize: letter.font.pixelSize + property alias verticalAlignment: letter.verticalAlignment + property alias letterAnchors: letter.anchors function resetToggledMode(mode) { toggled = mode; diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 1865e437e5..76b66178d4 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -251,7 +251,9 @@ Rectangle { Key { width: 43; glyph: "."; } Key { fontFamily: hiFiGlyphs.name; - fontPixelSize: 34; + fontPixelSize: 48; + letterAnchors.topMargin: -4; + verticalAlignment: Text.AlignVCenter; width: 86; glyph: "\ue02b"; } } @@ -342,7 +344,9 @@ Rectangle { Key { width: 43; glyph: "."; } Key { fontFamily: hiFiGlyphs.name; - fontPixelSize: 34; + fontPixelSize: 48; + letterAnchors.topMargin: -4; + verticalAlignment: Text.AlignVCenter; width: 86; glyph: "\ue02b"; } } From d1969d649a0e7f8a22791181a48e1d87fe77b460 Mon Sep 17 00:00:00 2001 From: beholder Date: Thu, 9 Nov 2017 22:33:16 +0300 Subject: [PATCH 128/171] fix not collapsing keyboard --- .../resources/qml/hifi/dialogs/TabletRunningScripts.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 80c1b58444..83f91c78c5 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -32,6 +32,8 @@ Rectangle { color: hifi.colors.baseGray + property bool keyboardEnabled: HMD.active + property bool keyboardRaised: false LetterboxMessage { id: letterBoxMessage @@ -380,7 +382,7 @@ Rectangle { Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i") onActiveFocusChanged: { // raise the keyboard - keyboard.raised = activeFocus; + root.keyboardRaised = activeFocus; // scroll to the bottom of the content area. if (activeFocus) { @@ -481,7 +483,7 @@ Rectangle { HifiControls.Keyboard { id: keyboard - raised: false + raised: parent.keyboardEnabled && parent.keyboardRaised numeric: false anchors { bottom: parent.bottom From 5fcde1186afb2dd3cb48dbb1b9e05c8f7771ce12 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 10 Nov 2017 03:54:03 +0300 Subject: [PATCH 129/171] hide keyboard before showing to solve clearing 'mirrorText' on jumping between input fields without hiding keyboard --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 24e1006083..01f8f4580a 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1133,6 +1133,10 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n item->setProperty("passwordField", QVariant(passwordField)); } + if (raised) { + item->setProperty("keyboardRaised", QVariant(!raised)); + } + item->setProperty("keyboardRaised", QVariant(raised)); return; } From ba4c0f189e9600921efa5c4107858775b04b6de3 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 10 Nov 2017 10:25:29 -0800 Subject: [PATCH 130/171] code review feedback removed discontinuity in safeDeltaTime, which is used to prevent division by zero. --- interface/src/LODManager.cpp | 3 ++- libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 8f01296e1c..01ccbd0d9a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -54,7 +54,8 @@ void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float delta float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET; float maxTime = glm::max(renderTime, engineRunTime); const float BLEND_TIMESCALE = 0.3f; // sec - const float safeDeltaTime = (deltaTimeSec == 0.0f) ? 0.001f : deltaTimeSec; + const float MIN_DELTA_TIME = 0.001f; + const float safeDeltaTime = glm::max(deltaTimeSec, MIN_DELTA_TIME); float blend = BLEND_TIMESCALE / safeDeltaTime; if (blend > 1.0f) { blend = 1.0f; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 2335095056..49d2431098 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -453,7 +453,8 @@ void Avatar::applyPositionDelta(const glm::vec3& delta) { void Avatar::measureMotionDerivatives(float deltaTime) { PerformanceTimer perfTimer("derivatives"); // linear - const float safeDeltaTime = (deltaTime == 0.0f) ? 0.001f : deltaTime; + const float MIN_DELTA_TIME = 0.001f; + const float safeDeltaTime = glm::max(deltaTime, MIN_DELTA_TIME); float invDeltaTime = 1.0f / safeDeltaTime; // Floating point error prevents us from computing velocity in a naive way // (e.g. vel = (pos - oldPos) / dt) so instead we use _positionOffsetAccumulator. From bf576e63fe49b91e0056c5ea97a2dffe4172bd91 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 10 Nov 2017 11:54:53 -0700 Subject: [PATCH 131/171] move constant to class definition --- interface/src/ui/overlays/Line3DOverlay.cpp | 4 +++- interface/src/ui/overlays/Line3DOverlay.h | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index a6b7242df2..eb19617bfc 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -16,9 +16,11 @@ #include "AbstractViewStateInterface.h" QString const Line3DOverlay::TYPE = "line3d"; +static const float DEFAULT_LINE_WIDTH = 0.02f; Line3DOverlay::Line3DOverlay() : - _geometryCacheID(DependencyManager::get()->allocateID()) + _geometryCacheID(DependencyManager::get()->allocateID()), + _lineWidth(DEFAULT_LINE_WIDTH) { } diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index 2a3c7caa99..2995363ad7 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -13,8 +13,6 @@ #include "Base3DOverlay.h" -static const float DEFAULT_LINE_WIDTH = 0.02f; - class Line3DOverlay : public Base3DOverlay { Q_OBJECT using Parent = Base3DOverlay; @@ -72,7 +70,7 @@ private: glm::vec3 _direction; // in parent frame float _length { 1.0 }; // in parent frame - float _lineWidth { DEFAULT_LINE_WIDTH }; + float _lineWidth { 0.0 }; float _glow { 0.0 }; int _geometryCacheID; }; From d53a29b958d40e752b1c342a2e1e2808c8727803 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 10 Nov 2017 12:24:19 -0700 Subject: [PATCH 132/171] correction --- interface/src/ui/overlays/Line3DOverlay.cpp | 4 +--- interface/src/ui/overlays/Line3DOverlay.h | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index eb19617bfc..a6b7242df2 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -16,11 +16,9 @@ #include "AbstractViewStateInterface.h" QString const Line3DOverlay::TYPE = "line3d"; -static const float DEFAULT_LINE_WIDTH = 0.02f; Line3DOverlay::Line3DOverlay() : - _geometryCacheID(DependencyManager::get()->allocateID()), - _lineWidth(DEFAULT_LINE_WIDTH) + _geometryCacheID(DependencyManager::get()->allocateID()) { } diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index 2995363ad7..79af937f23 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -70,7 +70,8 @@ private: glm::vec3 _direction; // in parent frame float _length { 1.0 }; // in parent frame - float _lineWidth { 0.0 }; + const float DEFAULT_LINE_WIDTH = 0.02f; + float _lineWidth { DEFAULT_LINE_WIDTH }; float _glow { 0.0 }; int _geometryCacheID; }; From c047a1d0a453fcc382c4d994eca0bc3f445c7096 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 9 Nov 2017 17:30:32 -0800 Subject: [PATCH 133/171] Rework perms wizard page --- domain-server/resources/web/css/style.css | 1 - domain-server/resources/web/header.html | 2 +- .../resources/web/wizard/css/style.css | 6 ++++ .../resources/web/wizard/index.shtml | 21 ++++--------- .../resources/web/wizard/js/wizard.js | 30 +++++++++++++++++++ 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 8b004687b9..547b903b15 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -307,7 +307,6 @@ table .headers + .headers td { margin-right: 20px; } -#visit-domain-link, .blue-link { font-size: 14px; text-decoration-line: underline; diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 7b07458784..1e32e9f02f 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -39,7 +39,7 @@
  • Settings
  • diff --git a/domain-server/resources/web/wizard/css/style.css b/domain-server/resources/web/wizard/css/style.css index dcb34ef887..cadba7453e 100644 --- a/domain-server/resources/web/wizard/css/style.css +++ b/domain-server/resources/web/wizard/css/style.css @@ -31,6 +31,12 @@ label { color: #373A3C; } +.wizard-link { + font-size: 16px; + font-weight: normal; + color: #2F80ED; +} + #admin-row { margin-top: 20px; margin-bottom: 20px; diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index fedf7a0599..a4dc646625 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -60,8 +60,7 @@

    - Add your High Fidelity username and any other usernames to grant administrator privileges. - + Add your High Fidelity username and any other usernames to grant administrator privileges

    @@ -78,7 +77,7 @@

    - Who can connect to your domain? + Who can connect to your domain?

    @@ -87,25 +86,21 @@

    @@ -113,7 +108,7 @@

    - Who can rez items in your domain? + Who can rez items in your domain?

    @@ -122,25 +117,21 @@

    diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 1af3f305b7..41dc06d6c8 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -56,6 +56,36 @@ $(document).ready(function(){ exploreSettings(); }); + $('input[type=radio][name=connect-radio]').change(function() { + var inputs = $('input[type=radio][name=rez-radio]'); + var disabled = []; + + switch (this.value) { + case 'none': + disabled = inputs.splice(1); + break; + case 'friends': + disabled = inputs.splice(2); + break; + case 'logged-in': + disabled = inputs.splice(3); + break; + case 'everyone': + disabled = inputs.splice(4); + break; + } + + $.each(inputs, function() { + $(this).prop('disabled', false); + }); + $.each(disabled, function() { + if ($(this).prop('checked')) { + $(inputs.last()).prop('checked', true); + } + $(this).prop('disabled', true); + }); + }); + reloadSettings(function(success) { if (success) { getDomainFromAPI(); From 2782ae03c573a5e507ea75d56b6e36f336026b74 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 9 Nov 2017 18:23:00 -0800 Subject: [PATCH 134/171] Add back buttons --- domain-server/resources/web/wizard/index.shtml | 12 +++++++++--- domain-server/resources/web/wizard/js/wizard.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index a4dc646625..192997fb66 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -137,9 +137,12 @@
    -
    +
    + +
    +
    -
    +
    @@ -179,7 +182,10 @@
    -
    +
    + +
    +
    diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 41dc06d6c8..75d0ca6c41 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -108,7 +108,7 @@ function setupWizardSteps() { if (Settings.data.values.wizard.cloud_domain) { $('.desktop-only').remove(); - $('.wizard-step').find('.back-button').hide(); + $('.wizard-step:first').find('.back-button').hide(); steps = $('.wizard-step'); $(steps).each(function(i) { From 796909d366042e29ebf4c9576f558b96ce07ea56 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 10 Nov 2017 16:19:49 -0800 Subject: [PATCH 135/171] Permissions page tweaks --- .../resources/web/wizard/index.shtml | 10 ++++----- .../resources/web/wizard/js/wizard.js | 21 ++++++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index 192997fb66..a81738517f 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -60,7 +60,7 @@

    - Add your High Fidelity username and any other usernames to grant administrator privileges + Add your High Fidelity username and any other usernames to grant administrator privileges

    @@ -77,7 +77,7 @@

    - Who can connect to your domain? + Who can connect to your domain?

    @@ -95,7 +95,7 @@

    @@ -108,7 +108,7 @@

    - Who can rez items in your domain? + Who can rez items in your domain?

    @@ -126,7 +126,7 @@

    diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 75d0ca6c41..11b7c3e524 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -10,6 +10,25 @@ $(document).ready(function(){ $('[data-toggle="tooltip"]').tooltip(); + $('.fake-link').on('click', function() { + return false; + }); + $('.perms-link').on('click', function() { + var modal_body = '

    '; + modal_body += 'None - No one will have permissions. Only you and the users your have given administrator privileges to will have permissions.

    '; + modal_body += 'Friends - Users who are your Friends in High Fidelity.

    '; + modal_body += 'Users logged into High Fidelity - Users who are currently logged into High Fidelity.

    '; + modal_body += 'Everyone - Anyone who uses High Fidelity.'; + modal_body += '
    '; + + dialog = bootbox.dialog({ + title: "User definition", + message: modal_body, + closeButton: true + }); + return false; + }); + $('body').on('click', '.next-button', function() { goToNextStep(); }); @@ -116,7 +135,7 @@ function setupWizardSteps() { }); $('#permissions-description').html('You have been assigned administrator privileges to this domain.'); - $('#admin-description').html('Add more High Fidelity usernames to grant administrator privileges.'); + $('#admin-description').html('Add more High Fidelity usernames'); } else { $('.cloud-only').remove(); $('#save-permissions').text("Finish"); From 9cd8f372f20e43840340de7ee2632d078d2f01d3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 10 Nov 2017 16:20:49 -0800 Subject: [PATCH 136/171] Fix race condition --- domain-server/resources/web/wizard/js/wizard.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 11b7c3e524..524514ead5 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -2,6 +2,8 @@ var Metaverse = { accessToken: null } +var currentStepNumber; + $(document).ready(function(){ Strings.ADD_PLACE_NOT_CONNECTED_MESSAGE = "You must have an access token to query your High Fidelity places.

    " + "Please go back and connect your account."; @@ -122,7 +124,7 @@ $(document).ready(function(){ }); function setupWizardSteps() { - var stepsCompleted = Settings.data.values.wizard.steps_completed; + currentStepNumber = Settings.data.values.wizard.steps_completed; var steps = null; if (Settings.data.values.wizard.cloud_domain) { @@ -145,12 +147,12 @@ function setupWizardSteps() { $(this).children(".step-title").text("Step " + (i + 1) + " of " + steps.length); }); - if (stepsCompleted == 0) { + if (currentStepNumber == 0) { $('#skip-wizard-button').show(); } } - var currentStep = steps[stepsCompleted]; + var currentStep = steps[currentStepNumber]; $(currentStep).show(); } @@ -253,7 +255,7 @@ function goToNextStep() { currentStep.hide(); nextStep.show(); - var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1; + currentStepNumber += 1; postSettings({ "wizard": { @@ -282,7 +284,7 @@ function goToPreviousStep() { currentStep.hide(); previousStep.show(); - var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) - 1; + currentStepNumber -= 1; postSettings({ "wizard": { @@ -488,7 +490,7 @@ function saveUsernamePassword() { return; } - var currentStepNumber = parseInt(Settings.data.values.wizard.steps_completed) + 1; + currentStepNumber += 1; var formJSON = { "security": { From 163de649bf2b5fa5b11b2bc4da34afd813a7c242 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 10 Nov 2017 17:44:09 -0800 Subject: [PATCH 137/171] prevent rendering HUD elements in secondary camera --- libraries/render-utils/src/RenderDeferredTask.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ac4e717d60..79428979b9 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -438,6 +438,11 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_context); + // We do not want to render HUD elements in secondary camera + if (renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + return; + } + // Grab the HUD texture gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) { if (renderContext->args->_hudOperator) { From 067436a743c80b06b40862836ef8833edb3b0f0c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 10 Nov 2017 17:25:27 -0800 Subject: [PATCH 138/171] CR --- domain-server/resources/web/wizard/index.shtml | 2 +- domain-server/resources/web/wizard/js/wizard.js | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index a81738517f..39b72f58a5 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -60,7 +60,7 @@

    - Add your High Fidelity username and any other usernames to grant administrator privileges + Add your High Fidelity username and any other usernames to grant administrator privileges

    diff --git a/domain-server/resources/web/wizard/js/wizard.js b/domain-server/resources/web/wizard/js/wizard.js index 524514ead5..57e85973f4 100644 --- a/domain-server/resources/web/wizard/js/wizard.js +++ b/domain-server/resources/web/wizard/js/wizard.js @@ -11,10 +11,7 @@ $(document).ready(function(){ $('#connect-account-btn').attr('href', URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true"); $('[data-toggle="tooltip"]').tooltip(); - - $('.fake-link').on('click', function() { - return false; - }); + $('.perms-link').on('click', function() { var modal_body = '
    '; modal_body += 'None - No one will have permissions. Only you and the users your have given administrator privileges to will have permissions.

    '; From 8f133fc7fa7ed1b742a0063cd40d653f09683582 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 10 Nov 2017 18:12:43 -0800 Subject: [PATCH 139/171] Congratulation page styling fixes --- .../resources/web/wizard/css/style.css | 12 +++++++-- .../resources/web/wizard/index.shtml | 25 +++++++++---------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/domain-server/resources/web/wizard/css/style.css b/domain-server/resources/web/wizard/css/style.css index cadba7453e..dfb576ebba 100644 --- a/domain-server/resources/web/wizard/css/style.css +++ b/domain-server/resources/web/wizard/css/style.css @@ -90,6 +90,14 @@ label { height: 169px; } -#visit-domain-row { - margin-bottom: 68px; +#congratulation-text { + margin-bottom: 59px; +} + +#visit-domain-checkbox { + margin-bottom: 23px; +} + +#visit-domain-checkbox label { + margin: 0 0; } diff --git a/domain-server/resources/web/wizard/index.shtml b/domain-server/resources/web/wizard/index.shtml index 39b72f58a5..9d4d8b7381 100644 --- a/domain-server/resources/web/wizard/index.shtml +++ b/domain-server/resources/web/wizard/index.shtml @@ -191,29 +191,28 @@
    -