From c3c9c0cb10694b10e09ec80c4e0adf627f3dfa79 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 13 Jul 2016 14:37:41 -0700 Subject: [PATCH 01/39] update so HTML5 media apis work again --- interface/resources/qml/Browser.qml | 5 ++++- interface/resources/qml/controls-uit/WebView.qml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index e9b99331c7..e397242a0c 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,4 +1,4 @@ -import QtQuick 2.3 +import QtQuick 2.5 import QtQuick.Controls 1.2 import QtWebEngine 1.1 @@ -131,6 +131,9 @@ ScrollingWindow { anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } onLoadingChanged: { if (loadRequest.status === WebEngineView.LoadSucceededStatus) { addressBar.text = loadRequest.url diff --git a/interface/resources/qml/controls-uit/WebView.qml b/interface/resources/qml/controls-uit/WebView.qml index e6005d5dcf..acd0e1ae12 100644 --- a/interface/resources/qml/controls-uit/WebView.qml +++ b/interface/resources/qml/controls-uit/WebView.qml @@ -15,7 +15,7 @@ WebEngineView { id: root property var newUrl; - profile.httpUserAgent: "Mozilla/5.0 Chrome (HighFidelityInterface)" + profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)" Component.onCompleted: { console.log("Connecting JS messaging to Hifi Logging") From aacddcf66d360b8a143036e9bb63628d6a566d8c Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 13 Jul 2016 15:02:51 -0700 Subject: [PATCH 02/39] fix pop ups --- interface/resources/qml/Browser.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index e397242a0c..3057cd3330 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -142,7 +142,11 @@ ScrollingWindow { onIconChanged: { console.log("New icon: " + icon) } - + onNewViewRequested:{ + var component = Qt.createComponent("Browser.qml"); + var newWindow = component.createObject(desktop); + request.openIn(newWindow.webView) + } //profile: desktop.browserProfile } From 2cd97bfe78d1254f0521963d8b7bf58a9eeff354 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Fri, 22 Jul 2016 15:55:42 -0700 Subject: [PATCH 03/39] Fix squeezeHands.js error on script end --- scripts/system/controllers/squeezeHands.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/squeezeHands.js b/scripts/system/controllers/squeezeHands.js index 9fdb359b25..f549f911c9 100644 --- a/scripts/system/controllers/squeezeHands.js +++ b/scripts/system/controllers/squeezeHands.js @@ -19,6 +19,8 @@ var CONTROLLER_DEAD_SPOT = 0.25; var TRIGGER_SMOOTH_TIMESCALE = 0.1; var OVERLAY_RAMP_RATE = 8.0; +var animStateHandlerID; + function clamp(val, min, max) { return Math.min(Math.max(val, min), max); } @@ -33,8 +35,10 @@ function lerp(a, b, alpha) { function init() { Script.update.connect(update); - MyAvatar.addAnimationStateHandler(animStateHandler, ["leftHandOverlayAlpha", "rightHandOverlayAlpha", - "leftHandGraspAlpha", "rightHandGraspAlpha"]); + animStateHandlerID = MyAvatar.addAnimationStateHandler( + animStateHandler, + ["leftHandOverlayAlpha", "rightHandOverlayAlpha", "leftHandGraspAlpha", "rightHandGraspAlpha"] + ); } function animStateHandler(props) { @@ -72,7 +76,7 @@ function update(dt) { function shutdown() { Script.update.disconnect(update); - MyAvatar.removeAnimationStateHandler(animStateHandler); + MyAvatar.removeAnimationStateHandler(animStateHandlerID); } Script.scriptEnding.connect(shutdown); From 530e17a7e571adee8db6d9ec17cb12dda175efb1 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Fri, 22 Jul 2016 15:08:09 -0700 Subject: [PATCH 04/39] Move JSON parsing for custom dialog to be sooner --- libraries/ui/src/OffscreenUi.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 9e5f6c4e62..06ef456006 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -349,12 +349,8 @@ QVariant OffscreenUi::getCustomInfo(const Icon icon, const QString& title, const } QVariant result = DependencyManager::get()->customInputDialog(icon, title, config); - if (result.isValid()) { - // We get a JSON encoded result, so we unpack it into a QVariant wrapping a QVariantMap - result = QVariant(QJsonDocument::fromJson(result.toString().toUtf8()).object().toVariantMap()); - if (ok) { - *ok = true; - } + if (ok && result.isValid()) { + *ok = true; } return result; @@ -386,7 +382,13 @@ QVariant OffscreenUi::customInputDialog(const Icon icon, const QString& title, c return result; } - return waitForInputDialogResult(createCustomInputDialog(icon, title, config)); + QVariant result = waitForInputDialogResult(createCustomInputDialog(icon, title, config)); + if (result.isValid()) { + // We get a JSON encoded result, so we unpack it into a QVariant wrapping a QVariantMap + result = QVariant(QJsonDocument::fromJson(result.toString().toUtf8()).object().toVariantMap()); + } + + return result; } void OffscreenUi::togglePinned() { From c25b87c33ff213a915b73eceba30812ed4c6ea17 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Fri, 22 Jul 2016 15:15:11 -0700 Subject: [PATCH 05/39] Use custom dialog for asset server add to world --- interface/resources/qml/AssetServer.qml | 75 +++++++++++++++++-- .../entities/src/EntityScriptingInterface.cpp | 6 +- .../entities/src/EntityScriptingInterface.h | 3 +- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index c9b6305258..02c72f5b2d 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -141,18 +141,81 @@ ScrollingWindow { } function addToWorld() { - var url = assetProxyModel.data(treeView.selection.currentIndex, 0x103); + var defaultURL = assetProxyModel.data(treeView.selection.currentIndex, 0x103); - if (!url || !canAddToWorld(url)) { + if (!defaultURL || !canAddToWorld(defaultURL)) { return; } - var name = assetProxyModel.data(treeView.selection.currentIndex); + var SHAPE_TYPE_NONE = 0; + var SHAPE_TYPE_SIMPLE_HULL = 1; + var SHAPE_TYPE_SIMPLE_COMPOUND = 2; + var SHAPE_TYPE_STATIC_MESH = 3; - console.log("Asset browser - adding asset " + url + " (" + name + ") to world."); + var SHAPE_TYPES = []; + SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision"; + SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model"; + SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes"; + SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons"; - var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); - Entities.addModelEntity(name, url, addPosition); + var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; + var DYNAMIC_DEFAULT = false; + var prompt = desktop.customInputDialog({ + textInput: { + label: "Model URL", + text: defaultURL + }, + comboBox: { + label: "Automatic Collisions", + index: SHAPE_TYPE_DEFAULT, + items: SHAPE_TYPES + }, + checkBox: { + label: "Dynamic", + checked: DYNAMIC_DEFAULT, + disableForItems: [ + SHAPE_TYPE_STATIC_MESH + ], + checkStateOnDisable: false, + warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic" + } + }); + + prompt.selected.connect(function (jsonResult) { + if (jsonResult) { + var result = JSON.parse(jsonResult); + var url = result.textInput; + var shapeType; + switch (result.comboBox) { + case SHAPE_TYPE_SIMPLE_HULL: + shapeType = "simple-hull"; + break; + case SHAPE_TYPE_SIMPLE_COMPOUND: + shapeType = "simple-compound"; + break; + case SHAPE_TYPE_STATIC_MESH: + shapeType = "static-mesh"; + break; + default: + shapeType = "none"; + } + + var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; + if (shapeType === "static-mesh" && dynamic) { + // The prompt should prevent this case + print("Error: model cannot be both static mesh and dynamic. This should never happen."); + } else if (url) { + var name = assetProxyModel.data(treeView.selection.currentIndex); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); + var gravity = dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }; + + print("Asset browser - adding asset " + url + " (" + name + ") to world."); + + // Entities.addEntity doesn't work from QML, so we use this. + Entities.addModelEntity(name, url, shapeType, dynamic, addPosition, gravity); + } + } + }); } function copyURLToClipboard(index) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 856e526b4c..653b37c3bb 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -198,12 +198,16 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } } -QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position) { +QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType, + bool dynamic, const glm::vec3& position, const glm::vec3& gravity) { EntityItemProperties properties; properties.setType(EntityTypes::Model); properties.setName(name); properties.setModelURL(modelUrl); + properties.setShapeTypeFromString(shapeType); + properties.setDynamic(dynamic); properties.setPosition(position); + properties.setGravity(gravity); return addEntity(properties); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e9024eb721..5aa0f5907e 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -86,7 +86,8 @@ public slots: Q_INVOKABLE QUuid addEntity(const EntityItemProperties& properties, bool clientOnly = false); /// temporary method until addEntity can be used from QJSEngine - Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const glm::vec3& position); + Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType, bool dynamic, + const glm::vec3& position, const glm::vec3& gravity); /// gets the current model properties for a specific model /// this function will not find return results in script engine contexts which don't have access to models From 7280992806ea11ac6b176677c0d932647da956fa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sat, 23 Jul 2016 10:30:44 -0700 Subject: [PATCH 06/39] add mutex lock around AvatarData joint data --- libraries/avatars/src/AvatarData.cpp | 101 ++++++++++++++++++--------- libraries/avatars/src/AvatarData.h | 5 +- 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e73702cd95..9034f58c93 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -256,6 +256,8 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { destinationBuffer += _headData->_blendshapeCoefficients.size() * sizeof(float); } + QReadLocker readLock(&_jointDataLock); + // joint rotation data *destinationBuffer++ = _jointData.size(); unsigned char* validityPosition = destinationBuffer; @@ -378,6 +380,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { void AvatarData::doneEncoding(bool cullSmallChanges) { // The server has finished sending this version of the joint-data to other nodes. Update _lastSentJointData. + QReadLocker readLock(&_jointDataLock); _lastSentJointData.resize(_jointData.size()); for (int i = 0; i < _jointData.size(); i ++) { const JointData& data = _jointData[ i ]; @@ -551,8 +554,6 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { PACKET_READ_CHECK(NumJoints, sizeof(uint8_t)); int numJoints = *sourceBuffer++; - _jointData.resize(numJoints); - const int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE); PACKET_READ_CHECK(JointRotationValidityBits, bytesOfValidity); @@ -576,6 +577,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // each joint rotation is stored in 6 bytes. + QWriteLocker writeLock(&_jointDataLock); + _jointData.resize(numJoints); + const int COMPRESSED_QUATERNION_SIZE = 6; PACKET_READ_CHECK(JointRotations, numValidJointRotations * COMPRESSED_QUATERNION_SIZE); for (int i = 0; i < numJoints; i++) { @@ -653,6 +657,7 @@ void AvatarData::setRawJointData(QVector data) { QMetaObject::invokeMethod(this, "setRawJointData", Q_ARG(QVector, data)); return; } + QWriteLocker writeLock(&_jointDataLock); _jointData = data; } @@ -664,6 +669,7 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v QMetaObject::invokeMethod(this, "setJointData", Q_ARG(int, index), Q_ARG(const glm::quat&, rotation)); return; } + QWriteLocker writeLock(&_jointDataLock); if (_jointData.size() <= index) { _jointData.resize(index + 1); } @@ -682,6 +688,8 @@ void AvatarData::clearJointData(int index) { QMetaObject::invokeMethod(this, "clearJointData", Q_ARG(int, index)); return; } + QWriteLocker writeLock(&_jointDataLock); + // BUG: I don't understand how this "clears" the joint data at index if (_jointData.size() <= index) { _jointData.resize(index + 1); } @@ -710,6 +718,7 @@ glm::quat AvatarData::getJointRotation(int index) const { Q_RETURN_ARG(glm::quat, result), Q_ARG(int, index)); return result; } + QReadLocker readLock(&_jointDataLock); return index < _jointData.size() ? _jointData.at(index).rotation : glm::quat(); } @@ -724,6 +733,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const { Q_RETURN_ARG(glm::vec3, result), Q_ARG(int, index)); return result; } + QReadLocker readLock(&_jointDataLock); return index < _jointData.size() ? _jointData.at(index).translation : glm::vec3(); } @@ -771,6 +781,7 @@ void AvatarData::setJointRotation(int index, const glm::quat& rotation) { QMetaObject::invokeMethod(this, "setJointRotation", Q_ARG(int, index), Q_ARG(const glm::quat&, rotation)); return; } + QWriteLocker writeLock(&_jointDataLock); if (_jointData.size() <= index) { _jointData.resize(index + 1); } @@ -787,6 +798,7 @@ void AvatarData::setJointTranslation(int index, const glm::vec3& translation) { QMetaObject::invokeMethod(this, "setJointTranslation", Q_ARG(int, index), Q_ARG(const glm::vec3&, translation)); return; } + QWriteLocker writeLock(&_jointDataLock); if (_jointData.size() <= index) { _jointData.resize(index + 1); } @@ -831,6 +843,7 @@ QVector AvatarData::getJointRotations() const { Q_RETURN_ARG(QVector, result)); return result; } + QReadLocker readLock(&_jointDataLock); QVector jointRotations(_jointData.size()); for (int i = 0; i < _jointData.size(); ++i) { jointRotations[i] = _jointData[i].rotation; @@ -845,6 +858,7 @@ void AvatarData::setJointRotations(QVector jointRotations) { "setJointRotations", Qt::BlockingQueuedConnection, Q_ARG(QVector, jointRotations)); } + QWriteLocker writeLock(&_jointDataLock); if (_jointData.size() < jointRotations.size()) { _jointData.resize(jointRotations.size()); } @@ -862,6 +876,7 @@ void AvatarData::setJointTranslations(QVector jointTranslations) { "setJointTranslations", Qt::BlockingQueuedConnection, Q_ARG(QVector, jointTranslations)); } + QWriteLocker writeLock(&_jointDataLock); if (_jointData.size() < jointTranslations.size()) { _jointData.resize(jointTranslations.size()); } @@ -873,11 +888,23 @@ void AvatarData::setJointTranslations(QVector jointTranslations) { } void AvatarData::clearJointsData() { + // BUG: this method is terribly inefficient and probably doesn't even work + // (see implementation of clearJointData(index)) for (int i = 0; i < _jointData.size(); ++i) { clearJointData(i); } } +int AvatarData::getJointIndex(const QString& name) const { + QReadLocker readLock(&_jointDataLock); + return _jointIndices.value(name) - 1; +} + +QStringList AvatarData::getJointNames() const { + QReadLocker readLock(&_jointDataLock); + return _jointNames; +} + void AvatarData::parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut) { QDataStream packetStream(data); @@ -1027,38 +1054,41 @@ void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { void AvatarData::setJointMappingsFromNetworkReply() { QNetworkReply* networkReply = static_cast(sender()); - QByteArray line; - while (!(line = networkReply->readLine()).isEmpty()) { - line = line.trimmed(); - if (line.startsWith("filename")) { - int filenameIndex = line.indexOf('=') + 1; - if (filenameIndex > 0) { - _skeletonFBXURL = _skeletonModelURL.resolved(QString(line.mid(filenameIndex).trimmed())); + { + QWriteLocker writeLock(&_jointDataLock); + QByteArray line; + while (!(line = networkReply->readLine()).isEmpty()) { + line = line.trimmed(); + if (line.startsWith("filename")) { + int filenameIndex = line.indexOf('=') + 1; + if (filenameIndex > 0) { + _skeletonFBXURL = _skeletonModelURL.resolved(QString(line.mid(filenameIndex).trimmed())); + } } + if (!line.startsWith("jointIndex")) { + continue; } - if (!line.startsWith("jointIndex")) { - continue; - } - int jointNameIndex = line.indexOf('=') + 1; - if (jointNameIndex == 0) { - continue; - } - int secondSeparatorIndex = line.indexOf('=', jointNameIndex); - if (secondSeparatorIndex == -1) { - continue; - } - QString jointName = line.mid(jointNameIndex, secondSeparatorIndex - jointNameIndex).trimmed(); - bool ok; - int jointIndex = line.mid(secondSeparatorIndex + 1).trimmed().toInt(&ok); - if (ok) { - while (_jointNames.size() < jointIndex + 1) { - _jointNames.append(QString()); + int jointNameIndex = line.indexOf('=') + 1; + if (jointNameIndex == 0) { + continue; + } + int secondSeparatorIndex = line.indexOf('=', jointNameIndex); + if (secondSeparatorIndex == -1) { + continue; + } + QString jointName = line.mid(jointNameIndex, secondSeparatorIndex - jointNameIndex).trimmed(); + bool ok; + int jointIndex = line.mid(secondSeparatorIndex + 1).trimmed().toInt(&ok); + if (ok) { + while (_jointNames.size() < jointIndex + 1) { + _jointNames.append(QString()); + } + _jointNames[jointIndex] = jointName; } - _jointNames[jointIndex] = jointName; } - } - for (int i = 0; i < _jointNames.size(); i++) { - _jointIndices.insert(_jointNames.at(i), i + 1); + for (int i = 0; i < _jointNames.size(); i++) { + _jointIndices.insert(_jointNames.at(i), i + 1); + } } networkReply->deleteLater(); @@ -1101,16 +1131,19 @@ void AvatarData::sendIdentityPacket() { } void AvatarData::updateJointMappings() { - _jointIndices.clear(); - _jointNames.clear(); - _jointData.clear(); + { + QWriteLocker writeLock(&_jointDataLock); + _jointIndices.clear(); + _jointNames.clear(); + _jointData.clear(); + } if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); QNetworkReply* networkReply = networkAccessManager.get(networkRequest); - connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); + connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply); } } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 14b4f07471..b88cec3e05 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -271,9 +271,9 @@ public: Q_INVOKABLE virtual void clearJointsData(); /// Returns the index of the joint with the specified name, or -1 if not found/unknown. - Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; } + Q_INVOKABLE virtual int getJointIndex(const QString& name) const; - Q_INVOKABLE virtual QStringList getJointNames() const { return _jointNames; } + Q_INVOKABLE virtual QStringList getJointNames() const; Q_INVOKABLE void setBlendshape(QString name, float val) { _headData->setBlendshape(name, val); } @@ -374,6 +374,7 @@ protected: QVector _jointData; ///< the state of the skeleton joints QVector _lastSentJointData; ///< the state of the skeleton joints last time we transmitted + mutable QReadWriteLock _jointDataLock; // key state KeyState _keyState; From 8acb30da8e1f19d8c906539cd0e16b1280e1fca2 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 24 Jul 2016 16:54:00 -0700 Subject: [PATCH 07/39] add permissions bar --- interface/resources/qml/Browser.qml | 86 ++++++++++++++++++- .../resources/qml/controls-uit/WebView.qml | 4 - 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 3057cd3330..9d709a309f 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -16,6 +16,7 @@ ScrollingWindow { destroyOnHidden: true width: 800 height: 600 + property variant permissionsBar: {'securityOrigin':'none','feature':'none'} property alias webView: webview x: 100 y: 100 @@ -32,6 +33,21 @@ ScrollingWindow { } } + function showPermissionsBar(){ + console.log('should show permissions bar') + permissionsContainer.visible=true; + } + + function hidePermissionsBar(){ + console.log('should hide permissions bar') + permissionsContainer.visible=false; + } + + function allowPermissions(){ + webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true); + hidePermissionsBar(); + } + Item { id:item width: pane.contentWidth @@ -70,6 +86,7 @@ ScrollingWindow { size: 48 MouseArea { anchors.fill: parent; onClicked: webview.goForward() } } + } Item { @@ -116,6 +133,7 @@ ScrollingWindow { if (text.indexOf("http") != 0) { text = "http://" + text } + root.hidePermissionsBar(); webview.url = text break; } @@ -123,16 +141,78 @@ ScrollingWindow { } } + Rectangle { + id:permissionsContainer + visible:false + color: "#000000" + width: parent.width + anchors.top: buttons.bottom + height:40 + z:100 + gradient: Gradient { + GradientStop { position: 0.0; color: "black" } + GradientStop { position: 1.0; color: "grey" } + } + + RalewayLight { + id: permissionsInfo + anchors.right:permissionsRow.left + anchors.rightMargin: 32 + anchors.topMargin:8 + anchors.top:parent.top + text: "This site wants to use your microphone/camera" + size: 18 + color: hifi.colors.white + } + + Row { + id: permissionsRow + spacing: 4 + anchors.top:parent.top + anchors.topMargin: 8 + anchors.right: parent.right + visible: true + z:101 + + Button { + id:allow + text: "Allow" + color: hifi.buttons.blue + colorScheme: root.colorScheme + width: 120 + enabled: true + onClicked: root.allowPermissions(); + z:101 + } + + Button { + id:block + text: "Block" + color: hifi.buttons.red + colorScheme: root.colorScheme + width: 120 + enabled: true + onClicked: root.hidePermissionsBar(); + z:101 + } + } + } + + + + WebEngineView { id: webview - url: "http://highfidelity.com" + url: "https://highfidelity.com" anchors.top: buttons.bottom anchors.topMargin: 8 anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); + permissionsBar.securityOrigin =securityOrigin; + permissionsBar.feature = feature; + root.showPermissionsBar(); } onLoadingChanged: { if (loadRequest.status === WebEngineView.LoadSucceededStatus) { @@ -164,4 +244,4 @@ ScrollingWindow { break; } } -} // dialog +} // dialog \ No newline at end of file diff --git a/interface/resources/qml/controls-uit/WebView.qml b/interface/resources/qml/controls-uit/WebView.qml index acd0e1ae12..4c165fc587 100644 --- a/interface/resources/qml/controls-uit/WebView.qml +++ b/interface/resources/qml/controls-uit/WebView.qml @@ -48,10 +48,6 @@ WebEngineView { } } - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - onLoadingChanged: { // Required to support clicking on "hifi://" links if (WebEngineView.LoadStartedStatus == loadRequest.status) { From 3b25b36db32ee5586b8fb98e1e2ec0195eb91470 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sun, 24 Jul 2016 16:57:15 -0700 Subject: [PATCH 08/39] cleanup --- interface/resources/qml/Browser.qml | 70 +++++++++++++---------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 9d709a309f..3dfcf98e25 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -34,12 +34,10 @@ ScrollingWindow { } function showPermissionsBar(){ - console.log('should show permissions bar') permissionsContainer.visible=true; } function hidePermissionsBar(){ - console.log('should hide permissions bar') permissionsContainer.visible=false; } @@ -141,39 +139,39 @@ ScrollingWindow { } } - Rectangle { - id:permissionsContainer - visible:false - color: "#000000" - width: parent.width - anchors.top: buttons.bottom - height:40 - z:100 - gradient: Gradient { - GradientStop { position: 0.0; color: "black" } - GradientStop { position: 1.0; color: "grey" } - } - - RalewayLight { - id: permissionsInfo - anchors.right:permissionsRow.left - anchors.rightMargin: 32 - anchors.topMargin:8 - anchors.top:parent.top - text: "This site wants to use your microphone/camera" - size: 18 - color: hifi.colors.white + Rectangle { + id:permissionsContainer + visible:false + color: "#000000" + width: parent.width + anchors.top: buttons.bottom + height:40 + z:100 + gradient: Gradient { + GradientStop { position: 0.0; color: "black" } + GradientStop { position: 1.0; color: "grey" } } - - Row { - id: permissionsRow - spacing: 4 - anchors.top:parent.top - anchors.topMargin: 8 - anchors.right: parent.right - visible: true - z:101 + RalewayLight { + id: permissionsInfo + anchors.right:permissionsRow.left + anchors.rightMargin: 32 + anchors.topMargin:8 + anchors.top:parent.top + text: "This site wants to use your microphone/camera" + size: 18 + color: hifi.colors.white + } + + Row { + id: permissionsRow + spacing: 4 + anchors.top:parent.top + anchors.topMargin: 8 + anchors.right: parent.right + visible: true + z:101 + Button { id:allow text: "Allow" @@ -196,10 +194,7 @@ ScrollingWindow { z:101 } } - } - - - + } WebEngineView { id: webview @@ -228,7 +223,6 @@ ScrollingWindow { request.openIn(newWindow.webView) } //profile: desktop.browserProfile - } } // item From d876251f1e9e36987c3094e52b119ae15aa180a9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 24 Jul 2016 19:17:39 -0700 Subject: [PATCH 09/39] release geometry refs in Model::deleteGeometry() --- libraries/render-utils/src/Model.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e2363d0cca..b04a1d8023 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1192,6 +1192,8 @@ void Model::deleteGeometry() { _meshStates.clear(); _rig->destroyAnimGraph(); _blendedBlendshapeCoefficients.clear(); + _renderGeometry.reset(); + _collisionGeometry.reset(); } AABox Model::getRenderableMeshBound() const { From 1df3b59aa19e19ae07ec009deaf1f0f92b7d248a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Sun, 24 Jul 2016 19:19:35 -0700 Subject: [PATCH 10/39] change BUG to FIXME --- libraries/avatars/src/AvatarData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9034f58c93..dee0d1cb20 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -689,7 +689,7 @@ void AvatarData::clearJointData(int index) { return; } QWriteLocker writeLock(&_jointDataLock); - // BUG: I don't understand how this "clears" the joint data at index + // FIXME: I don't understand how this "clears" the joint data at index if (_jointData.size() <= index) { _jointData.resize(index + 1); } @@ -888,7 +888,7 @@ void AvatarData::setJointTranslations(QVector jointTranslations) { } void AvatarData::clearJointsData() { - // BUG: this method is terribly inefficient and probably doesn't even work + // FIXME: this method is terribly inefficient and probably doesn't even work // (see implementation of clearJointData(index)) for (int i = 0; i < _jointData.size(); ++i) { clearJointData(i); From 708cce64b662145bf7e5e8c204a72ccbd2d18f68 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 25 Jul 2016 11:05:55 -0700 Subject: [PATCH 11/39] work with far trigger --- .../DomainContent/Home/whiteboard/swiper.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/unpublishedScripts/DomainContent/Home/whiteboard/swiper.js b/unpublishedScripts/DomainContent/Home/whiteboard/swiper.js index cd19c6eeee..555224e2b6 100644 --- a/unpublishedScripts/DomainContent/Home/whiteboard/swiper.js +++ b/unpublishedScripts/DomainContent/Home/whiteboard/swiper.js @@ -18,11 +18,22 @@ busy: false, preload: function(entityID) { this.entityID = entityID; + Entities.editEntity(entityID, { + userData: JSON.stringify({ + grabbableKey: { + grabbable: false, + wantsTrigger: true + } + }) + }); Script.update.connect(this.update); }, clickReleaseOnEntity: function() { this.createSupplies(); }, + startFarTrigger: function() { + this.createSupplies(); + }, update: function() { if (_this.busy === true) { return; @@ -45,7 +56,6 @@ }, 2000) } }, - createSupplies: function() { var myProperties = Entities.getEntityProperties(this.entityID); From 84e4de4bad8043136a560d6ad855155a9e12dde8 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 25 Jul 2016 11:11:37 -0700 Subject: [PATCH 12/39] update formatting --- interface/resources/qml/Browser.qml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 1287102bed..be9154dc77 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -141,17 +141,17 @@ ScrollingWindow { } Rectangle { - id:permissionsContainer - visible:false - color: "#000000" - width: parent.width - anchors.top: buttons.bottom - height:40 - z:100 - gradient: Gradient { - GradientStop { position: 0.0; color: "black" } - GradientStop { position: 1.0; color: "grey" } - } + id:permissionsContainer + visible:false + color: "#000000" + width: parent.width + anchors.top: buttons.bottom + height:40 + z:100 + gradient: Gradient { + GradientStop { position: 0.0; color: "black" } + GradientStop { position: 1.0; color: "grey" } + } RalewayLight { id: permissionsInfo @@ -206,7 +206,7 @@ ScrollingWindow { anchors.left: parent.left anchors.right: parent.right onFeaturePermissionRequested: { - permissionsBar.securityOrigin =securityOrigin; + permissionsBar.securityOrigin = securityOrigin; permissionsBar.feature = feature; root.showPermissionsBar(); } From 38765e6fa4b59e1f14ac79f800d09dd0916b5242 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Mon, 25 Jul 2016 11:12:34 -0700 Subject: [PATCH 13/39] extra space --- interface/resources/qml/Browser.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index be9154dc77..47231957c2 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -207,7 +207,7 @@ ScrollingWindow { anchors.right: parent.right onFeaturePermissionRequested: { permissionsBar.securityOrigin = securityOrigin; - permissionsBar.feature = feature; + permissionsBar.feature = feature; root.showPermissionsBar(); } onLoadingChanged: { From 344ec25bcd3ede709e5edc0553e01769bad75f32 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Mon, 25 Jul 2016 14:01:57 -0700 Subject: [PATCH 14/39] Fix gravity for dynamic entities --- interface/resources/qml/AssetServer.qml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 02c72f5b2d..3d0526e3c3 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -207,7 +207,14 @@ ScrollingWindow { } else if (url) { var name = assetProxyModel.data(treeView.selection.currentIndex); var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); - var gravity = dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 }; + var gravity; + if (dynamic) { + // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a + // different scripting engine from QTScript. + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); + } else { + gravity = { x: 0, y: 0, z: 0 }; + } print("Asset browser - adding asset " + url + " (" + name + ") to world."); From 90154158b6eb1a5099fae6ece1b0b3cd5dbbc2f6 Mon Sep 17 00:00:00 2001 From: Zander Otavka Date: Mon, 25 Jul 2016 14:08:07 -0700 Subject: [PATCH 15/39] Fix gravity zero vector --- interface/resources/qml/AssetServer.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 3d0526e3c3..8d971e48d3 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -213,7 +213,7 @@ ScrollingWindow { // different scripting engine from QTScript. gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); } else { - gravity = { x: 0, y: 0, z: 0 }; + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); } print("Asset browser - adding asset " + url + " (" + name + ") to world."); From fb84f058d6856784ea5fe8b74b0519c35f23674f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 25 Jul 2016 15:56:05 -0700 Subject: [PATCH 16/39] Fix alpha cut-outs and incorrect gamma on Web3DOverlays --- interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 41 +++++++++++++++++++ libraries/render-utils/src/GeometryCache.h | 9 ++++ ...imple_srgb_textured_unlit_no_dst_alpha.slf | 34 +++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index c9c24d3ab6..b224b3a047 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -101,7 +101,7 @@ void Web3DOverlay::render(RenderArgs* args) { batch.setModelTransform(transform); auto geometryCache = DependencyManager::get(); - geometryCache->bindSimpleProgram(batch, true, false, true, false); + geometryCache->bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(batch); geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index cebd8ad37f..7c4172b8e5 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -35,6 +35,7 @@ #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" +#include "simple_srgb_textured_unlit_no_dst_alpha_frag.h" #include "glowLine_vert.h" #include "glowLine_geom.h" #include "glowLine_frag.h" @@ -1748,6 +1749,46 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } +void GeometryCache::bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(gpu::Batch& batch) { + batch.setPipeline(getSimpleSRGBTexturedUnlitNoDstAlphaPipeline()); + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, + DependencyManager::get()->getNormalFittingTexture()); +} + +gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline() { + // Compile the shaders, once + static std::once_flag once; + std::call_once(once, [&]() { + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_srgb_textured_unlit_no_dst_alpha_frag)); + + _simpleSRGBTexturedUnlitNoDstAlphaShader = gpu::Shader::createProgram(VS, PS); + + gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); + gpu::Shader::makeProgram(*_simpleSRGBTexturedUnlitNoDstAlphaShader, slotBindings); + }); + + if (_simpleSRGBTexturedUnlitNoDstAlphaPipeline) { + return _simpleSRGBTexturedUnlitNoDstAlphaPipeline; + } + + // If the pipeline did not exist, make it + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_NONE); + + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::ShaderPointer program = _simpleSRGBTexturedUnlitNoDstAlphaShader; + gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); + _simpleSRGBTexturedUnlitNoDstAlphaPipeline = pipeline; + return pipeline; +} + void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool unlit, bool depthBiased) { batch.setPipeline(getSimplePipeline(textured, culled, unlit, depthBiased)); diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index bab0942672..3d987939d4 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -157,6 +157,11 @@ public: // Get the pipeline to render static geometry gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true, bool unlit = false, bool depthBias = false); + + + void bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(gpu::Batch& batch); + gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline(); + render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; } render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; } @@ -416,6 +421,10 @@ private: static render::ShapePipelinePointer _simpleWirePipeline; gpu::PipelinePointer _glowLinePipeline; QHash _simplePrograms; + + gpu::ShaderPointer _simpleSRGBTexturedUnlitNoDstAlphaShader; + gpu::PipelinePointer _simpleSRGBTexturedUnlitNoDstAlphaPipeline; + }; #endif // hifi_GeometryCache_h diff --git a/libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf b/libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf new file mode 100644 index 0000000000..e2109973db --- /dev/null +++ b/libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf @@ -0,0 +1,34 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple.frag +// fragment shader +// +// Created by Anthony Thibault on 7/25/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Color.slh@> +<@include DeferredBufferWrite.slh@> + +// the albedo texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 _normal; +in vec4 _color; +in vec2 _texCoord0; + +void main(void) { + vec4 texel = texture(originalTexture, _texCoord0.st); + texel = colorToLinearRGBA(texel); + + packDeferredFragmentUnlit( + normalize(_normal), + 1.0, + _color.rgb * texel.rgb); +} From 0a35c13a94cd805955b8e24cd4f8dc9f8e0e80dd Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 25 Jul 2016 16:30:29 -0700 Subject: [PATCH 17/39] Moved creation of pipeline into call_once block --- libraries/render-utils/src/GeometryCache.cpp | 26 +++++++------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 7c4172b8e5..7ec2a84cf9 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1768,25 +1768,17 @@ gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); gpu::Shader::makeProgram(*_simpleSRGBTexturedUnlitNoDstAlphaShader, slotBindings); + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_NONE); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + _simpleSRGBTexturedUnlitNoDstAlphaPipeline = gpu::Pipeline::create(_simpleSRGBTexturedUnlitNoDstAlphaShader, state); }); - if (_simpleSRGBTexturedUnlitNoDstAlphaPipeline) { - return _simpleSRGBTexturedUnlitNoDstAlphaPipeline; - } - - // If the pipeline did not exist, make it - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_NONE); - - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - - gpu::ShaderPointer program = _simpleSRGBTexturedUnlitNoDstAlphaShader; - gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); - _simpleSRGBTexturedUnlitNoDstAlphaPipeline = pipeline; - return pipeline; + return _simpleSRGBTexturedUnlitNoDstAlphaPipeline; } void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool unlit, bool depthBiased) { From 83dc9ea6bba4391b2642d9dba405f1afe8e0697f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Mon, 25 Jul 2016 21:46:30 -0700 Subject: [PATCH 18/39] punish slow scripts and don't send updates while physics is still loading --- interface/src/Application.cpp | 5 ++++ interface/src/Application.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 31 +++++++++++++++++--- libraries/script-engine/src/ScriptEngine.h | 5 ++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc37325ac5..faa1229cad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4678,6 +4678,11 @@ void Application::packetSent(quint64 length) { } void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { + + scriptEngine->setPhysicsEnabledFunction([this]() { + return isPhysicsEnabled(); + }); + // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. auto entityScriptingInterface = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index a254072561..0af65f665f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -215,6 +215,7 @@ public: qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } bool isAboutToQuit() const { return _aboutToQuit; } + bool isPhysicsEnabled() const { return _physicsEnabled; } // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display // rendering of several elements depend on that diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 9642aaf588..2ce3fcd7e0 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -828,24 +828,42 @@ void ScriptEngine::run() { _lastUpdate = usecTimestampNow(); + qint64 totalSleepFor = 0; + std::chrono::microseconds totalUpdates; + auto lastLoopStart = clock::now(); + // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine while (!_isFinished) { + auto thisLoopStart = clock::now(); + // Throttle to SCRIPT_FPS const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); + const std::chrono::microseconds MINIMUM_SLEEP { FRAME_DURATION / 2 }; + + auto beforeSleep = clock::now(); clock::time_point sleepTime(startTime + thisFrame++ * FRAME_DURATION); + auto wouldSleep = (sleepTime - clock::now()); + auto avgUpdates = totalUpdates / thisFrame; + + if (wouldSleep < avgUpdates) { + sleepTime = beforeSleep + avgUpdates; + } + std::this_thread::sleep_until(sleepTime); #ifdef SCRIPT_DELAY_DEBUG { - auto now = clock::now(); - uint64_t seconds = std::chrono::duration_cast(now - startTime).count(); + auto sleptTill = clock::now(); + uint64_t seconds = std::chrono::duration_cast(sleptTill - startTime).count(); if (seconds > 0) { // avoid division by zero and time travel uint64_t fps = thisFrame / seconds; // Overreporting artificially reduces the reported rate if (thisFrame % SCRIPT_FPS == 0) { qCDebug(scriptengine) << "Frame:" << thisFrame << - "Slept (us):" << std::chrono::duration_cast(now - sleepTime).count() << + "Slept (us):" << std::chrono::duration_cast(sleptTill - beforeSleep).count() << + "Avg Updates (us):" << avgUpdates.count() << + "Last loop time (us):" << std::chrono::duration_cast(thisLoopStart - lastLoopStart).count() << "FPS:" << fps; } } @@ -874,16 +892,21 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); // we check for 'now' in the past in case people set their clock back - if (_lastUpdate < now) { + if (_isPhysicsEnabledFunc() && _lastUpdate < now) { float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND; if (!_isFinished) { + auto preUpdate = clock::now(); emit update(deltaTime); + auto postUpdate = clock::now(); + auto elapsed = (postUpdate - preUpdate); + totalUpdates += std::chrono::duration_cast(elapsed); } } _lastUpdate = now; // Debug and clear exceptions hadUncaughtExceptions(*this, _fileNameString); + lastLoopStart = thisLoopStart; } qCDebug(scriptengine) << "Script Engine stopping:" << getFilename(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1077dce686..a62f6e1a88 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -168,6 +168,8 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } + void setPhysicsEnabledFunction(std::function func) { _isPhysicsEnabledFunc = func; } + public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); void updateMemoryCost(const qint64&); @@ -236,6 +238,9 @@ protected: QUrl currentSandboxURL {}; // The toplevel url string for the entity script that loaded the code being executed, else empty. void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); + + std::function _isPhysicsEnabledFunc{ [](){ return true; } }; + }; #endif // hifi_ScriptEngine_h From a12034cb45255d19fc1b880a2e8e4beaff8e7b9e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 26 Jul 2016 07:54:55 -0700 Subject: [PATCH 19/39] fix unix warning, added comments --- libraries/script-engine/src/ScriptEngine.cpp | 35 ++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2ce3fcd7e0..fd09e9a018 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -828,42 +828,44 @@ void ScriptEngine::run() { _lastUpdate = usecTimestampNow(); - qint64 totalSleepFor = 0; std::chrono::microseconds totalUpdates; - auto lastLoopStart = clock::now(); // TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine while (!_isFinished) { - auto thisLoopStart = clock::now(); + auto beforeSleep = clock::now(); // Throttle to SCRIPT_FPS + // We'd like to try to keep the script at a solid SCRIPT_FPS update rate. And so we will + // calculate a sleepUntil to be the time from our start time until the original target + // sleepUntil for this frame. const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); - const std::chrono::microseconds MINIMUM_SLEEP { FRAME_DURATION / 2 }; + clock::time_point sleepUntil(startTime + thisFrame++ * FRAME_DURATION); - auto beforeSleep = clock::now(); - clock::time_point sleepTime(startTime + thisFrame++ * FRAME_DURATION); - auto wouldSleep = (sleepTime - clock::now()); - auto avgUpdates = totalUpdates / thisFrame; + // However, if our sleepUntil is not at least our average update time into the future + // it means our script is taking too long in it's updates, and we want to punish the + // script a little bit. So we will force the sleepUntil to be at least our averageUpdate + // time into the future. + auto wouldSleep = (sleepUntil - clock::now()); + auto avgerageUpdate = totalUpdates / thisFrame; - if (wouldSleep < avgUpdates) { - sleepTime = beforeSleep + avgUpdates; + if (wouldSleep < avgerageUpdate) { + sleepUntil = beforeSleep + avgerageUpdate; } - std::this_thread::sleep_until(sleepTime); + std::this_thread::sleep_until(sleepUntil); #ifdef SCRIPT_DELAY_DEBUG { - auto sleptTill = clock::now(); - uint64_t seconds = std::chrono::duration_cast(sleptTill - startTime).count(); + auto actuallySleptUntil = clock::now(); + uint64_t seconds = std::chrono::duration_cast(actuallySleptUntil - startTime).count(); if (seconds > 0) { // avoid division by zero and time travel uint64_t fps = thisFrame / seconds; // Overreporting artificially reduces the reported rate if (thisFrame % SCRIPT_FPS == 0) { qCDebug(scriptengine) << "Frame:" << thisFrame << - "Slept (us):" << std::chrono::duration_cast(sleptTill - beforeSleep).count() << - "Avg Updates (us):" << avgUpdates.count() << - "Last loop time (us):" << std::chrono::duration_cast(thisLoopStart - lastLoopStart).count() << + "Slept (us):" << std::chrono::duration_cast(actuallySleptUntil - beforeSleep).count() << + "Avg Updates (us):" << avgerageUpdate.count() << "FPS:" << fps; } } @@ -906,7 +908,6 @@ void ScriptEngine::run() { // Debug and clear exceptions hadUncaughtExceptions(*this, _fileNameString); - lastLoopStart = thisLoopStart; } qCDebug(scriptengine) << "Script Engine stopping:" << getFilename(); From 2d199fe3d007f3a6fb7f9c1099aac08c583e416d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 26 Jul 2016 08:08:32 -0700 Subject: [PATCH 20/39] rename function for better clarity --- interface/src/Application.cpp | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/script-engine/src/ScriptEngine.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index faa1229cad..eba400ebc5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4679,7 +4679,7 @@ void Application::packetSent(quint64 length) { void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { - scriptEngine->setPhysicsEnabledFunction([this]() { + scriptEngine->setEmitScriptUpdatesFunction([this]() { return isPhysicsEnabled(); }); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fd09e9a018..21eae99307 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -894,7 +894,7 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); // we check for 'now' in the past in case people set their clock back - if (_isPhysicsEnabledFunc() && _lastUpdate < now) { + if (_emitScriptUpdates() && _lastUpdate < now) { float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND; if (!_isFinished) { auto preUpdate = clock::now(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index a62f6e1a88..e093f0393b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -168,7 +168,7 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - void setPhysicsEnabledFunction(std::function func) { _isPhysicsEnabledFunc = func; } + void setEmitScriptUpdatesFunction(std::function func) { _emitScriptUpdates = func; } public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); @@ -239,7 +239,7 @@ protected: void doWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, std::function operation); void callWithEnvironment(const EntityItemID& entityID, const QUrl& sandboxURL, QScriptValue function, QScriptValue thisObject, QScriptValueList args); - std::function _isPhysicsEnabledFunc{ [](){ return true; } }; + std::function _emitScriptUpdates{ [](){ return true; } }; }; From 3962487ee394fb278b3f7fed20a41032a5c05250 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 08:51:12 -0700 Subject: [PATCH 21/39] Fix depth state caching / resetting --- .../gpu-gl/src/gpu/gl/GLBackendState.cpp | 83 ++++++++++--------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp index a42b0dca6f..f04a0a75f8 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp @@ -158,64 +158,73 @@ void GLBackend::do_setStateDepthBias(Vec2 bias) { } void GLBackend::do_setStateDepthTest(State::DepthTest test) { - if (_pipeline._stateCache.depthTest != test) { + const auto& current = _pipeline._stateCache.depthTest; + if (current != test) { if (test.isEnabled()) { glEnable(GL_DEPTH_TEST); - glDepthMask(test.getWriteMask()); - glDepthFunc(COMPARISON_TO_GL[test.getFunction()]); } else { glDisable(GL_DEPTH_TEST); } + if (test.getWriteMask() != current.getWriteMask()) { + glDepthMask(test.getWriteMask()); + } + if (test.getFunction() != current.getFunction()) { + glDepthFunc(COMPARISON_TO_GL[test.getFunction()]); + } if (CHECK_GL_ERROR()) { qDebug() << "DepthTest" << (test.isEnabled() ? "Enabled" : "Disabled") << "Mask=" << (test.getWriteMask() ? "Write" : "no Write") << "Func=" << test.getFunction() << "Raw=" << test.getRaw(); } - _pipeline._stateCache.depthTest = test; } } void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) { - - if ((_pipeline._stateCache.stencilActivation != activation) - || (_pipeline._stateCache.stencilTestFront != frontTest) - || (_pipeline._stateCache.stencilTestBack != backTest)) { + const auto& currentActivation = _pipeline._stateCache.stencilActivation; + const auto& currentTestFront = _pipeline._stateCache.stencilTestFront; + const auto& currentTestBack = _pipeline._stateCache.stencilTestBack; + if ((currentActivation != activation) + || (currentTestFront != frontTest) + || (currentTestBack != backTest)) { if (activation.isEnabled()) { glEnable(GL_STENCIL_TEST); - - if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) { - glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); - glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); - } else { - glStencilMask(activation.getWriteMaskFront()); - } - - static GLenum STENCIL_OPS[] = { - GL_KEEP, - GL_ZERO, - GL_REPLACE, - GL_INCR_WRAP, - GL_DECR_WRAP, - GL_INVERT, - GL_INCR, - GL_DECR }; - - if (frontTest != backTest) { - glStencilOpSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); - glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); - - glStencilOpSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]); - glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[backTest.getFunction()], backTest.getReference(), backTest.getReadMask()); - } else { - glStencilOp(STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); - glStencilFunc(COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); - } - } else { + } + else { glDisable(GL_STENCIL_TEST); } + + if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) { + glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); + glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); + } + else { + glStencilMask(activation.getWriteMaskFront()); + } + + static GLenum STENCIL_OPS[State::NUM_STENCIL_OPS] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR_WRAP, + GL_DECR_WRAP, + GL_INVERT, + GL_INCR, + GL_DECR }; + + if (frontTest != backTest) { + glStencilOpSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); + glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); + + glStencilOpSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]); + glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[backTest.getFunction()], backTest.getReference(), backTest.getReadMask()); + } else { + glStencilOp(STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); + glStencilFunc(COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); + } + (void)CHECK_GL_ERROR(); _pipeline._stateCache.stencilActivation = activation; From ac743b6acbe20dda7fde4c630a00f1ad2f5cebad Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 11:53:37 -0700 Subject: [PATCH 22/39] PR feedback --- .../gpu-gl/src/gpu/gl/GLBackendState.cpp | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp index f04a0a75f8..b1e4f427db 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendState.cpp @@ -181,26 +181,24 @@ void GLBackend::do_setStateDepthTest(State::DepthTest test) { } } -void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest frontTest, State::StencilTest backTest) { +void GLBackend::do_setStateStencil(State::StencilActivation activation, State::StencilTest testFront, State::StencilTest testBack) { const auto& currentActivation = _pipeline._stateCache.stencilActivation; const auto& currentTestFront = _pipeline._stateCache.stencilTestFront; const auto& currentTestBack = _pipeline._stateCache.stencilTestBack; if ((currentActivation != activation) - || (currentTestFront != frontTest) - || (currentTestBack != backTest)) { + || (currentTestFront != testFront) + || (currentTestBack != testBack)) { if (activation.isEnabled()) { glEnable(GL_STENCIL_TEST); - } - else { + } else { glDisable(GL_STENCIL_TEST); } if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) { glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront()); glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack()); - } - else { + } else { glStencilMask(activation.getWriteMaskFront()); } @@ -214,22 +212,22 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S GL_INCR, GL_DECR }; - if (frontTest != backTest) { - glStencilOpSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); - glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); + if (testFront != testBack) { + glStencilOpSeparate(GL_FRONT, STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getPassOp()], STENCIL_OPS[testFront.getDepthFailOp()]); + glStencilFuncSeparate(GL_FRONT, COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); - glStencilOpSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]); - glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[backTest.getFunction()], backTest.getReference(), backTest.getReadMask()); + glStencilOpSeparate(GL_BACK, STENCIL_OPS[testBack.getFailOp()], STENCIL_OPS[testBack.getPassOp()], STENCIL_OPS[testBack.getDepthFailOp()]); + glStencilFuncSeparate(GL_BACK, COMPARISON_TO_GL[testBack.getFunction()], testBack.getReference(), testBack.getReadMask()); } else { - glStencilOp(STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]); - glStencilFunc(COMPARISON_TO_GL[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask()); + glStencilOp(STENCIL_OPS[testFront.getFailOp()], STENCIL_OPS[testFront.getPassOp()], STENCIL_OPS[testFront.getDepthFailOp()]); + glStencilFunc(COMPARISON_TO_GL[testFront.getFunction()], testFront.getReference(), testFront.getReadMask()); } (void)CHECK_GL_ERROR(); _pipeline._stateCache.stencilActivation = activation; - _pipeline._stateCache.stencilTestFront = frontTest; - _pipeline._stateCache.stencilTestBack = backTest; + _pipeline._stateCache.stencilTestFront = testFront; + _pipeline._stateCache.stencilTestBack = testBack; } } From a455f3a435961b8d2024c8d31dddbe6c9e6aa12c Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 15:25:36 -0700 Subject: [PATCH 23/39] Add frame concept to gpu library --- libraries/gpu/src/gpu/Forward.h | 4 ++++ libraries/gpu/src/gpu/Frame.cpp | 10 ++++++++++ libraries/gpu/src/gpu/Frame.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 libraries/gpu/src/gpu/Frame.cpp create mode 100644 libraries/gpu/src/gpu/Frame.h diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index 7fe6739ff7..e2a4ad38dd 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -21,6 +22,9 @@ namespace gpu { class Context; using ContextPointer = std::shared_ptr; class GPUObject; + class Frame; + using FramePointer = std::shared_ptr; + using FrameHandler = std::function; using Stamp = int; using uint32 = uint32_t; diff --git a/libraries/gpu/src/gpu/Frame.cpp b/libraries/gpu/src/gpu/Frame.cpp new file mode 100644 index 0000000000..d36c7f5537 --- /dev/null +++ b/libraries/gpu/src/gpu/Frame.cpp @@ -0,0 +1,10 @@ +// +// Created by Bradley Austin Davis on 2016/07/26 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Frame.h" + +using namespace gpu; diff --git a/libraries/gpu/src/gpu/Frame.h b/libraries/gpu/src/gpu/Frame.h new file mode 100644 index 0000000000..99296cc91e --- /dev/null +++ b/libraries/gpu/src/gpu/Frame.h @@ -0,0 +1,28 @@ +// +// Created by Bradley Austin Davis on 2016/07/26 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Frame_h +#define hifi_gpu_Frame_h + +#include "Forward.h" + +namespace gpu { + +class Frame { +public: + /// The sensor pose used for rendering the frame, only applicable for HMDs + glm::mat4 pose; + /// The collection of batches which make up the frame + std::vector batches; + /// The destination framebuffer in which the results will be placed + FramebufferPointer framebuffer; +}; + +}; + + +#endif From bb6abf11d33b2f4f29da312a912d25c28323abd0 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 15:32:31 -0700 Subject: [PATCH 24/39] FramebufferCache, cleanup & thread safety --- .../render-utils/src/FramebufferCache.cpp | 27 +++++++------------ libraries/render-utils/src/FramebufferCache.h | 13 ++++----- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 5375de273a..4ada0ce980 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -11,34 +11,25 @@ #include "FramebufferCache.h" -#include - #include +#include +#include -#include -#include -#include #include "RenderUtilsLogging.h" -static QQueue _cachedFramebuffers; - -FramebufferCache::FramebufferCache() { -} - -FramebufferCache::~FramebufferCache() { - _cachedFramebuffers.clear(); -} - void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { //If the size changed, we need to delete our FBOs if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; _selfieFramebuffer.reset(); - _cachedFramebuffers.clear(); _occlusionFramebuffer.reset(); _occlusionTexture.reset(); _occlusionBlurredFramebuffer.reset(); _occlusionBlurredTexture.reset(); + { + std::unique_lock lock(_mutex); + _cachedFramebuffers.clear(); + } } } @@ -55,8 +46,6 @@ void FramebufferCache::createPrimaryFramebuffer() { auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); - - resizeAmbientOcclusionBuffers(); } @@ -87,7 +76,8 @@ void FramebufferCache::resizeAmbientOcclusionBuffers() { gpu::FramebufferPointer FramebufferCache::getFramebuffer() { - if (_cachedFramebuffers.isEmpty()) { + std::unique_lock lock(_mutex); + if (_cachedFramebuffers.empty()) { _cachedFramebuffers.push_back(gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_SRGBA_32, _frameBufferSize.width(), _frameBufferSize.height()))); } gpu::FramebufferPointer result = _cachedFramebuffers.front(); @@ -96,6 +86,7 @@ gpu::FramebufferPointer FramebufferCache::getFramebuffer() { } void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebuffer) { + std::unique_lock lock(_mutex); if (QSize(framebuffer->getSize().x, framebuffer->getSize().y) == _frameBufferSize) { _cachedFramebuffers.push_back(framebuffer); } diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index d3d26c35b0..10ec664669 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -11,13 +11,10 @@ #include -#include +#include +#include #include -namespace gpu { -class Batch; -} - /// Stores cached textures, including render-to-texture targets. class FramebufferCache : public Dependency { SINGLETON_DEPENDENCY @@ -47,9 +44,6 @@ public: void releaseFramebuffer(const gpu::FramebufferPointer& framebuffer); private: - FramebufferCache(); - virtual ~FramebufferCache(); - void createPrimaryFramebuffer(); gpu::FramebufferPointer _shadowFramebuffer; @@ -65,6 +59,9 @@ private: QSize _frameBufferSize{ 100, 100 }; int _AOResolutionLevel = 1; // AO perform at half res + std::mutex _mutex; + std::list _cachedFramebuffers; + // Resize/reallocate the buffers used for AO // the size of the AO buffers is scaled by the AOResolutionScale; void resizeAmbientOcclusionBuffers(); From fa2089828564e9930982ddad67bd19ff3e3e7aab Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 16:13:22 -0700 Subject: [PATCH 25/39] Remove last direct use of gpu::Context::render() --- libraries/render-utils/src/RenderDeferredTask.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index bb7adf3f80..e39d659051 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -347,10 +347,10 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon // Needs to be distinct from the other batch because using the clear call // while stereo is enabled triggers a warning if (_opaquePass) { - gpu::Batch batch; - batch.enableStereo(false); - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, true); - args->_context->render(batch); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch){ + batch.enableStereo(false); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0, true); + }); } // Render the items From a9740b803fa91931e845615a8fbf5efad2c5f54d Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 16:13:48 -0700 Subject: [PATCH 26/39] Defer batch execution to the end of the frame generation --- interface/src/Application.cpp | 31 +++++++----- libraries/gpu/src/gpu/Batch.cpp | 27 +++++++++++ libraries/gpu/src/gpu/Context.cpp | 80 ++++++++++++++++++++++++------- libraries/gpu/src/gpu/Context.h | 73 +++++++++++----------------- libraries/gpu/src/gpu/Forward.h | 9 ++++ libraries/gpu/src/gpu/Frame.h | 1 + 6 files changed, 147 insertions(+), 74 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eba400ebc5..e294ae38ad 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1689,6 +1689,17 @@ void Application::paintGL() { renderArgs._context->syncCache(); } + auto framebufferCache = DependencyManager::get(); + // Final framebuffer that will be handled to the display-plugin + auto finalFramebuffer = framebufferCache->getFramebuffer(); + + _gpuContext->beginFrame(finalFramebuffer, getHMDSensorPose()); + // Reset the gpu::Context Stages + // Back to the default framebuffer; + gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) { + batch.resetStages(); + }); + auto inputs = AvatarInputs::getInstance(); if (inputs->mirrorVisible()) { PerformanceTimer perfTimer("Mirror"); @@ -1711,10 +1722,6 @@ void Application::paintGL() { QSize size = getDeviceSize(); renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); - auto overlayTexture = _applicationOverlay.acquireOverlay(); - if (overlayTexture) { - displayPlugin->submitOverlayTexture(overlayTexture); - } } glm::vec3 boomOffset; @@ -1816,12 +1823,8 @@ void Application::paintGL() { getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform()); // Primary rendering pass - auto framebufferCache = DependencyManager::get(); const QSize size = framebufferCache->getFrameBufferSize(); - // Final framebuffer that will be handled to the display-plugin - auto finalFramebuffer = framebufferCache->getFramebuffer(); - { PROFILE_RANGE(__FUNCTION__ "/mainRender"); PerformanceTimer perfTimer("mainRender"); @@ -1880,6 +1883,13 @@ void Application::paintGL() { renderArgs._context->enableStereo(false); } + _gpuContext->endFrame(); + + gpu::TexturePointer overlayTexture = _applicationOverlay.acquireOverlay(); + if (overlayTexture) { + displayPlugin->submitOverlayTexture(overlayTexture); + } + // deliver final composited scene to the display plugin { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); @@ -1900,11 +1910,6 @@ void Application::paintGL() { { Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages - // Back to the default framebuffer; - gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) { - batch.resetStages(); - }); } uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9161ee3642..ab1337070c 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -46,6 +46,33 @@ Batch::Batch() { _drawCallInfos.reserve(_drawCallInfosMax); } +Batch::Batch(const Batch& batch_) { + Batch& batch = *const_cast(&batch_); + _commands.swap(batch._commands); + _commandOffsets.swap(batch._commandOffsets); + _params.swap(batch._params); + _data.swap(batch._data); + _invalidModel = batch._invalidModel; + _currentModel = batch._currentModel; + _objects.swap(batch._objects); + _currentNamedCall = batch._currentNamedCall; + + _buffers._items.swap(batch._buffers._items); + _textures._items.swap(batch._textures._items); + _streamFormats._items.swap(batch._streamFormats._items); + _transforms._items.swap(batch._transforms._items); + _pipelines._items.swap(batch._pipelines._items); + _framebuffers._items.swap(batch._framebuffers._items); + _drawCallInfos.swap(batch._drawCallInfos); + _queries._items.swap(batch._queries._items); + _lambdas._items.swap(batch._lambdas._items); + _profileRanges._items.swap(batch._profileRanges._items); + _names._items.swap(batch._names._items); + _namedData.swap(batch._namedData); + _enableStereo = batch._enableStereo; + _enableSkybox = batch._enableSkybox; +} + Batch::~Batch() { _commandsMax = std::max(_commands.size(), _commandsMax); _commandOffsetsMax = std::max(_commandOffsets.size(), _commandOffsetsMax); diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 2c27260331..ff43491133 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Context.h" - +#include "Frame.h" using namespace gpu; Context::CreateBackend Context::_createBackendCallback = nullptr; @@ -20,6 +20,13 @@ Context::Context() { if (_createBackendCallback) { _backend.reset(_createBackendCallback()); } + + _frameHandler = [this](Frame& frame){ + for (size_t i = 0; i < frame.batches.size(); ++i) { + _backend->_stereo = frame.stereoStates[i]; + _backend->render(frame.batches[i]); + } + }; } Context::Context(const Context& context) { @@ -28,6 +35,43 @@ Context::Context(const Context& context) { Context::~Context() { } +void Context::setFrameHandler(FrameHandler handler) { + _frameHandler = handler; +} + +#define DEFERRED_RENDERING + +void Context::beginFrame(const FramebufferPointer& outputFramebuffer, const glm::mat4& renderPose) { + _currentFrame = Frame(); + _currentFrame.framebuffer = outputFramebuffer; + _currentFrame.pose = renderPose; + _frameActive = true; +} + +void Context::append(Batch& batch) { + if (!_frameActive) { + qWarning() << "Batch executed outside of frame boundaries"; + } +#ifdef DEFERRED_RENDERING + _currentFrame.batches.emplace_back(batch); + _currentFrame.stereoStates.emplace_back(_stereo); +#else + _backend->_stereo = _stereo; + _backend->render(batch); +#endif +} + +void Context::endFrame() { +#ifdef DEFERRED_RENDERING + if (_frameHandler) { + _frameHandler(_currentFrame); + } +#endif + _currentFrame = Frame(); + _frameActive = false; +} + + bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { if (shader.isProgram() && _makeProgramCallback) { return _makeProgramCallback(shader, bindings); @@ -35,36 +79,38 @@ bool Context::makeProgram(Shader& shader, const Shader::BindingSet& bindings) { return false; } -void Context::render(Batch& batch) { - PROFILE_RANGE(__FUNCTION__); - _backend->render(batch); -} - void Context::enableStereo(bool enable) { - _backend->enableStereo(enable); + _stereo._enable = enable; } bool Context::isStereo() { - return _backend->isStereo(); + return _stereo._enable; } void Context::setStereoProjections(const mat4 eyeProjections[2]) { - _backend->setStereoProjections(eyeProjections); + for (int i = 0; i < 2; ++i) { + _stereo._eyeProjections[i] = eyeProjections[i]; + } } -void Context::setStereoViews(const mat4 eyeViews[2]) { - _backend->setStereoViews(eyeViews); +void Context::setStereoViews(const mat4 views[2]) { + for (int i = 0; i < 2; ++i) { + _stereo._eyeViews[i] = views[i]; + } } void Context::getStereoProjections(mat4* eyeProjections) const { - _backend->getStereoProjections(eyeProjections); + for (int i = 0; i < 2; ++i) { + eyeProjections[i] = _stereo._eyeProjections[i]; + } } void Context::getStereoViews(mat4* eyeViews) const { - _backend->getStereoViews(eyeViews); + for (int i = 0; i < 2; ++i) { + eyeViews[i] = _stereo._eyeViews[i]; + } } - void Context::syncCache() { PROFILE_RANGE(__FUNCTION__); _backend->syncCache(); @@ -103,12 +149,12 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S if (!_stereo._skybox) { offsetTransform.postTranslate(-Vec3(_stereo._eyeViews[eye][3])); } else { - // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future + // FIXME: If "skybox" the ipd is set to 0 for now, let s try to propose a better solution for this in the future } result._projection = _stereo._eyeProjections[eye]; result.recomputeDerived(offsetTransform); - result._stereoInfo = Vec4(1.0f, (float) eye, 0.0f, 0.0f); + result._stereoInfo = Vec4(1.0f, (float)eye, 0.0f, 0.0f); return result; } @@ -125,7 +171,7 @@ std::atomic Context::_textureGPUTransferCount{ 0 }; void Context::incrementBufferGPUCount() { _bufferGPUCount++; } -void Context::decrementBufferGPUCount() { +void Context::decrementBufferGPUCount() { _bufferGPUCount--; } void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 2d0baa0497..5f894318f2 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -16,12 +16,13 @@ #include +#include "Forward.h" #include "Batch.h" - #include "Resource.h" #include "Texture.h" #include "Pipeline.h" #include "Framebuffer.h" +#include "Frame.h" class QImage; @@ -46,51 +47,11 @@ public: ContextStats(const ContextStats& stats) = default; }; -struct StereoState { - bool _enable{ false }; - bool _skybox{ false }; - // 0 for left eye, 1 for right eye - uint8_t _pass{ 0 }; - mat4 _eyeViews[2]; - mat4 _eyeProjections[2]; -}; - class Backend { public: virtual~ Backend() {}; virtual void render(Batch& batch) = 0; - virtual void enableStereo(bool enable) { - _stereo._enable = enable; - } - - virtual bool isStereo() { - return _stereo._enable; - } - - void setStereoProjections(const mat4 eyeProjections[2]) { - for (int i = 0; i < 2; ++i) { - _stereo._eyeProjections[i] = eyeProjections[i]; - } - } - - void setStereoViews(const mat4 views[2]) { - for (int i = 0; i < 2; ++i) { - _stereo._eyeViews[i] = views[i]; - } - } - - void getStereoProjections(mat4* eyeProjections) const { - for (int i = 0; i < 2; ++i) { - eyeProjections[i] = _stereo._eyeProjections[i]; - } - } - - void getStereoViews(mat4* eyeViews) const { - for (int i = 0; i < 2; ++i) { - eyeViews[i] = _stereo._eyeViews[i]; - } - } virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; @@ -137,8 +98,25 @@ public: static void decrementTextureGPUTransferCount(); protected: - StereoState _stereo; + virtual bool isStereo() { + return _stereo._enable; + } + + void getStereoProjections(mat4* eyeProjections) const { + for (int i = 0; i < 2; ++i) { + eyeProjections[i] = _stereo._eyeProjections[i]; + } + } + + void getStereoViews(mat4* eyeViews) const { + for (int i = 0; i < 2; ++i) { + eyeViews[i] = _stereo._eyeViews[i]; + } + } + + friend class Context; ContextStats _stats; + StereoState _stereo; }; class Context { @@ -161,7 +139,10 @@ public: Context(); ~Context(); - void render(Batch& batch); + void setFrameHandler(FrameHandler handler); + void beginFrame(const FramebufferPointer& outputFramebuffer, const glm::mat4& renderPose = glm::mat4()); + void append(Batch& batch); + void endFrame(); void enableStereo(bool enable = true); bool isStereo(); @@ -191,6 +172,10 @@ protected: Context(const Context& context); std::unique_ptr _backend; + bool _frameActive { false }; + Frame _currentFrame; + FrameHandler _frameHandler; + StereoState _stereo; // This function can only be called by "static Shader::makeProgram()" // makeProgramShader(...) make a program shader ready to be used in a Batch. @@ -234,7 +219,7 @@ template void doInBatch(std::shared_ptr context, F f) { gpu::Batch batch; f(batch); - context->render(batch); + context->append(batch); } }; diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index e2a4ad38dd..3b04b17d87 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -86,6 +86,15 @@ namespace gpu { class TextureView; using TextureViews = std::vector; + struct StereoState { + bool _enable{ false }; + bool _skybox{ false }; + // 0 for left eye, 1 for right eye + uint8 _pass{ 0 }; + Mat4 _eyeViews[2]; + Mat4 _eyeProjections[2]; + }; + namespace gl { class GLBuffer; } diff --git a/libraries/gpu/src/gpu/Frame.h b/libraries/gpu/src/gpu/Frame.h index 99296cc91e..ed5e2ea179 100644 --- a/libraries/gpu/src/gpu/Frame.h +++ b/libraries/gpu/src/gpu/Frame.h @@ -18,6 +18,7 @@ public: glm::mat4 pose; /// The collection of batches which make up the frame std::vector batches; + std::vector stereoStates; /// The destination framebuffer in which the results will be placed FramebufferPointer framebuffer; }; From 54a7265be8ee66b3a4f0a849ccb70c9ef7fb8edd Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 16:32:56 -0700 Subject: [PATCH 27/39] Removing empty file, because jenkins --- libraries/gpu/src/gpu/Frame.cpp | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 libraries/gpu/src/gpu/Frame.cpp diff --git a/libraries/gpu/src/gpu/Frame.cpp b/libraries/gpu/src/gpu/Frame.cpp deleted file mode 100644 index d36c7f5537..0000000000 --- a/libraries/gpu/src/gpu/Frame.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by Bradley Austin Davis on 2016/07/26 -// Copyright 2013-2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "Frame.h" - -using namespace gpu; From 5bbcbbb811985e1bfba7bd054f95ec72f82f1739 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 26 Jul 2016 17:06:44 -0700 Subject: [PATCH 28/39] Update render perf tool to use the new API --- tests/render-perf/src/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index ace637e92a..22dd96b83b 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -403,7 +403,12 @@ private: renderArgs._blitFramebuffer = finalFramebuffer; } + _gpuContext->beginFrame(renderArgs._blitFramebuffer); + gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) { + batch.resetStages(); + }); render(&renderArgs); + _gpuContext->endFrame(); GLuint glTex; { auto gpuTex = renderArgs._blitFramebuffer->getRenderBuffer(0); @@ -428,9 +433,6 @@ private: _offscreenContext->makeCurrent(); framebufferCache->releaseFramebuffer(renderArgs._blitFramebuffer); renderArgs._blitFramebuffer.reset(); - gpu::doInBatch(renderArgs._context, [&](gpu::Batch& batch) { - batch.resetStages(); - }); _fpsCounter.increment(); static size_t _frameCount { 0 }; ++_frameCount; From 0f7f9990c2d70b59414c60d5eff28e7cc4d8def2 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Wed, 27 Jul 2016 17:58:24 -0700 Subject: [PATCH 29/39] Tuned haptic pulses for grab, release, equip, de-quip --- .../system/controllers/handControllerGrab.js | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index bfdb26a2bb..5815e8129f 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -38,6 +38,15 @@ var BUMPER_ON_VALUE = 0.5; var THUMB_ON_VALUE = 0.5; +var HAPTIC_PULSE_STRENGTH = 1.0; +var HAPTIC_PULSE_DURATION = 13.0; +var HAPTIC_TEXTURE_STRENGTH = 0.1; +var HAPTIC_TEXTURE_DURATION = 3.0; +var HAPTIC_TEXTURE_DISTANCE = 0.002; +var HAPTIC_DEQUIP_STRENGTH = 0.75; +var HAPTIC_DEQUIP_DURATION = 50.0; + + var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move. var PICK_WITH_HAND_RAY = true; @@ -934,7 +943,7 @@ function MyController(hand) { entityPropertiesCache.addEntities(candidateEntities); var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities); if (!this.waitForTriggerRelease) { - this.updateEquipHaptics(potentialEquipHotspot); + this.updateEquipHaptics(potentialEquipHotspot, this.getHandPosition()); } var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS); @@ -948,11 +957,15 @@ function MyController(hand) { this.prevPotentialEquipHotspot = null; }; - this.updateEquipHaptics = function(potentialEquipHotspot) { + this.updateEquipHaptics = function(potentialEquipHotspot, currentLocation) { if (potentialEquipHotspot && !this.prevPotentialEquipHotspot || !potentialEquipHotspot && this.prevPotentialEquipHotspot) { - Controller.triggerShortHapticPulse(0.5, this.hand); - } + Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand); + this.lastHapticPulseLocation = currentLocation; + } else if (potentialEquipHotspot && Vec3.distance(this.lastHapticPulseLocation, currentLocation) > HAPTIC_TEXTURE_DISTANCE) { + Controller.triggerHapticPulse(HAPTIC_TEXTURE_STRENGTH, HAPTIC_TEXTURE_DURATION, this.hand); + this.lastHapticPulseLocation = currentLocation; + } this.prevPotentialEquipHotspot = potentialEquipHotspot; }; @@ -1337,7 +1350,7 @@ function MyController(hand) { } } - this.updateEquipHaptics(potentialEquipHotspot); + this.updateEquipHaptics(potentialEquipHotspot, handPosition); var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS); equipHotspotBuddy.updateHotspots(nearEquipHotspots, timestamp); @@ -1422,6 +1435,8 @@ function MyController(hand) { this.callEntityMethodOnGrabbed("startDistanceGrab"); } + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + this.turnOffVisualizations(); this.previousRoomControllerPosition = roomControllerPosition; @@ -1611,7 +1626,7 @@ function MyController(hand) { if (handIsUpsideDown != this.prevHandIsUpsideDown) { this.prevHandIsUpsideDown = handIsUpsideDown; - Controller.triggerShortHapticPulse(0.5, this.hand); + Controller.triggerHapticPulse(HAPTIC_DEQUIP_STRENGTH, HAPTIC_DEQUIP_DURATION, this.hand); } return handIsUpsideDown; @@ -1625,7 +1640,7 @@ function MyController(hand) { this.dropGestureReset(); this.clearEquipHaptics(); - Controller.triggerShortHapticPulse(1.0, this.hand); + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); if (this.entityActivated) { var saveGrabbedID = this.grabbedEntity; @@ -1987,6 +2002,8 @@ function MyController(hand) { joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + this.grabbedEntity = null; this.grabbedHotspot = null; From 3e0ef7d43a0b8b8e563a66f80094055b20ffba4d Mon Sep 17 00:00:00 2001 From: humbletim Date: Fri, 22 Jul 2016 11:54:02 -0400 Subject: [PATCH 30/39] make Assets.getMapping(path) actually return the mapping --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index f1198c9d5b..5a81fe8749 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -62,8 +62,10 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto request = assetClient->createGetMappingRequest(path); connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { + auto hash = request->getHash(); + if (callback.isCallable()) { - QJSValueList args { request->getErrorString() }; + QJSValueList args { request->getErrorString(), hash }; callback.call(args); } From f37570dc9ac574db3cb28565abbbc482915e094c Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Thu, 28 Jul 2016 08:23:45 -0700 Subject: [PATCH 31/39] only pulse on release when held --- scripts/system/controllers/handControllerGrab.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 5815e8129f..bd618c5a44 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1965,6 +1965,9 @@ function MyController(hand) { var noVelocity = false; if (this.grabbedEntity !== null) { + // Make a small release haptic pulse if we really were holding something + Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); + // If this looks like the release after adjusting something still held in the other hand, print the position // and rotation of the held thing to help content creators set the userData. var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {}); @@ -2002,8 +2005,6 @@ function MyController(hand) { joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); - Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); - this.grabbedEntity = null; this.grabbedHotspot = null; From 516780934230e1d9ec4914b1e4ad2f607873cf15 Mon Sep 17 00:00:00 2001 From: Eric Levin Date: Thu, 28 Jul 2016 08:51:11 -0700 Subject: [PATCH 32/39] release near and far grab at trigger click detent --- scripts/system/controllers/handControllerGrab.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index bd618c5a44..c023278a3b 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1443,7 +1443,8 @@ function MyController(hand) { }; this.distanceHolding = function(deltaTime, timestamp) { - if (this.triggerSmoothedReleased()) { + + if (!this.triggerClicked) { this.callEntityMethodOnGrabbed("releaseGrab"); this.setState(STATE_OFF, "trigger released"); return; @@ -1761,7 +1762,7 @@ function MyController(hand) { this.nearGrabbing = function(deltaTime, timestamp) { - if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { + if (this.state == STATE_NEAR_GRABBING && !this.triggerClicked) { this.callEntityMethodOnGrabbed("releaseGrab"); this.setState(STATE_OFF, "trigger released"); return; From 755989b8ffe1d3afe8683d552f5f89d47ca973d5 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 28 Jul 2016 10:01:05 -0700 Subject: [PATCH 33/39] don't allow punished scripts to slow stop or shutdown --- libraries/script-engine/src/ScriptEngine.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 21eae99307..cb82974f4f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -845,14 +845,24 @@ void ScriptEngine::run() { // it means our script is taking too long in it's updates, and we want to punish the // script a little bit. So we will force the sleepUntil to be at least our averageUpdate // time into the future. - auto wouldSleep = (sleepUntil - clock::now()); + auto wouldSleep = (sleepUntil - beforeSleep); auto avgerageUpdate = totalUpdates / thisFrame; if (wouldSleep < avgerageUpdate) { sleepUntil = beforeSleep + avgerageUpdate; } - std::this_thread::sleep_until(sleepUntil); + // We don't want to actually sleep for too long, because it causes our scripts to hang + // on shutdown and stop... so we want to loop and sleep until we've spent our time in + // purgatory, constantly checking to see if our script was asked to end + while (!_isFinished && clock::now() < sleepUntil) { + auto wouldSleepSlice = (sleepUntil - clock::now()); + auto thisSleepUntil = sleepUntil; + if (wouldSleepSlice > FRAME_DURATION) { + thisSleepUntil = clock::now() + FRAME_DURATION; + } + std::this_thread::sleep_until(thisSleepUntil); + } #ifdef SCRIPT_DELAY_DEBUG { From 6b8e912114deae537794700816f72955b2bf9b8b Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Thu, 28 Jul 2016 10:02:19 -0700 Subject: [PATCH 34/39] Fix for mac and linux builds --- libraries/render-utils/src/GeometryCache.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 3d987939d4..ce4277b141 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -158,9 +158,8 @@ public: gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true, bool unlit = false, bool depthBias = false); - void bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(gpu::Batch& batch); - gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline(); + gpu::PipelinePointer getSimpleSRGBTexturedUnlitNoDstAlphaPipeline(); render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; } render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; } From 22619a66bad13b3aca9c3c03332036283f26194c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 28 Jul 2016 10:51:17 -0700 Subject: [PATCH 35/39] process events also --- libraries/script-engine/src/ScriptEngine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cb82974f4f..2dea38cfae 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -855,13 +855,18 @@ void ScriptEngine::run() { // We don't want to actually sleep for too long, because it causes our scripts to hang // on shutdown and stop... so we want to loop and sleep until we've spent our time in // purgatory, constantly checking to see if our script was asked to end + bool firstTime = true; while (!_isFinished && clock::now() < sleepUntil) { + if (!firstTime) { + QCoreApplication::processEvents(); // before we sleep again, give events a chance to process + } auto wouldSleepSlice = (sleepUntil - clock::now()); auto thisSleepUntil = sleepUntil; if (wouldSleepSlice > FRAME_DURATION) { thisSleepUntil = clock::now() + FRAME_DURATION; } std::this_thread::sleep_until(thisSleepUntil); + firstTime = false; } #ifdef SCRIPT_DELAY_DEBUG From ea310bcc43dc5edce629fd8d5dde629f59e1076a Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Thu, 28 Jul 2016 14:11:19 -0700 Subject: [PATCH 36/39] Web Entities now render correctly as well --- interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 6 +++--- libraries/render-utils/src/GeometryCache.cpp | 18 +++++++++--------- libraries/render-utils/src/GeometryCache.h | 8 ++++---- ...imple_srgb_textured_unlit_no_tex_alpha.slf} | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) rename libraries/render-utils/src/{simple_srgb_textured_unlit_no_dst_alpha.slf => simple_srgb_textured_unlit_no_tex_alpha.slf} (94%) diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index b224b3a047..1c84e71fa7 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -101,7 +101,7 @@ void Web3DOverlay::render(RenderArgs* args) { batch.setModelTransform(transform); auto geometryCache = DependencyManager::get(); - geometryCache->bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(batch); + geometryCache->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch); geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 8298dbcec5..6fa3a319d7 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -208,9 +208,9 @@ void RenderableWebEntityItem::render(RenderArgs* args) { batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); textured = emissive = true; } - - DependencyManager::get()->bindSimpleProgram(batch, textured, culled, emissive); - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, 0.0f)); + + DependencyManager::get()->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch); + DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } void RenderableWebEntityItem::setSourceUrl(const QString& value) { diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 7ec2a84cf9..1251c3b5b5 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -35,7 +35,7 @@ #include "simple_vert.h" #include "simple_textured_frag.h" #include "simple_textured_unlit_frag.h" -#include "simple_srgb_textured_unlit_no_dst_alpha_frag.h" +#include "simple_srgb_textured_unlit_no_tex_alpha_frag.h" #include "glowLine_vert.h" #include "glowLine_geom.h" #include "glowLine_frag.h" @@ -1749,25 +1749,25 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } -void GeometryCache::bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(gpu::Batch& batch) { - batch.setPipeline(getSimpleSRGBTexturedUnlitNoDstAlphaPipeline()); +void GeometryCache::bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(gpu::Batch& batch) { + batch.setPipeline(getSimpleSRGBTexturedUnlitNoTexAlphaPipeline()); // Set a default normal map batch.setResourceTexture(render::ShapePipeline::Slot::MAP::NORMAL_FITTING, DependencyManager::get()->getNormalFittingTexture()); } -gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline() { +gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoTexAlphaPipeline() { // Compile the shaders, once static std::once_flag once; std::call_once(once, [&]() { auto VS = gpu::Shader::createVertex(std::string(simple_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_srgb_textured_unlit_no_dst_alpha_frag)); + auto PS = gpu::Shader::createPixel(std::string(simple_srgb_textured_unlit_no_tex_alpha_frag)); - _simpleSRGBTexturedUnlitNoDstAlphaShader = gpu::Shader::createProgram(VS, PS); + _simpleSRGBTexturedUnlitNoTexAlphaShader = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING)); - gpu::Shader::makeProgram(*_simpleSRGBTexturedUnlitNoDstAlphaShader, slotBindings); + gpu::Shader::makeProgram(*_simpleSRGBTexturedUnlitNoTexAlphaShader, slotBindings); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_NONE); state->setDepthTest(true, true, gpu::LESS_EQUAL); @@ -1775,10 +1775,10 @@ gpu::PipelinePointer GeometryCache::getSimpleSRGBTexturedUnlitNoDstAlphaPipeline gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _simpleSRGBTexturedUnlitNoDstAlphaPipeline = gpu::Pipeline::create(_simpleSRGBTexturedUnlitNoDstAlphaShader, state); + _simpleSRGBTexturedUnlitNoTexAlphaPipeline = gpu::Pipeline::create(_simpleSRGBTexturedUnlitNoTexAlphaShader, state); }); - return _simpleSRGBTexturedUnlitNoDstAlphaPipeline; + return _simpleSRGBTexturedUnlitNoTexAlphaPipeline; } void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool unlit, bool depthBiased) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index ce4277b141..e28e76a766 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -158,8 +158,8 @@ public: gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true, bool unlit = false, bool depthBias = false); - void bindSimpleSRGBTexturedUnlitNoDstAlphaProgram(gpu::Batch& batch); - gpu::PipelinePointer getSimpleSRGBTexturedUnlitNoDstAlphaPipeline(); + void bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(gpu::Batch& batch); + gpu::PipelinePointer getSimpleSRGBTexturedUnlitNoTexAlphaPipeline(); render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; } render::ShapePipelinePointer getWireShapePipeline() { return GeometryCache::_simpleWirePipeline; } @@ -421,8 +421,8 @@ private: gpu::PipelinePointer _glowLinePipeline; QHash _simplePrograms; - gpu::ShaderPointer _simpleSRGBTexturedUnlitNoDstAlphaShader; - gpu::PipelinePointer _simpleSRGBTexturedUnlitNoDstAlphaPipeline; + gpu::ShaderPointer _simpleSRGBTexturedUnlitNoTexAlphaShader; + gpu::PipelinePointer _simpleSRGBTexturedUnlitNoTexAlphaPipeline; }; diff --git a/libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf b/libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf similarity index 94% rename from libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf rename to libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf index e2109973db..bab18b970b 100644 --- a/libraries/render-utils/src/simple_srgb_textured_unlit_no_dst_alpha.slf +++ b/libraries/render-utils/src/simple_srgb_textured_unlit_no_tex_alpha.slf @@ -2,7 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple.frag +// simple_srgb_texture_unlit_no_tex_alpha.frag // fragment shader // // Created by Anthony Thibault on 7/25/16. From 74a3835a1e3d4639ab7fadaf5dd1c19e7c569932 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 28 Jul 2016 15:15:33 -0700 Subject: [PATCH 37/39] CR feedback --- libraries/script-engine/src/ScriptEngine.cpp | 24 +++++--------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2dea38cfae..f98b07478b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -839,34 +839,22 @@ void ScriptEngine::run() { // calculate a sleepUntil to be the time from our start time until the original target // sleepUntil for this frame. const std::chrono::microseconds FRAME_DURATION(USECS_PER_SECOND / SCRIPT_FPS + 1); - clock::time_point sleepUntil(startTime + thisFrame++ * FRAME_DURATION); + clock::time_point targetSleepUntil(startTime + thisFrame++ * FRAME_DURATION); // However, if our sleepUntil is not at least our average update time into the future // it means our script is taking too long in it's updates, and we want to punish the // script a little bit. So we will force the sleepUntil to be at least our averageUpdate // time into the future. - auto wouldSleep = (sleepUntil - beforeSleep); - auto avgerageUpdate = totalUpdates / thisFrame; - - if (wouldSleep < avgerageUpdate) { - sleepUntil = beforeSleep + avgerageUpdate; - } + auto averageUpdate = totalUpdates / thisFrame; + auto sleepUntil = std::max(targetSleepUntil, beforeSleep + averageUpdate); // We don't want to actually sleep for too long, because it causes our scripts to hang // on shutdown and stop... so we want to loop and sleep until we've spent our time in // purgatory, constantly checking to see if our script was asked to end - bool firstTime = true; while (!_isFinished && clock::now() < sleepUntil) { - if (!firstTime) { - QCoreApplication::processEvents(); // before we sleep again, give events a chance to process - } - auto wouldSleepSlice = (sleepUntil - clock::now()); - auto thisSleepUntil = sleepUntil; - if (wouldSleepSlice > FRAME_DURATION) { - thisSleepUntil = clock::now() + FRAME_DURATION; - } + QCoreApplication::processEvents(); // before we sleep again, give events a chance to process + auto thisSleepUntil = std::min(sleepUntil, clock::now() + FRAME_DURATION); std::this_thread::sleep_until(thisSleepUntil); - firstTime = false; } #ifdef SCRIPT_DELAY_DEBUG @@ -880,7 +868,7 @@ void ScriptEngine::run() { qCDebug(scriptengine) << "Frame:" << thisFrame << "Slept (us):" << std::chrono::duration_cast(actuallySleptUntil - beforeSleep).count() << - "Avg Updates (us):" << avgerageUpdate.count() << + "Avg Updates (us):" << averageUpdate.count() << "FPS:" << fps; } } From e879f22c952772658276153fb3bd8690affe31fe Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 28 Jul 2016 15:15:52 -0700 Subject: [PATCH 38/39] fix behavior with no entity server --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e294ae38ad..5d50a1c9fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4685,7 +4685,8 @@ void Application::packetSent(quint64 length) { void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) { scriptEngine->setEmitScriptUpdatesFunction([this]() { - return isPhysicsEnabled(); + SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer); + return !entityServerNode || isPhysicsEnabled(); }); // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so From 8e3bc97ef9323a5e9e19d5960fa92897feafa5a3 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Fri, 29 Jul 2016 08:10:10 -0700 Subject: [PATCH 39/39] fix for unused variable warnings --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 6fa3a319d7..82c142db37 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -203,10 +203,8 @@ void RenderableWebEntityItem::render(RenderArgs* args) { if (!success) { return; } - bool textured = false, culled = false, emissive = false; if (_texture) { batch._glActiveBindTexture(GL_TEXTURE0, GL_TEXTURE_2D, _texture); - textured = emissive = true; } DependencyManager::get()->bindSimpleSRGBTexturedUnlitNoTexAlphaProgram(batch);