diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index c4e0c85642..47fb610469 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -2,6 +2,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.2 import QtWebChannel 1.0 import QtWebEngine 1.2 +import FileTypeProfile 1.0 import "controls-uit" import "styles" as HifiStyles @@ -216,6 +217,11 @@ ScrollingWindow { WebChannel.id: "eventBridgeWrapper" property var eventBridge; } + + profile: FileTypeProfile { + id: webviewProfile + storageName: "qmlWebEngine" + } webChannel.registeredObjects: [eventBridgeWrapper] diff --git a/interface/resources/qml/controls/WebEntityView.qml b/interface/resources/qml/controls/WebEntityView.qml new file mode 100644 index 0000000000..a3d5fe903b --- /dev/null +++ b/interface/resources/qml/controls/WebEntityView.qml @@ -0,0 +1,22 @@ +// +// WebEntityView.qml +// +// Created by Kunal Gosar on 16 March 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 +// + +import QtQuick 2.5 +import "." +import FileTypeProfile 1.0 + +WebView { + viewProfile: FileTypeProfile { + id: webviewProfile + storageName: "qmlWebEngine" + } + + urlTag: "noDownload=true"; +} diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index a3badd7e1f..52f277520f 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -10,6 +10,7 @@ Item { property alias eventBridge: eventBridgeWrapper.eventBridge property alias canGoBack: root.canGoBack; property var goBack: root.goBack; + property alias urlTag: root.urlTag property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardRaised: false property bool punctuationMode: false @@ -27,6 +28,8 @@ Item { WebChannel.id: "eventBridgeWrapper" property var eventBridge; } + + property alias viewProfile: root.profile WebEngineView { id: root @@ -66,6 +69,8 @@ Item { injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. worldId: WebEngineScript.MainWorld } + + property string urlTag: "noDownload=false"; userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] @@ -94,6 +99,7 @@ Item { // Required to support clicking on "hifi://" links if (WebEngineView.LoadStartedStatus == loadRequest.status) { var url = loadRequest.url.toString(); + url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag; if (urlHandler.canHandleUrl(url)) { if (urlHandler.handleUrl(url)) { root.stop(); diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index 8905ed9c17..e328805d74 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -12,6 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "../styles-uit" +import "../controls-uit" Item { property var dialogTitleText : ""; @@ -67,6 +68,29 @@ Item { verticalAlignment: Text.AlignTop; } + HiFiGlyphs { + id: closeGlyphButton; + text: hifi.glyphs.close; + size: 32; + anchors.verticalCenter: dialogTitle.verticalCenter; + anchors.right: parent.right; + anchors.rightMargin: 20; + MouseArea { + anchors.fill: closeGlyphButton; + hoverEnabled: true; + onEntered: { + parent.text = hifi.glyphs.closeInverted; + } + onExited: { + parent.text = hifi.glyphs.close; + } + onClicked: { + combo.visible = false; + } + } + } + + ListModel { id: comboListViewModel; } @@ -92,8 +116,7 @@ Item { color: selectedOptionIndex === index ? '#cee6ff' : 'white'; Rectangle { id: comboOptionSelected; - visible: selectedOptionIndex === index ? true : false; - color: hifi.colors.blueAccent; + color: selectedOptionIndex == index ? hifi.colors.blueAccent : 'white'; anchors.left: parent.left; anchors.leftMargin: 20; anchors.top: parent.top; @@ -102,7 +125,7 @@ Item { height: width; radius: width; border.width: 3; - border.color: hifi.colors.blueHighlight; + border.color: selectedOptionIndex === index ? hifi.colors.blueHighlight: hifi.colors.lightGrayText; } diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index e50d1de547..754876b2c1 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -85,6 +85,28 @@ Item { wrapMode: Text.WordWrap textFormat: Text.StyledText } + HiFiGlyphs { + id: closeGlyphButton + text: hifi.glyphs.close + size: headerTextPixelSize + anchors.top: parent.top + anchors.topMargin: -20 + anchors.right: parent.right + anchors.rightMargin: -25 + MouseArea { + anchors.fill: closeGlyphButton + hoverEnabled: true + onEntered: { + parent.text = hifi.glyphs.closeInverted; + } + onExited: { + parent.text = hifi.glyphs.close; + } + onClicked: { + letterbox.visible = false; + } + } + } } // Popup Text Text { diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 809ff24b62..d785a8582c 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -308,12 +308,11 @@ Rectangle { MouseArea { anchors.fill: parent; hoverEnabled: true; - enabled: activeTab === "connectionsTab"; onClicked: letterbox(hifi.glyphs.question, "Connections and Friends", - "Purple borders around profile pictures are Connections.
" + + "Purple borders around profile pictures represent Connections.
" + "When your availability is set to Everyone, Connections can see your username and location.

" + - "Green borders around profile pictures are Friends.
" + + "Green borders around profile pictures represent Friends.
" + "When your availability is set to Friends, only Friends can see your username and location."); onEntered: connectionsHelpText.color = hifi.colors.blueHighlight; onExited: connectionsHelpText.color = hifi.colors.blueAccent; @@ -849,11 +848,6 @@ Rectangle { pal.sendToScript({method: newValue ? 'addFriend' : 'removeFriend', params: model.userName}); UserActivityLogger["palAction"](newValue ? styleData.role : "un-" + styleData.role, model.sessionId); - - // http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html#creating-property-bindings-from-javascript - // I'm using an explicit binding here because clicking a checkbox breaks the implicit binding as set by - // "checked:" statement above. - checked = Qt.binding(function() { return (model["connection"] === "friend" ? true : false)}); } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e19eea0a2e..0c7347d909 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -142,6 +142,7 @@ #include "ModelPackager.h" #include "networking/HFWebEngineProfile.h" #include "networking/HFTabletWebEngineProfile.h" +#include "networking/FileTypeProfile.h" #include "scripting/TestScriptingInterface.h" #include "scripting/AccountScriptingInterface.h" #include "scripting/AssetMappingsScriptingInterface.h" @@ -218,6 +219,7 @@ static const QString FST_EXTENSION = ".fst"; static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; +static const QString WEB_VIEW_TAG = "noDownload=true"; static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; @@ -1934,6 +1936,7 @@ void Application::initializeUi() { qmlRegisterType("HFWebEngineProfile", 1, 0, "HFWebEngineProfile"); qmlRegisterType("HFTabletWebEngineProfile", 1, 0, "HFTabletWebEngineProfile"); + qmlRegisterType("FileTypeProfile", 1, 0, "FileTypeProfile"); auto offscreenUi = DependencyManager::get(); offscreenUi->create(_glWidget->qglContext()); @@ -5036,7 +5039,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // TODO fix shadows and make them use the GPU library // The pending changes collecting the changes here - render::PendingChanges pendingChanges; + render::Transaction transaction; // FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities // Background rendering decision @@ -5044,7 +5047,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se auto backgroundRenderData = make_shared(); auto backgroundRenderPayload = make_shared(backgroundRenderData); BackgroundRenderData::_item = _main3DScene->allocateID(); - pendingChanges.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); + transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); } // Assuming nothing get's rendered through that @@ -5062,7 +5065,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se static_cast(RenderArgs::RENDER_DEBUG_HULLS)); } renderArgs->_debugFlags = renderDebugFlags; - //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges); + //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction); } } @@ -5074,9 +5077,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se WorldBoxRenderData::_item = _main3DScene->allocateID(); - pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload); + transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload); } else { - pendingChanges.updateItem(WorldBoxRenderData::_item, + transaction.updateItem(WorldBoxRenderData::_item, [](WorldBoxRenderData& payload) { payload._val++; }); @@ -5089,10 +5092,10 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se } { - PerformanceTimer perfTimer("SceneProcessPendingChanges"); - _main3DScene->enqueuePendingChanges(pendingChanges); + PerformanceTimer perfTimer("SceneProcessTransaction"); + _main3DScene->enqueueTransaction(transaction); - _main3DScene->processPendingChangesQueue(); + _main3DScene->processTransactionQueue(); } // For now every frame pass the renderContext @@ -5545,7 +5548,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri bool Application::canAcceptURL(const QString& urlString) const { QUrl url(urlString); - if (urlString.startsWith(HIFI_URL_SCHEME)) { + if (url.query().contains(WEB_VIEW_TAG)) { + return false; + } else if (urlString.startsWith(HIFI_URL_SCHEME)) { return true; } QHashIterator i(_acceptedExtensions); @@ -5653,7 +5658,9 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { QUrl scriptURL { scriptFilenameOrURL }; if (scriptURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) { - shortName = shortName.mid(shortName.lastIndexOf('/') + 1); + int startIndex = shortName.lastIndexOf('/') + 1; + int endIndex = shortName.lastIndexOf('?'); + shortName = shortName.mid(startIndex, endIndex - startIndex); } QString message = "Would you like to run this script:\n" + shortName; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ade98c63d8..b6ec45b308 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -476,34 +476,34 @@ static TextRenderer3D* textRenderer(TextRendererType type) { return displayNameRenderer; } -bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { +bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction) { auto avatarPayload = new render::Payload(self); auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); _renderItemID = scene->allocateID(); - pendingChanges.resetItem(_renderItemID, avatarPayloadPointer); - _skeletonModel->addToScene(scene, pendingChanges); + transaction.resetItem(_renderItemID, avatarPayloadPointer); + _skeletonModel->addToScene(scene, transaction); for (auto& attachmentModel : _attachmentModels) { - attachmentModel->addToScene(scene, pendingChanges); + attachmentModel->addToScene(scene, transaction); } _inScene = true; return true; } -void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_renderItemID); +void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::Transaction& transaction) { + transaction.removeItem(_renderItemID); render::Item::clearID(_renderItemID); - _skeletonModel->removeFromScene(scene, pendingChanges); + _skeletonModel->removeFromScene(scene, transaction); for (auto& attachmentModel : _attachmentModels) { - attachmentModel->removeFromScene(scene, pendingChanges); + attachmentModel->removeFromScene(scene, transaction); } _inScene = false; } -void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) { +void Avatar::updateRenderItem(render::Transaction& transaction) { if (render::Item::isValidID(_renderItemID)) { - pendingChanges.updateItem>(_renderItemID, [](render::Payload& p) {}); + transaction.updateItem>(_renderItemID, [](render::Payload& p) {}); } } @@ -680,24 +680,24 @@ void Avatar::fixupModelsInScene() { // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { - _skeletonModel->removeFromScene(scene, pendingChanges); - _skeletonModel->addToScene(scene, pendingChanges); + _skeletonModel->removeFromScene(scene, transaction); + _skeletonModel->addToScene(scene, transaction); } for (auto attachmentModel : _attachmentModels) { if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { - attachmentModel->removeFromScene(scene, pendingChanges); - attachmentModel->addToScene(scene, pendingChanges); + attachmentModel->removeFromScene(scene, transaction); + attachmentModel->addToScene(scene, transaction); } } for (auto attachmentModelToRemove : _attachmentsToRemove) { - attachmentModelToRemove->removeFromScene(scene, pendingChanges); + attachmentModelToRemove->removeFromScene(scene, transaction); } _attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end()); _attachmentsToRemove.clear(); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1422,14 +1422,14 @@ QList Avatar::getSkeleton() { void Avatar::addToScene(AvatarSharedPointer myHandle) { render::ScenePointer scene = qApp->getMain3DScene(); if (scene) { - render::PendingChanges pendingChanges; + render::Transaction transaction; auto nodelist = DependencyManager::get(); if (DependencyManager::get()->shouldRenderAvatars() && !nodelist->isIgnoringNode(getSessionUUID()) && !nodelist->isRadiusIgnoringNode(getSessionUUID())) { - addToScene(myHandle, scene, pendingChanges); + addToScene(myHandle, scene, transaction); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } else { qCWarning(interfaceapp) << "AvatarManager::addAvatar() : Unexpected null scene, possibly during application shutdown"; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ba7e1c617e..7fadf96e11 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -82,12 +82,12 @@ public: virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges); + render::Transaction& transaction); void removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges); + render::Transaction& transaction); - void updateRenderItem(render::PendingChanges& pendingChanges); + void updateRenderItem(render::Transaction& transaction); virtual void postUpdate(float deltaTime); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 6152148887..48914908c6 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -104,11 +104,11 @@ void AvatarManager::init() { this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection); render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; if (DependencyManager::get()->shouldRenderAvatars()) { - _myAvatar->addToScene(_myAvatar, scene, pendingChanges); + _myAvatar->addToScene(_myAvatar, scene, transaction); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } void AvatarManager::updateMyAvatar(float deltaTime) { @@ -192,7 +192,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { return false; }); - render::PendingChanges pendingChanges; + render::Transaction transaction; uint64_t startTime = usecTimestampNow(); const uint64_t UPDATE_BUDGET = 2000; // usec uint64_t updateExpiry = startTime + UPDATE_BUDGET; @@ -228,7 +228,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { numAvatarsUpdated++; } avatar->simulate(deltaTime, inView); - avatar->updateRenderItem(pendingChanges); + avatar->updateRenderItem(transaction); avatar->setLastRenderUpdateTime(startTime); } else { // we've spent our full time budget --> bail on the rest of the avatar updates @@ -262,7 +262,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { _avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC; _numAvatarsUpdated = numAvatarsUpdated; _numAvatarsNotUpdated = numAVatarsNotUpdated; - qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges); + qApp->getMain3DScene()->enqueueTransaction(transaction); simulateAvatarFades(deltaTime); } @@ -283,13 +283,13 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { const float MIN_FADE_SCALE = MIN_AVATAR_SCALE; render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, pendingChanges); + avatar->removeFromScene(*fadingIterator, scene, transaction); // only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine if (_motionStatesToRemoveFromPhysics.empty()) { fadingIterator = _avatarFades.erase(fadingIterator); @@ -302,7 +302,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { ++fadingIterator; } } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } AvatarSharedPointer AvatarManager::newSharedAvatar() { @@ -479,17 +479,17 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; - avatar->addToScene(avatar, scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + avatar->addToScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); } } else { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; - avatar->removeFromScene(avatar, scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + avatar->removeFromScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); } } } diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index f479ed9a35..c7d25d3151 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -205,10 +205,10 @@ void CauterizedModel::updateRenderItems() { uint32_t deleteGeometryCounter = self->getGeometryCounter(); - render::PendingChanges pendingChanges; + render::Transaction transaction; QList keys = self->getRenderItems().keys(); foreach (auto itemID, keys) { - pendingChanges.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { + transaction.updateItem(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) { if (data._model && data._model->isLoaded()) { // Ensure the model geometry was not reset between frames if (deleteGeometryCounter == data._model->getGeometryCounter()) { @@ -233,7 +233,7 @@ void CauterizedModel::updateRenderItems() { }); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); }); } else { Model::updateRenderItems(); diff --git a/interface/src/networking/FileTypeProfile.cpp b/interface/src/networking/FileTypeProfile.cpp new file mode 100644 index 0000000000..6fcd8df669 --- /dev/null +++ b/interface/src/networking/FileTypeProfile.cpp @@ -0,0 +1,26 @@ +// +// FileTypeProfile.cpp +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 "FileTypeProfile.h" + +#include "FileTypeRequestInterceptor.h" + +static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; + +FileTypeProfile::FileTypeProfile(QObject* parent) : + QQuickWebEngineProfile(parent) +{ + static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)"; + setHttpUserAgent(WEB_ENGINE_USER_AGENT); + + auto requestInterceptor = new FileTypeRequestInterceptor(this); + setRequestInterceptor(requestInterceptor); +} diff --git a/interface/src/networking/FileTypeProfile.h b/interface/src/networking/FileTypeProfile.h new file mode 100644 index 0000000000..f922fd66de --- /dev/null +++ b/interface/src/networking/FileTypeProfile.h @@ -0,0 +1,25 @@ +// +// FileTypeProfile.h +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 +// + +#pragma once + +#ifndef hifi_FileTypeProfile_h +#define hifi_FileTypeProfile_h + +#include + +class FileTypeProfile : public QQuickWebEngineProfile { +public: + FileTypeProfile(QObject* parent = Q_NULLPTR); +}; + + +#endif // hifi_FileTypeProfile_h diff --git a/interface/src/networking/FileTypeRequestInterceptor.cpp b/interface/src/networking/FileTypeRequestInterceptor.cpp new file mode 100644 index 0000000000..91bacd46a6 --- /dev/null +++ b/interface/src/networking/FileTypeRequestInterceptor.cpp @@ -0,0 +1,21 @@ +// +// FileTypeRequestInterceptor.cpp +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 "FileTypeRequestInterceptor.h" + +#include + +#include "RequestFilters.h" + +void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { + RequestFilters::interceptHFWebEngineRequest(info); + RequestFilters::interceptFileType(info); +} diff --git a/interface/src/networking/FileTypeRequestInterceptor.h b/interface/src/networking/FileTypeRequestInterceptor.h new file mode 100644 index 0000000000..be971daf7a --- /dev/null +++ b/interface/src/networking/FileTypeRequestInterceptor.h @@ -0,0 +1,26 @@ +// +// FileTypeRequestInterceptor.h +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 +// + +#pragma once + +#ifndef hifi_FileTypeRequestInterceptor_h +#define hifi_FileTypeRequestInterceptor_h + +#include + +class FileTypeRequestInterceptor : public QWebEngineUrlRequestInterceptor { +public: + FileTypeRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {}; + + virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override; +}; + +#endif // hifi_FileTypeRequestInterceptor_h diff --git a/interface/src/networking/HFWebEngineRequestInterceptor.cpp b/interface/src/networking/HFWebEngineRequestInterceptor.cpp index f6b0914f08..59897d427f 100644 --- a/interface/src/networking/HFWebEngineRequestInterceptor.cpp +++ b/interface/src/networking/HFWebEngineRequestInterceptor.cpp @@ -10,35 +10,12 @@ // #include "HFWebEngineRequestInterceptor.h" -#include "NetworkingConstants.h" #include #include - -bool isAuthableHighFidelityURL(const QUrl& url) { - static const QStringList HF_HOSTS = { - "highfidelity.com", "highfidelity.io", - "metaverse.highfidelity.com", "metaverse.highfidelity.io" - }; - const auto& scheme = url.scheme(); - const auto& host = url.host(); - - return (scheme == "https" && HF_HOSTS.contains(host)) || - ((scheme == NetworkingConstants::METAVERSE_SERVER_URL.scheme()) && (host == NetworkingConstants::METAVERSE_SERVER_URL.host())); -} +#include "RequestFilters.h" void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { - // check if this is a request to a highfidelity URL - if (isAuthableHighFidelityURL(info.requestUrl())) { - // if we have an access token, add it to the right HTTP header for authorization - auto accountManager = DependencyManager::get(); - - if (accountManager->hasValidAccessToken()) { - static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization"; - - QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; - info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit()); - } - } + RequestFilters::interceptHFWebEngineRequest(info); } diff --git a/interface/src/networking/RequestFilters.cpp b/interface/src/networking/RequestFilters.cpp new file mode 100644 index 0000000000..fedde94f15 --- /dev/null +++ b/interface/src/networking/RequestFilters.cpp @@ -0,0 +1,65 @@ +// +// RequestFilters.cpp +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 "RequestFilters.h" +#include "NetworkingConstants.h" + +#include + +#include + +namespace { + + bool isAuthableHighFidelityURL(const QUrl& url) { + static const QStringList HF_HOSTS = { + "highfidelity.com", "highfidelity.io", + "metaverse.highfidelity.com", "metaverse.highfidelity.io" + }; + const auto& scheme = url.scheme(); + const auto& host = url.host(); + + return (scheme == "https" && HF_HOSTS.contains(host)) || + ((scheme == NetworkingConstants::METAVERSE_SERVER_URL.scheme()) && (host == NetworkingConstants::METAVERSE_SERVER_URL.host())); + } + + bool isScript(const QString filename) { + return filename.endsWith(".js", Qt::CaseInsensitive); + } + + bool isJSON(const QString filename) { + return filename.endsWith(".json", Qt::CaseInsensitive); + } + +} + +void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) { + // check if this is a request to a highfidelity URL + if (isAuthableHighFidelityURL(info.requestUrl())) { + // if we have an access token, add it to the right HTTP header for authorization + auto accountManager = DependencyManager::get(); + + if (accountManager->hasValidAccessToken()) { + static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization"; + + QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; + info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit()); + } + } +} + +void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) { + QString filename = info.requestUrl().fileName(); + if (isScript(filename) || isJSON(filename)) { + static const QString CONTENT_HEADER = "Accept"; + static const QString TYPE_VALUE = "text/plain,text/html"; + info.setHttpHeader(CONTENT_HEADER.toLocal8Bit(), TYPE_VALUE.toLocal8Bit()); + } +} diff --git a/interface/src/networking/RequestFilters.h b/interface/src/networking/RequestFilters.h new file mode 100644 index 0000000000..0d7d66e155 --- /dev/null +++ b/interface/src/networking/RequestFilters.h @@ -0,0 +1,28 @@ +// +// RequestFilters.h +// interface/src/networking +// +// Created by Kunal Gosar on 2017-03-10. +// 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 +// + +#pragma once + +#ifndef hifi_RequestFilters_h +#define hifi_RequestFilters_h + +#include +#include + +class RequestFilters : public QObject { + Q_OBJECT + +public: + static void interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info); + static void interceptFileType(QWebEngineUrlRequestInfo& info); +}; + +#endif // hifi_RequestFilters_h diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 70b1fa4b71..d7057c6faa 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -199,9 +199,9 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; - pendingChanges.updateItem(itemID); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + transaction.updateItem(itemID); + scene->enqueueTransaction(transaction); } } } @@ -264,9 +264,9 @@ void Base3DOverlay::locationChanged(bool tellPhysics) { auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; - pendingChanges.updateItem(itemID); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + transaction.updateItem(itemID); + scene->enqueueTransaction(transaction); } } diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index a0f7c4e824..98ca7110ae 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -58,15 +58,15 @@ void ModelOverlay::update(float deltatime) { _isLoaded = _model->isActive(); } -bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - Volume3DOverlay::addToScene(overlay, scene, pendingChanges); - _model->addToScene(scene, pendingChanges); +bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) { + Volume3DOverlay::addToScene(overlay, scene, transaction); + _model->addToScene(scene, transaction); return true; } -void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - Volume3DOverlay::removeFromScene(overlay, scene, pendingChanges); - _model->removeFromScene(scene, pendingChanges); +void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) { + Volume3DOverlay::removeFromScene(overlay, scene, transaction); + _model->removeFromScene(scene, transaction); } void ModelOverlay::render(RenderArgs* args) { @@ -74,16 +74,16 @@ void ModelOverlay::render(RenderArgs* args) { // check to see if when we added our model to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; if (_model->needsFixupInScene()) { - _model->removeFromScene(scene, pendingChanges); - _model->addToScene(scene, pendingChanges); + _model->removeFromScene(scene, transaction); + _model->addToScene(scene, transaction); } _model->setVisibleInScene(_visible, scene); _model->setLayeredInFront(getDrawInFront(), scene); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } void ModelOverlay::setProperties(const QVariantMap& properties) { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index d5f709c2db..245688156f 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -36,8 +36,8 @@ public: virtual ModelOverlay* createClone() const override; - virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) override; + virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) override; void locationChanged(bool tellPhysics) override; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 764422019e..e3004bd9c6 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -196,14 +196,14 @@ float Overlay::updatePulse() { return _pulse; } -bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { +bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) { _renderItemID = scene->allocateID(); - pendingChanges.resetItem(_renderItemID, std::make_shared(overlay)); + transaction.resetItem(_renderItemID, std::make_shared(overlay)); return true; } -void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_renderItemID); +void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction) { + transaction.removeItem(_renderItemID); render::Item::clearID(_renderItemID); } diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 9ad4f0ba70..9849c71a1f 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -48,8 +48,8 @@ public: virtual AABox getBounds() const = 0; virtual bool supportsGetProperty() const { return true; } - virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); - virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); + virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction); + virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::Transaction& transaction); virtual const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 712342087d..61a283b88c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -78,7 +78,7 @@ void Overlays::update(float deltatime) { void Overlays::cleanupOverlaysToDelete() { if (!_overlaysToDelete.isEmpty()) { render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; { QWriteLocker lock(&_deleteLock); @@ -88,13 +88,13 @@ void Overlays::cleanupOverlaysToDelete() { auto itemID = overlay->getRenderItemID(); if (render::Item::isValidID(itemID)) { - overlay->removeFromScene(overlay, scene, pendingChanges); + overlay->removeFromScene(overlay, scene, transaction); } } while (!_overlaysToDelete.isEmpty()); } - if (pendingChanges._removedItems.size() > 0) { - scene->enqueuePendingChanges(pendingChanges); + if (transaction._removedItems.size() > 0) { + scene->enqueueTransaction(transaction); } } } @@ -197,9 +197,9 @@ OverlayID Overlays::addOverlay(Overlay::Pointer overlay) { _overlaysWorld[thisID] = overlay; render::ScenePointer scene = qApp->getMain3DScene(); - render::PendingChanges pendingChanges; - overlay->addToScene(overlay, scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + overlay->addToScene(overlay, scene, transaction); + scene->enqueueTransaction(transaction); } else { _overlaysHUD[thisID] = overlay; } diff --git a/libraries/animation/src/AnimationCache.cpp b/libraries/animation/src/AnimationCache.cpp index 6594482085..23c9d1d0b5 100644 --- a/libraries/animation/src/AnimationCache.cpp +++ b/libraries/animation/src/AnimationCache.cpp @@ -74,7 +74,7 @@ void AnimationReader::run() { // Parse the FBX directly from the QNetworkReply FBXGeometry::Pointer fbxgeo; if (_url.path().toLower().endsWith(".fbx")) { - fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path())); + fbxgeo.reset(readFBX(_data, QVariantHash(), _url)); } else { QString errorStr("usupported format"); emit onError(299, errorStr); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4843afd5b1..fd5e07918e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -127,11 +127,11 @@ void EntityTreeRenderer::clear() { // remove all entities from the scene auto scene = _viewState->getMain3DScene(); if (scene) { - render::PendingChanges pendingChanges; + render::Transaction transaction; foreach(auto entity, _entitiesInScene) { - entity->removeFromScene(entity, scene, pendingChanges); + entity->removeFromScene(entity, scene, transaction); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } else { qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown"; } @@ -951,11 +951,11 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { // here's where we remove the entity payload from the scene if (_entitiesInScene.contains(entityID)) { auto entity = _entitiesInScene.take(entityID); - render::PendingChanges pendingChanges; + render::Transaction transaction; auto scene = _viewState->getMain3DScene(); if (scene) { - entity->removeFromScene(entity, scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + entity->removeFromScene(entity, scene, transaction); + scene->enqueueTransaction(transaction); } else { qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), Unexpected null scene, possibly during application shutdown"; } @@ -973,13 +973,13 @@ void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) { void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) { // here's where we add the entity payload to the scene - render::PendingChanges pendingChanges; + render::Transaction transaction; auto scene = _viewState->getMain3DScene(); if (scene) { - if (entity->addToScene(entity, scene, pendingChanges)) { + if (entity->addToScene(entity, scene, transaction)) { _entitiesInScene.insert(entity->getEntityItemID(), entity); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } else { qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected null scene, possibly during application shutdown"; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 98271ddbbb..2f053924ab 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -54,7 +54,7 @@ namespace render { // Mixin class for implementing basic single item rendering class SimpleRenderableEntityItem { public: - bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { + bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) { _myItem = scene->allocateID(); auto renderData = std::make_shared(self, _myItem); @@ -64,13 +64,13 @@ public: makeEntityItemStatusGetters(self, statusGetters); renderPayload->addStatusGetters(statusGetters); - pendingChanges.resetItem(_myItem, renderPayload); + transaction.resetItem(_myItem, renderPayload); return true; } - void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_myItem); + void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) { + transaction.removeItem(_myItem); render::Item::clearID(_myItem); } @@ -79,14 +79,14 @@ public: return; } - render::PendingChanges pendingChanges; + render::Transaction transaction; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { - pendingChanges.updateItem(_myItem, [](RenderableEntityItemProxy& data) { + transaction.updateItem(_myItem, [](RenderableEntityItemProxy& data) { }); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } else { qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown"; } @@ -99,8 +99,8 @@ private: #define SIMPLE_RENDERABLE() \ public: \ - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { return _renderHelper.addToScene(self, scene, pendingChanges); } \ - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override { _renderHelper.removeFromScene(self, scene, pendingChanges); } \ + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override { return _renderHelper.addToScene(self, scene, transaction); } \ + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override { _renderHelper.removeFromScene(self, scene, transaction); } \ virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); _renderHelper.notifyChanged(); } \ virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); _renderHelper.notifyChanged(); } \ void checkFading() { \ diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index a7fcbf53ae..0b8592e678 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -27,7 +27,7 @@ RenderableLightEntityItem::RenderableLightEntityItem(const EntityItemID& entityI { } -bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { +bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) { _myItem = scene->allocateID(); auto renderItem = std::make_shared(); @@ -39,7 +39,7 @@ bool RenderableLightEntityItem::addToScene(EntityItemPointer self, std::shared_p makeEntityItemStatusGetters(self, statusGetters); renderPayload->addStatusGetters(statusGetters); - pendingChanges.resetItem(_myItem, renderPayload); + transaction.resetItem(_myItem, renderPayload); return true; } @@ -51,8 +51,8 @@ void RenderableLightEntityItem::somethingChangedNotification() { LightEntityItem::somethingChangedNotification(); } -void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_myItem); +void RenderableLightEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) { + transaction.removeItem(_myItem); render::Item::clearID(_myItem); } @@ -81,12 +81,12 @@ void RenderableLightEntityItem::notifyChanged() { return; } - render::PendingChanges pendingChanges; + render::Transaction transaction; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - updateLightFromEntity(pendingChanges); + updateLightFromEntity(transaction); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, @@ -103,13 +103,13 @@ bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& ori } -void RenderableLightEntityItem::updateLightFromEntity(render::PendingChanges& pendingChanges) { +void RenderableLightEntityItem::updateLightFromEntity(render::Transaction& transaction) { if (!render::Item::isValidID(_myItem)) { return; } - pendingChanges.updateItem(_myItem, [&](LightPayload& data) { + transaction.updateItem(_myItem, [&](LightPayload& data) { updateRenderItemFromEntity(data); }); } diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index 36ba0d6311..42a5dbc91a 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -28,12 +28,12 @@ public: BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; - void updateLightFromEntity(render::PendingChanges& pendingChanges); + void updateLightFromEntity(render::Transaction& transaction); - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; virtual void somethingChangedNotification() override; - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; virtual void locationChanged(bool tellPhysics = true) override; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 487a3e1e56..0cd5b718af 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -228,20 +228,20 @@ namespace render { } bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { + render::Transaction& transaction) { _myMetaItem = scene->allocateID(); auto renderData = std::make_shared(self); auto renderPayload = std::make_shared(renderData); - pendingChanges.resetItem(_myMetaItem, renderPayload); + transaction.resetItem(_myMetaItem, renderPayload); if (_model) { render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); // note: we don't mind if the model fails to add, we'll retry (in render()) until it succeeds - _model->addToScene(scene, pendingChanges, statusGetters); + _model->addToScene(scene, transaction, statusGetters); } // we've successfully added _myMetaItem so we always return true @@ -249,11 +249,11 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p } void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_myMetaItem); + render::Transaction& transaction) { + transaction.removeItem(_myMetaItem); render::Item::clearID(_myMetaItem); if (_model) { - _model->removeFromScene(scene, pendingChanges); + _model->removeFromScene(scene, transaction); } } @@ -467,15 +467,15 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } if (_model->needsFixupInScene()) { - render::PendingChanges pendingChanges; + render::Transaction transaction; - _model->removeFromScene(scene, pendingChanges); + _model->removeFromScene(scene, transaction); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, statusGetters); + _model->addToScene(scene, transaction, statusGetters); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } auto& currentURL = getParsedModelURL(); @@ -525,9 +525,9 @@ ModelPointer RenderableModelEntityItem::getModel(QSharedPointergetMain3DScene(); - render::PendingChanges pendingChanges; - _model->removeFromScene(scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + _model->removeFromScene(scene, transaction); + scene->enqueueTransaction(transaction); // release interest _myRenderer->releaseModel(_model); @@ -1226,10 +1226,10 @@ void RenderableModelEntityItem::locationChanged(bool tellPhysics) { } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - render::PendingChanges pendingChanges; + render::Transaction transaction; - pendingChanges.updateItem(myMetaItem); - scene->enqueuePendingChanges(pendingChanges); + transaction.updateItem(myMetaItem); + scene->enqueueTransaction(transaction); }); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 057ca36e13..c770e85089 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -40,8 +40,8 @@ public: void doInitialModelSimulation(); - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; void updateModelBounds(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 86c3f5ff35..fdf9ba888f 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -162,7 +162,7 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::ScenePointer scene, - render::PendingChanges& pendingChanges) { + render::Transaction& transaction) { _scene = scene; _renderItemId = _scene->allocateID(); auto particlePayloadData = std::make_shared(); @@ -171,14 +171,14 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); - pendingChanges.resetItem(_renderItemId, renderPayload); + transaction.resetItem(_renderItemId, renderPayload); return true; } void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self, render::ScenePointer scene, - render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_renderItemId); + render::Transaction& transaction) { + transaction.removeItem(_renderItemId); _scene = nullptr; render::Item::clearID(_renderItemId); }; @@ -206,12 +206,12 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { return; } if (!getVisible()) { - render::PendingChanges pendingChanges; - pendingChanges.updateItem(_renderItemId, [](ParticlePayloadData& payload) { + render::Transaction transaction; + transaction.updateItem(_renderItemId, [](ParticlePayloadData& payload) { payload.setVisibleFlag(false); }); - _scene->enqueuePendingChanges(pendingChanges); + _scene->enqueueTransaction(transaction); return; } @@ -253,8 +253,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { } - render::PendingChanges pendingChanges; - pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { + render::Transaction transaction; + transaction.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { payload.setVisibleFlag(true); // Update particle uniforms @@ -282,7 +282,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { } }); - _scene->enqueuePendingChanges(pendingChanges); + _scene->enqueueTransaction(transaction); } void RenderableParticleEffectEntityItem::createPipelines() { @@ -318,9 +318,9 @@ void RenderableParticleEffectEntityItem::notifyBoundChanged() { if (!render::Item::isValidID(_renderItemId)) { return; } - render::PendingChanges pendingChanges; - pendingChanges.updateItem(_renderItemId, [](ParticlePayloadData& payload) { + render::Transaction transaction; + transaction.updateItem(_renderItemId, [](ParticlePayloadData& payload) { }); - _scene->enqueuePendingChanges(pendingChanges); + _scene->enqueueTransaction(transaction); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index a36c3640d6..9b31c92b07 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -25,8 +25,8 @@ public: void updateRenderItem(); - virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; - virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; + virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::Transaction& transaction) override; + virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::Transaction& transaction) override; protected: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 419f32f897..b8093d85d0 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -817,7 +817,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { + render::Transaction& transaction) { _myItem = scene->allocateID(); auto renderItem = std::make_shared(getThisPointer()); @@ -828,15 +828,15 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); - pendingChanges.resetItem(_myItem, renderPayload); + transaction.resetItem(_myItem, renderPayload); return true; } void RenderablePolyVoxEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_myItem); + render::Transaction& transaction) { + transaction.removeItem(_myItem); render::Item::clearID(_myItem); } @@ -1615,10 +1615,10 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { return; } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - render::PendingChanges pendingChanges; - pendingChanges.updateItem(_myItem, [](PolyVoxPayload& payload) {}); + render::Transaction transaction; + transaction.updateItem(_myItem, [](PolyVoxPayload& payload) {}); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index cdfe2e38fe..ecb1817e94 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -107,10 +107,10 @@ public: virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) override; + render::Transaction& transaction) override; virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) override; + render::Transaction& transaction) override; virtual void setXNNeighborID(const EntityItemID& xNNeighborID) override; virtual void setYNNeighborID(const EntityItemID& yNNeighborID) override; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c4ae0db1aa..109c4cbfe9 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -266,7 +266,7 @@ void RenderableWebEntityItem::loadSourceURL() { _webSurface->setMaxFps(DEFAULT_MAX_FPS); } - _webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) { + _webSurface->load("WebEntityView.qml", [&](QQmlContext* context, QObject* obj) { context->setContextProperty("eventBridgeJavaScriptToInject", QVariant(_javaScriptToInject)); }); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 0215ce4d07..c9a45465c2 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -118,13 +118,13 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - render::PendingChanges pendingChanges; - _model->removeFromScene(scene, pendingChanges); + render::Transaction transaction; + _model->removeFromScene(scene, transaction); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges); + _model->addToScene(scene, transaction); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); _model->setVisibleInScene(getVisible(), scene); } @@ -164,9 +164,9 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { _model && !_model->needsFixupInScene()) { // If the model is in the scene but doesn't need to be, remove it. render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - render::PendingChanges pendingChanges; - _model->removeFromScene(scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + _model->removeFromScene(scene, transaction); + scene->enqueueTransaction(transaction); } } @@ -218,7 +218,7 @@ namespace render { } bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { + render::Transaction& transaction) { _myMetaItem = scene->allocateID(); auto renderData = std::make_shared(self); @@ -228,16 +228,16 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); - pendingChanges.resetItem(_myMetaItem, renderPayload); + transaction.resetItem(_myMetaItem, renderPayload); return true; } void RenderableZoneEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { - pendingChanges.removeItem(_myMetaItem); + render::Transaction& transaction) { + transaction.removeItem(_myMetaItem); render::Item::clearID(_myMetaItem); if (_model) { - _model->removeFromScene(scene, pendingChanges); + _model->removeFromScene(scene, transaction); } } @@ -246,13 +246,13 @@ void RenderableZoneEntityItem::notifyBoundChanged() { if (!render::Item::isValidID(_myMetaItem)) { return; } - render::PendingChanges pendingChanges; + render::Transaction transaction; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { - pendingChanges.updateItem(_myMetaItem, [](RenderableZoneEntityItemMeta& data) { + transaction.updateItem(_myMetaItem, [](RenderableZoneEntityItemMeta& data) { }); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } else { qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown"; } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 58aa951e64..bbb7ed0c01 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -38,8 +38,8 @@ public: virtual void render(RenderArgs* args) override; virtual bool contains(const glm::vec3& point) const override; - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; private: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b973d916e6..74d2daccbf 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -53,7 +53,7 @@ using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr scene, - render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene + render::Transaction& transaction) { return false; } // by default entity items don't add to scene virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, - render::PendingChanges& pendingChanges) { } // by default entity items don't add to scene + render::Transaction& transaction) { } // by default entity items don't add to scene virtual void render(RenderArgs* args) { } // by default entity items don't know how to render static int expectedBytes(); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 64ee0bc869..bcd2be3384 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -376,10 +376,10 @@ public: }; bool checkMaterialsHaveTextures(const QHash& materials, - const QHash& textureFilenames, const QMultiMap& _connectionChildMap) { + const QHash& textureFilepaths, const QMultiMap& _connectionChildMap) { foreach (const QString& materialID, materials.keys()) { foreach (const QString& childID, _connectionChildMap.values(materialID)) { - if (textureFilenames.contains(childID)) { + if (textureFilepaths.contains(childID)) { return true; } } @@ -443,21 +443,48 @@ FBXLight extractLight(const FBXNode& object) { return light; } -QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) { - QString path = QFileInfo(url).path(); - QByteArray filename = filepath; - QFileInfo checkFile(path + "/" + filepath); +QByteArray fixedTextureFilepath(QByteArray fbxRelativeFilepath, QUrl url) { + // first setup a QFileInfo for the passed relative filepath, with backslashes replaced by forward slashes + auto fileInfo = QFileInfo { fbxRelativeFilepath.replace("\\", "/") }; - // check if the file exists at the RelativeFilename - if (!(checkFile.exists() && checkFile.isFile())) { - // if not, assume it is in the fbx directory - filename = filename.mid(filename.lastIndexOf('/') + 1); +#ifndef Q_OS_WIN + // it turns out that absolute windows paths starting with drive letters look like relative paths to QFileInfo on UNIX + // so we add a check for that here to work around it + bool isRelative = fbxRelativeFilepath[1] != ':' && fileInfo.isRelative(); +#else + bool isRelative = fileInfo.isRelative(); +#endif + + if (isRelative) { + // the RelativeFilename pulled from the FBX is already correctly relative + // so simply return this as the filepath to use + return fbxRelativeFilepath; + } else { + // the RelativeFilename pulled from the FBX is an absolute path + + // use the URL to figure out where the FBX is being loaded from + auto filename = fileInfo.fileName(); + + if (url.isLocalFile()) { + // the FBX is being loaded from the local filesystem + + if (fileInfo.exists() && fileInfo.isFile()) { + // found a file at the absolute path in the FBX, return that path + return fbxRelativeFilepath; + } else { + // didn't find a file at the absolute path, assume it is right beside the FBX + // return just the filename as the relative path + return filename.toUtf8(); + } + } else { + // this is a remote file, meaning we can't really do anything with the absolute path to the texture + // so assume it will be right beside the fbx + return filename.toUtf8(); + } } - - return filename; } -FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) { +FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QUrl& url) { const FBXNode& node = _fbxNode; QMap meshes; QHash modelIDsToNames; @@ -833,11 +860,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS const int MODEL_UV_SCALING_MIN_SIZE = 2; const int CROPPING_MIN_SIZE = 4; if (subobject.name == "RelativeFilename" && subobject.properties.length() >= RELATIVE_FILENAME_MIN_SIZE) { - QByteArray filename = subobject.properties.at(0).toByteArray(); - QByteArray filepath = filename.replace('\\', '/'); - filename = fileOnUrl(filepath, url); + auto filepath = fixedTextureFilepath(subobject.properties.at(0).toByteArray(), url); + _textureFilepaths.insert(getID(object.properties), filepath); - _textureFilenames.insert(getID(object.properties), filename); } else if (subobject.name == "TextureName" && subobject.properties.length() >= TEXTURE_NAME_MIN_SIZE) { // trim the name from the timestamp QString name = QString(subobject.properties.at(0).toByteArray()); @@ -930,7 +955,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS QByteArray content; foreach (const FBXNode& subobject, object.children) { if (subobject.name == "RelativeFilename") { - filepath= subobject.properties.at(0).toByteArray(); + filepath = subobject.properties.at(0).toByteArray(); filepath = filepath.replace('\\', '/'); } else if (subobject.name == "Content" && !subobject.properties.isEmpty()) { @@ -1502,7 +1527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS geometry.materials = _fbxMaterials; // see if any materials have texture children - bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap); + bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilepaths, _connectionChildMap); for (QMap::iterator it = meshes.begin(); it != meshes.end(); it++) { ExtractedMesh& extracted = it.value(); @@ -1547,7 +1572,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS materialIndex++; - } else if (_textureFilenames.contains(childID)) { + } else if (_textureFilepaths.contains(childID)) { FBXTexture texture = getTexture(childID); for (int j = 0; j < extracted.partMaterialTextures.size(); j++) { int partTexture = extracted.partMaterialTextures.at(j).second; @@ -1818,13 +1843,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS return geometryPtr; } -FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel); } -FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) { +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { FBXReader reader; reader._fbxNode = FBXReader::parseFBX(device); reader._loadLightmaps = loadLightmaps; diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index f73088e7a1..dd746322e9 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -268,7 +268,7 @@ class FBXGeometry { public: using Pointer = std::shared_ptr; - QString originalURL; + QUrl originalURL; QString author; QString applicationName; ///< the name of the application that generated the model @@ -330,11 +330,11 @@ Q_DECLARE_METATYPE(FBXGeometry::Pointer) /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f); /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); +FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QUrl& url = QUrl(), bool loadLightmaps = true, float lightmapLevel = 1.0f); class TextureParam { public: @@ -402,19 +402,17 @@ public: FBXNode _fbxNode; static FBXNode parseFBX(QIODevice* device); - FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QString& url); + FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QUrl& url); ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex); QHash meshes; - static void buildModelMesh(FBXMesh& extractedMesh, const QString& url); + static void buildModelMesh(FBXMesh& extractedMesh, const QUrl& url); FBXTexture getTexture(const QString& textureID); QHash _textureNames; // Hashes the original RelativeFilename of textures QHash _textureFilepaths; - // Hashes the place to look for textures, in case they are not inlined - QHash _textureFilenames; // Hashes texture content by filepath, in case they are inlined QHash _textureContent; QHash _textureParams; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index ca2ec557b4..2f63d894fd 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -85,12 +85,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { FBXTexture texture; const QByteArray& filepath = _textureFilepaths.value(textureID); texture.content = _textureContent.value(filepath); - - if (texture.content.isEmpty()) { // the content is not inlined - texture.filename = _textureFilenames.value(textureID); - } else { // use supplied filepath for inlined content - texture.filename = filepath; - } + texture.filename = filepath; texture.name = _textureNames.value(textureID); texture.transform.setIdentity(); @@ -155,7 +150,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { // FBX files generated by 3DSMax have an intermediate texture parent, apparently foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) { - if (_textureFilenames.contains(childTextureID)) { + if (_textureFilepaths.contains(childTextureID)) { diffuseTexture = getTexture(diffuseTextureID); } } diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 4e153dfe3a..a6d70408ae 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -388,7 +388,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn return data.extracted; } -void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { +void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QUrl& url) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("buildModelMesh failed -- .*"); unsigned int totalSourceIndices = 0; diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 8befdf3e16..28de0c70eb 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -72,6 +72,15 @@ Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const { } void Texture::setKtxBacking(const std::string& filename) { + // Check the KTX file for validity before using it as backing storage + { + ktx::StoragePointer storage { new storage::FileStorage(filename.c_str()) }; + auto ktxPointer = ktx::KTX::create(storage); + if (!ktxPointer) { + return; + } + } + auto newBacking = std::unique_ptr(new KtxStorage(filename)); setStorage(newBacking); } @@ -185,7 +194,12 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } Texture* Texture::unserialize(const std::string& ktxfile, TextureUsageType usageType, Usage usage, const Sampler::Desc& sampler) { - ktx::KTXDescriptor descriptor { ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) })->toDescriptor() }; + std::unique_ptr ktxPointer = ktx::KTX::create(ktx::StoragePointer { new storage::FileStorage(ktxfile.c_str()) }); + if (!ktxPointer) { + return nullptr; + } + + ktx::KTXDescriptor descriptor { ktxPointer->toDescriptor() }; const auto& header = descriptor.header; Format mipFormat = Format::COLOR_BGRA_32; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index dd3193073d..142ea74af4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -173,7 +173,7 @@ void GeometryReader::run() { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { - fbxGeometry.reset(readFBX(_data, _mapping, _url.path())); + fbxGeometry.reset(readFBX(_data, _mapping, _url)); if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported FBX version"); } diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 6066385847..162745e76f 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -114,9 +114,9 @@ AnimDebugDraw::AnimDebugDraw() : render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { _itemID = scene->allocateID(); - render::PendingChanges pendingChanges; - pendingChanges.resetItem(_itemID, _animDebugDrawPayload); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + transaction.resetItem(_itemID, _animDebugDrawPayload); + scene->enqueueTransaction(transaction); } // HACK: add red, green and blue axis at (1,1,1) @@ -142,9 +142,9 @@ void AnimDebugDraw::shutdown() { // remove renderItem from main 3d scene. render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene && _itemID) { - render::PendingChanges pendingChanges; - pendingChanges.removeItem(_itemID); - scene->enqueuePendingChanges(pendingChanges); + render::Transaction transaction; + transaction.removeItem(_itemID); + scene->enqueueTransaction(transaction); } } @@ -317,8 +317,8 @@ void AnimDebugDraw::update() { return; } - render::PendingChanges pendingChanges; - pendingChanges.updateItem(_itemID, [&](AnimDebugDrawData& data) { + render::Transaction transaction; + transaction.updateItem(_itemID, [&](AnimDebugDrawData& data) { const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3); const size_t VERTICES_PER_LINK = 8 * 2; @@ -422,5 +422,5 @@ void AnimDebugDraw::update() { data._indexBuffer->setSubData(i, (uint16_t)i);; } }); - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 9ffd94af38..e534628c83 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -88,8 +88,9 @@ static const std::string DEFAULT_NORMAL_SHADER { static const std::string DEFAULT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" - " return vec4(vec3(pow(frag.obscurance, 1.0 / 2.2)), 1.0);" + // " DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);" + // " return vec4(vec3(pow(frag.obscurance, 1.0 / 2.2)), 1.0);" + " return vec4(vec3(pow(texture(specularMap, uv).a, 1.0 / 2.2)), 1.0);" " }" }; @@ -194,6 +195,18 @@ static const std::string DEFAULT_DIFFUSED_NORMAL_CURVATURE_SHADER{ " }" }; +static const std::string DEFAULT_CURVATURE_OCCLUSION_SHADER{ + "vec4 getFragmentColor() {" + " vec4 midNormalCurvature;" + " vec4 lowNormalCurvature;" + " unpackMidLowNormalCurvature(uv, midNormalCurvature, lowNormalCurvature);" + " float ambientOcclusion = curvatureAO(lowNormalCurvature.a * 20.0f) * 0.5f;" + " float ambientOcclusionHF = curvatureAO(midNormalCurvature.a * 8.0f) * 0.5f;" + " ambientOcclusion = min(ambientOcclusion, ambientOcclusionHF);" + " return vec4(vec3(ambientOcclusion), 1.0);" + " }" +}; + static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{ "vec4 getFragmentColor() {" " return vec4(pow(vec3(texture(scatteringMap, uv).xyz), vec3(1.0 / 2.2)), 1.0);" @@ -203,7 +216,7 @@ static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{ static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{ "vec4 getFragmentColor() {" - " return vec4(vec3(texture(obscuranceMap, uv).xyz), 1.0);" + " return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);" // When drawing color " return vec4(vec3(texture(occlusionMap, uv).xyz), 1.0);" // when drawing normal" return vec4(normalize(texture(occlusionMap, uv).xyz * 2.0 - vec3(1.0)), 1.0);" " }" @@ -288,6 +301,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_DIFFUSED_CURVATURE_SHADER; case DiffusedNormalCurvatureMode: return DEFAULT_DIFFUSED_NORMAL_CURVATURE_SHADER; + case CurvatureOcclusionMode: + return DEFAULT_CURVATURE_OCCLUSION_SHADER; case ScatteringDebugMode: return DEFAULT_DEBUG_SCATTERING_SHADER; case AmbientOcclusionMode: diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index eb1a541d2e..be775e052f 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -72,6 +72,7 @@ protected: NormalCurvatureMode, DiffusedCurvatureMode, DiffusedNormalCurvatureMode, + CurvatureOcclusionMode, ScatteringDebugMode, AmbientOcclusionMode, AmbientOcclusionBlurredMode, diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 7c81b2c142..315de30fea 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -67,10 +67,8 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) { frag.scattering = 0.0; unpackModeMetallic(diffuseVal.w, frag.mode, frag.metallic); - //frag.emissive = specularVal.xyz; frag.obscurance = min(specularVal.w, frag.obscurance); - if (frag.mode == FRAG_MODE_SCATTERING) { frag.scattering = specularVal.x; } diff --git a/libraries/render-utils/src/DeferredFramebuffer.cpp b/libraries/render-utils/src/DeferredFramebuffer.cpp index 52329931d0..5d345f0851 100644 --- a/libraries/render-utils/src/DeferredFramebuffer.cpp +++ b/libraries/render-utils/src/DeferredFramebuffer.cpp @@ -55,7 +55,7 @@ void DeferredFramebuffer::allocate() { _deferredColorTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler)); _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler)); - _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(colorFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler)); + _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(linearFormat, width, height, gpu::Texture::SINGLE_MIP, defaultSampler)); _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture); _deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture); diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index b919108115..5f74b46d3e 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -62,7 +62,7 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, vec3 fragEyeDir, vec3 f <@if supportScattering@> float curvatureAO(in float k) { - return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369; + return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369f; } <@endif@> @@ -83,13 +83,12 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie specular = evalAmbientSpecularIrradiance(ambient, eyeDir, normal, roughness) * ambientFresnel; <@if supportScattering@> - float ambientOcclusion = curvatureAO(lowNormalCurvature.w * 20.0f) * 0.5f; - float ambientOcclusionHF = curvatureAO(midNormalCurvature.w * 8.0f) * 0.5f; - ambientOcclusion = min(ambientOcclusion, ambientOcclusionHF); - - obscurance = min(obscurance, ambientOcclusion); - if (scattering * isScatteringEnabled() > 0.0) { + float ambientOcclusion = curvatureAO(lowNormalCurvature.w * 20.0f) * 0.5f; + float ambientOcclusionHF = curvatureAO(midNormalCurvature.w * 8.0f) * 0.5f; + ambientOcclusion = min(ambientOcclusion, ambientOcclusionHF); + + obscurance = min(obscurance, ambientOcclusion); // Diffuse from ambient diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3448c9e8da..c274d69af6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -235,9 +235,9 @@ void Model::updateRenderItems() { uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; - render::PendingChanges pendingChanges; + render::Transaction transaction; foreach (auto itemID, self->_modelMeshRenderItemsMap.keys()) { - pendingChanges.updateItem(itemID, [deleteGeometryCounter](ModelMeshPartPayload& data) { + transaction.updateItem(itemID, [deleteGeometryCounter](ModelMeshPartPayload& data) { if (data._model && data._model->isLoaded()) { // Ensure the model geometry was not reset between frames if (deleteGeometryCounter == data._model->_deleteGeometryCounter) { @@ -259,14 +259,14 @@ void Model::updateRenderItems() { Transform collisionMeshOffset; collisionMeshOffset.setIdentity(); Transform modelTransform = self->getTransform(); - foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { - pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { + foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { + transaction.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. data.updateTransform(modelTransform, collisionMeshOffset); }); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); }); } @@ -538,14 +538,14 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen if (_isVisible != newValue) { _isVisible = newValue; - render::PendingChanges pendingChanges; + render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { - pendingChanges.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.resetItem(item, _modelMeshRenderItemsMap[item]); } - foreach(auto item, _collisionRenderItemsMap.keys()) { - pendingChanges.resetItem(item, _collisionRenderItemsMap[item]); + foreach(auto item, _collisionRenderItemsMap.keys()) { + transaction.resetItem(item, _collisionRenderItemsMap[item]); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } } @@ -554,19 +554,19 @@ void Model::setLayeredInFront(bool layered, std::shared_ptr scene if (_isLayeredInFront != layered) { _isLayeredInFront = layered; - render::PendingChanges pendingChanges; + render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { - pendingChanges.resetItem(item, _modelMeshRenderItemsMap[item]); + transaction.resetItem(item, _modelMeshRenderItemsMap[item]); } - foreach(auto item, _collisionRenderItemsMap.keys()) { - pendingChanges.resetItem(item, _collisionRenderItemsMap[item]); + foreach(auto item, _collisionRenderItemsMap.keys()) { + transaction.resetItem(item, _collisionRenderItemsMap[item]); } - scene->enqueuePendingChanges(pendingChanges); + scene->enqueueTransaction(transaction); } } bool Model::addToScene(std::shared_ptr scene, - render::PendingChanges& pendingChanges, + render::Transaction& transaction, render::Item::Status::Getters& statusGetters) { bool readyToRender = _collisionGeometry || isLoaded(); if (!_addedToScene && readyToRender) { @@ -579,11 +579,11 @@ bool Model::addToScene(std::shared_ptr scene, foreach (auto renderItem, _collisionRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - if (_collisionRenderItems.empty() && statusGetters.size()) { + if (_collisionRenderItems.empty() && statusGetters.size()) { renderPayload->addStatusGetters(statusGetters); } - pendingChanges.resetItem(item, renderPayload); - _collisionRenderItemsMap.insert(item, renderPayload); + transaction.resetItem(item, renderPayload); + _collisionRenderItemsMap.insert(item, renderPayload); } somethingAdded = !_collisionRenderItems.empty(); } @@ -595,10 +595,10 @@ bool Model::addToScene(std::shared_ptr scene, foreach(auto renderItem, _modelMeshRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) { + if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) { renderPayload->addStatusGetters(statusGetters); } - pendingChanges.resetItem(item, renderPayload); + transaction.resetItem(item, renderPayload); hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); @@ -622,16 +622,16 @@ bool Model::addToScene(std::shared_ptr scene, return somethingAdded; } -void Model::removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges) { +void Model::removeFromScene(std::shared_ptr scene, render::Transaction& transaction) { foreach (auto item, _modelMeshRenderItemsMap.keys()) { - pendingChanges.removeItem(item); + transaction.removeItem(item); } _modelMeshRenderItemIDs.clear(); _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); - foreach(auto item, _collisionRenderItemsMap.keys()) { - pendingChanges.removeItem(item); + foreach(auto item, _collisionRenderItemsMap.keys()) { + transaction.removeItem(item); } _collisionRenderItems.clear(); _collisionRenderItems.clear(); @@ -794,11 +794,11 @@ void Model::setURL(const QUrl& url) { _url = url; { - render::PendingChanges pendingChanges; + render::Transaction transaction; render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); if (scene) { - removeFromScene(scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); + removeFromScene(scene, transaction); + scene->enqueueTransaction(transaction); } else { qCWarning(renderutils) << "Model::setURL(), Unexpected null scene, possibly during application shutdown"; } @@ -1279,17 +1279,17 @@ bool Model::initWhenReady(render::ScenePointer scene) { createRenderItemSet(); - render::PendingChanges pendingChanges; + render::Transaction transaction; - bool addedPendingChanges = false; + bool addedTransaction = false; if (_collisionGeometry) { foreach (auto renderItem, _collisionRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); _collisionRenderItemsMap.insert(item, renderPayload); - pendingChanges.resetItem(item, renderPayload); + transaction.resetItem(item, renderPayload); } - addedPendingChanges = !_collisionRenderItems.empty(); + addedTransaction = !_collisionRenderItems.empty(); } else { bool hasTransparent = false; size_t verticesCount = 0; @@ -1300,17 +1300,17 @@ bool Model::initWhenReady(render::ScenePointer scene) { hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); _modelMeshRenderItemsMap.insert(item, renderPayload); - pendingChanges.resetItem(item, renderPayload); + transaction.resetItem(item, renderPayload); } - addedPendingChanges = !_modelMeshRenderItemsMap.empty(); + addedTransaction = !_modelMeshRenderItemsMap.empty(); _renderInfoVertexCount = verticesCount; _renderInfoDrawCalls = _modelMeshRenderItemsMap.count(); _renderInfoHasTransparent = hasTransparent; } - _addedToScene = addedPendingChanges; - if (addedPendingChanges) { - scene->enqueuePendingChanges(pendingChanges); - // NOTE: updateRender items enqueues identical pendingChanges (using a lambda) + _addedToScene = addedTransaction; + if (addedTransaction) { + scene->enqueueTransaction(transaction); + // NOTE: updateRender items enqueues identical transaction (using a lambda) // so it looks like we're doing double work here, but I don't want to remove the call // for fear there is some side effect we'll miss. -- Andrew 2016.07.21 // TODO: figure out if we really need this call to updateRenderItems() or not. diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index bb283cce1f..e852358bc4 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -42,7 +42,7 @@ class ViewFrustum; namespace render { class Scene; - class PendingChanges; + class Transaction; typedef unsigned int ItemID; } class MeshPartPayload; @@ -88,14 +88,14 @@ public: bool needsReload() const { return _needsReload; } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, - render::PendingChanges& pendingChanges) { + render::Transaction& transaction) { auto getters = render::Item::Status::Getters(0); - return addToScene(scene, pendingChanges, getters); + return addToScene(scene, transaction, getters); } bool addToScene(std::shared_ptr scene, - render::PendingChanges& pendingChanges, + render::Transaction& transaction, render::Item::Status::Getters& statusGetters); - void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); + void removeFromScene(std::shared_ptr scene, render::Transaction& transaction); bool isRenderable() const; bool isVisible() const { return _isVisible; } diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index c018e5e526..e9750f0054 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -16,15 +16,20 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> + uniform sampler2D linearDepthMap; uniform sampler2D halfLinearDepthMap; uniform sampler2D halfNormalMap; uniform sampler2D occlusionMap; uniform sampler2D occlusionBlurredMap; -uniform sampler2D curvatureMap; -uniform sampler2D diffusedCurvatureMap; uniform sampler2D scatteringMap; +<$declareDeferredCurvature()$> + +float curvatureAO(float k) { + return 1.0f - (0.0022f * k * k) + (0.0776f * k) + 0.7369f; +} + in vec2 uv; out vec4 outFragColor; diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 076879ae25..537d8c1337 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -16,31 +16,31 @@ using namespace render; -void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) { +void Transaction::resetItem(ItemID id, const PayloadPointer& payload) { if (payload) { _resetItems.push_back(id); _resetPayloads.push_back(payload); } else { - qCDebug(renderlogging) << "WARNING: PendingChanges::resetItem with a null payload!"; + qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!"; removeItem(id); } } -void PendingChanges::removeItem(ItemID id) { +void Transaction::removeItem(ItemID id) { _removedItems.push_back(id); } -void PendingChanges::updateItem(ItemID id, const UpdateFunctorPointer& functor) { +void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) { _updatedItems.push_back(id); _updateFunctors.push_back(functor); } -void PendingChanges::merge(const PendingChanges& changes) { - _resetItems.insert(_resetItems.end(), changes._resetItems.begin(), changes._resetItems.end()); - _resetPayloads.insert(_resetPayloads.end(), changes._resetPayloads.begin(), changes._resetPayloads.end()); - _removedItems.insert(_removedItems.end(), changes._removedItems.begin(), changes._removedItems.end()); - _updatedItems.insert(_updatedItems.end(), changes._updatedItems.begin(), changes._updatedItems.end()); - _updateFunctors.insert(_updateFunctors.end(), changes._updateFunctors.begin(), changes._updateFunctors.end()); +void Transaction::merge(const Transaction& transaction) { + _resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end()); + _resetPayloads.insert(_resetPayloads.end(), transaction._resetPayloads.begin(), transaction._resetPayloads.end()); + _removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end()); + _updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end()); + _updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end()); } Scene::Scene(glm::vec3 origin, float size) : @@ -63,27 +63,27 @@ bool Scene::isAllocatedID(const ItemID& id) const { } /// Enqueue change batch to the scene -void Scene::enqueuePendingChanges(const PendingChanges& pendingChanges) { - _changeQueueMutex.lock(); - _changeQueue.push(pendingChanges); - _changeQueueMutex.unlock(); +void Scene::enqueueTransaction(const Transaction& transaction) { + _transactionQueueMutex.lock(); + _transactionQueue.push(transaction); + _transactionQueueMutex.unlock(); } -void consolidateChangeQueue(PendingChangesQueue& queue, PendingChanges& singleBatch) { +void consolidateTransaction(TransactionQueue& queue, Transaction& singleBatch) { while (!queue.empty()) { - const auto& pendingChanges = queue.front(); - singleBatch.merge(pendingChanges); + const auto& transaction = queue.front(); + singleBatch.merge(transaction); queue.pop(); }; } -void Scene::processPendingChangesQueue() { +void Scene::processTransactionQueue() { PROFILE_RANGE(render, __FUNCTION__); - PendingChanges consolidatedPendingChanges; + Transaction consolidatedTransaction; { - std::unique_lock lock(_changeQueueMutex); - consolidateChangeQueue(_changeQueue, consolidatedPendingChanges); + std::unique_lock lock(_transactionQueueMutex); + consolidateTransaction(_transactionQueue, consolidatedTransaction); } { @@ -95,19 +95,19 @@ void Scene::processPendingChangesQueue() { _items.resize(maxID + 100); // allocate the maxId and more } // Now we know for sure that we have enough items in the array to - // capture anything coming from the pendingChanges + // capture anything coming from the transaction // resets and potential NEW items - resetItems(consolidatedPendingChanges._resetItems, consolidatedPendingChanges._resetPayloads); + resetItems(consolidatedTransaction._resetItems, consolidatedTransaction._resetPayloads); // Update the numItemsAtomic counter AFTER the reset changes went through _numAllocatedItems.exchange(maxID); // updates - updateItems(consolidatedPendingChanges._updatedItems, consolidatedPendingChanges._updateFunctors); + updateItems(consolidatedTransaction._updatedItems, consolidatedTransaction._updateFunctors); // removes - removeItems(consolidatedPendingChanges._removedItems); + removeItems(consolidatedTransaction._removedItems); // Update the numItemsAtomic counter AFTER the pending changes went through _numAllocatedItems.exchange(maxID); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index f2f8403dc9..09a725205d 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -19,10 +19,19 @@ namespace render { class Engine; -class PendingChanges { +// Transaction is the mechanism to make any change to the scene. +// Whenever a new item need to be reset, +// or when an item changes its position or its size +// or when an item's payload has to be be updated with new states (coming from outside the scene knowledge) +// or when an item is destroyed +// These changes must be expressed through the corresponding command from the Transaction +// THe Transaction is then queued on the Scene so all the pending transactions can be consolidated and processed at the time +// of updating the scene before it s rendered. +// +class Transaction { public: - PendingChanges() {} - ~PendingChanges() {} + Transaction() {} + ~Transaction() {} void resetItem(ItemID id, const PayloadPointer& payload); void removeItem(ItemID id); @@ -34,7 +43,7 @@ public: void updateItem(ItemID id, const UpdateFunctorPointer& functor); void updateItem(ItemID id) { updateItem(id, nullptr); } - void merge(const PendingChanges& changes); + void merge(const Transaction& transaction); ItemIDs _resetItems; Payloads _resetPayloads; @@ -44,12 +53,12 @@ public: protected: }; -typedef std::queue PendingChangesQueue; +typedef std::queue TransactionQueue; // Scene is a container for Items -// Items are introduced, modified or erased in the scene through PendingChanges -// Once per Frame, the PendingChanges are all flushed +// Items are introduced, modified or erased in the scene through Transaction +// Once per Frame, the Transaction are all flushed // During the flush the standard buckets are updated // Items are notified accordingly on any update message happening class Scene { @@ -66,11 +75,11 @@ public: // THis is the total number of allocated items, this a threadsafe call size_t getNumItems() const { return _numAllocatedItems.load(); } - // Enqueue change batch to the scene - void enqueuePendingChanges(const PendingChanges& pendingChanges); + // Enqueue transaction to the scene + void enqueueTransaction(const Transaction& transaction); - // Process the penging changes equeued - void processPendingChangesQueue(); + // Process the pending transactions queued + void processTransactionQueue(); // This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues @@ -91,8 +100,8 @@ protected: // Thread safe elements that can be accessed from anywhere std::atomic _IDAllocator{ 1 }; // first valid itemID will be One std::atomic _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size() - std::mutex _changeQueueMutex; - PendingChangesQueue _changeQueue; + std::mutex _transactionQueueMutex; + TransactionQueue _transactionQueue; // The actual database // database of items is protected for editing by a mutex diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index e8ea2e0217..7bc22eb3e6 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -133,7 +133,8 @@ namespace SceneScripting { class SceneScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY - + + public: Q_PROPERTY(bool shouldRenderAvatars READ shouldRenderAvatars WRITE setShouldRenderAvatars) Q_PROPERTY(bool shouldRenderEntities READ shouldRenderEntities WRITE setShouldRenderEntities) diff --git a/libraries/shared/src/Trace.cpp b/libraries/shared/src/Trace.cpp index 1e3d490a9c..d7feb65ff3 100644 --- a/libraries/shared/src/Trace.cpp +++ b/libraries/shared/src/Trace.cpp @@ -179,7 +179,7 @@ void Tracer::serialize(const QString& originalPath) { { // "traceEvents":[ - // {"args":{"nv_payload":0},"cat":"hifi.render","name":"render::Scene::processPendingChangesQueue","ph":"B","pid":14796,"tid":21636,"ts":68795933487} + // {"args":{"nv_payload":0},"cat":"hifi.render","name":"render::Scene::processTransactionQueue","ph":"B","pid":14796,"tid":21636,"ts":68795933487} QJsonArray traceEvents; diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index c7ec8e1153..778e0e1905 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -63,7 +63,8 @@ Column { "Directional:LightingModel:enableDirectionalLight", "Point:LightingModel:enablePointLight", "Spot:LightingModel:enableSpotLight", - "Light Contour:LightingModel:showLightContour" + "Light Contour:LightingModel:showLightContour", + "Shadow:RenderShadowTask:enabled" ] CheckBox { text: modelData.split(":")[0] @@ -150,6 +151,7 @@ Column { ListElement { text: "Mid Normal"; color: "White" } ListElement { text: "Low Curvature"; color: "White" } ListElement { text: "Low Normal"; color: "White" } + ListElement { text: "Curvature Occlusion"; color: "White" } ListElement { text: "Debug Scattering"; color: "White" } ListElement { text: "Ambient Occlusion"; color: "White" } ListElement { text: "Ambient Occlusion Blurred"; color: "White" } diff --git a/scripts/system/makeUserConnection.js b/scripts/system/makeUserConnection.js index 0a781a5bb8..674da2d677 100644 --- a/scripts/system/makeUserConnection.js +++ b/scripts/system/makeUserConnection.js @@ -131,7 +131,6 @@ function request(options, callback) { // cb(error, responseOfCorrectContentType) var error = (httpRequest.status !== HTTP_OK) && httpRequest.status.toString() + ':' + httpRequest.statusText, response = !error && httpRequest.responseText, contentType = !error && httpRequest.getResponseHeader('content-type'); - debug('FIXME REMOVE: server response', options, error, response, contentType); if (!error && contentType.indexOf('application/json') === 0) { // ignoring charset, etc. try { response = JSON.parse(response); @@ -139,6 +138,9 @@ function request(options, callback) { // cb(error, responseOfCorrectContentType) error = e; } } + if (error) { + response = {statusCode: httpRequest.status}; + } callback(error, response); } }; @@ -164,7 +166,6 @@ function request(options, callback) { // cb(error, responseOfCorrectContentType) options.headers["Content-type"] = "application/json"; options.body = JSON.stringify(options.body); } - debug("FIXME REMOVE: final options to send", options); for (key in options.headers || {}) { httpRequest.setRequestHeader(key, options.headers[key]); } @@ -574,6 +575,9 @@ function handleConnectionResponseAndMaybeRepeat(error, response) { } } else if (error || (response.status !== 'success')) { debug('server fail', error, response.status); + if (response && (response.statusCode === 401)) { + error = "All participants must be logged in to connect."; + } result = error ? {status: 'error', connection: error} : response; UserActivityLogger.makeUserConnection(connectingId, false, error || response); connectionRequestCompleted(); @@ -603,6 +607,15 @@ function makeConnection(id) { // probably, in which we do this. Controller.triggerHapticPulse(HAPTIC_DATA.background.strength, MAKING_CONNECTION_TIMEOUT, handToHaptic(currentHand)); requestBody = {node_id: cleanId(MyAvatar.sessionUUID), proposed_node_id: cleanId(id)}; // for use when repeating + + // It would be "simpler" to skip this and just look at the response, but: + // 1. We don't want to bother the metaverse with request that we know will fail. + // 2. We don't want our code here to be dependent on precisely how the metaverse responds (400, 401, etc.) + if (!Account.isLoggedIn()) { + handleConnectionResponseAndMaybeRepeat("401:Unauthorized", {statusCode: 401}); + return; + } + // This will immediately set response if successfull (e.g., the other guy got his request in first), or immediate failure, // and will otherwise poll (using the requestBody we just set). request({ // diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 3989e8e372..25a5edf3a3 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -427,21 +427,24 @@ function deleteNotification(index) { arrays.splice(index, 1); } -// wraps whole word to newline -function stringDivider(str, slotWidth, spaceReplacer) { - var left, right; - if (str.length > slotWidth && slotWidth > 0) { - left = str.substring(0, slotWidth); - right = str.substring(slotWidth); - return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer); +// Trims extra whitespace and breaks into lines of length no more than MAX_LENGTH, breaking at spaces. Trims extra whitespace. +var MAX_LENGTH = 42; +function wordWrap(string) { + var finishedLines = [], currentLine = ''; + string.split(/\s/).forEach(function (word) { + var tail = currentLine ? ' ' + word : word; + if ((currentLine.length + tail.length) <= MAX_LENGTH) { + currentLine += tail; + } else { + finishedLines.push(currentLine); + currentLine = word; + } + }); + if (currentLine) { + finishedLines.push(currentLine); } - return str; -} - -// formats string to add newline every 43 chars -function wordWrap(str) { - return stringDivider(str, 43.0, "\n"); + return finishedLines.join('\n'); } function update() { diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 522fe79b10..b76776b1ab 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -880,7 +880,7 @@ private: getEntities()->update(); // The pending changes collecting the changes here - render::PendingChanges pendingChanges; + render::Transaction transaction; // FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities // Background rendering decision @@ -888,7 +888,7 @@ private: auto backgroundRenderData = std::make_shared(); auto backgroundRenderPayload = std::make_shared(backgroundRenderData); BackgroundRenderData::_item = _main3DScene->allocateID(); - pendingChanges.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); + transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); } // Setup the current Zone Entity lighting { @@ -897,10 +897,10 @@ private: } { - PerformanceTimer perfTimer("SceneProcessPendingChanges"); - _main3DScene->enqueuePendingChanges(pendingChanges); + PerformanceTimer perfTimer("SceneProcessTransaction"); + _main3DScene->enqueueTransaction(transaction); - _main3DScene->processPendingChangesQueue(); + _main3DScene->processTransactionQueue(); } } @@ -914,13 +914,13 @@ private: PROFILE_RANGE(render, __FUNCTION__); PerformanceTimer perfTimer("draw"); // The pending changes collecting the changes here - render::PendingChanges pendingChanges; + render::Transaction transaction; // Setup the current Zone Entity lighting DependencyManager::get()->setGlobalLight(_sunSkyStage.getSunLight()); { - PerformanceTimer perfTimer("SceneProcessPendingChanges"); - _main3DScene->enqueuePendingChanges(pendingChanges); - _main3DScene->processPendingChangesQueue(); + PerformanceTimer perfTimer("SceneProcessTransaction"); + _main3DScene->enqueueTransaction(transaction); + _main3DScene->processTransactionQueue(); } // For now every frame pass the renderContext