diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 93ccbc0b8c..56f761e42d 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -82,6 +82,12 @@ ModalWindow { // Clear selection when click on external frame. frameClicked.connect(function() { d.clearSelection(); }); + + if (selectDirectory) { + currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder)); + } + + fileTableView.forceActiveFocus(); } Item { @@ -703,7 +709,6 @@ ModalWindow { if (!helper.urlIsWritable(selection)) { desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, - buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, text: "Unable to write to location " + selection }) return; diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 9a19889938..2cf50891c9 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -65,7 +65,10 @@ Preference { verticalCenter: dataTextField.verticalCenter } onClicked: { - var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) }); + var browser = fileBrowserBuilder.createObject(desktop, { + selectDirectory: true, + dir: fileDialogHelper.pathToUrl(preference.value) + }); browser.selectedFile.connect(function(fileUrl){ console.log(fileUrl); dataTextField.text = fileDialogHelper.urlToPath(fileUrl); diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml index b10b66f07c..b509f0ce3a 100644 --- a/interface/resources/qml/hifi/overlays/ImageOverlay.qml +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -1,5 +1,6 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 +import QtGraphicalEffects 1.0 import "." @@ -44,6 +45,12 @@ Overlay { } } + ColorOverlay { + id: color + anchors.fill: image + source: image + } + function updateSubImage(subImage) { var keys = Object.keys(subImage); for (var i = 0; i < keys.length; ++i) { @@ -70,6 +77,7 @@ Overlay { case "alpha": root.opacity = value; break; case "imageURL": image.source = value; break; case "subImage": updateSubImage(value); break; + case "color": color.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, root.opacity); break; default: console.log("OVERLAY Unhandled image property " + key); } } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index f46a906af8..39bb7eac17 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -239,11 +239,13 @@ void Avatar::updateAvatarEntities() { } AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs(); - foreach (auto entityID, recentlyDettachedAvatarEntities) { - if (!_avatarEntityData.contains(entityID)) { - entityTree->deleteEntity(entityID, true, true); + _avatarEntitiesLock.withReadLock([&] { + foreach (auto entityID, recentlyDettachedAvatarEntities) { + if (!_avatarEntityData.contains(entityID)) { + entityTree->deleteEntity(entityID, true, true); + } } - } + }); }); if (success) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index fa8db02658..be5bf7722f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -709,12 +709,14 @@ void MyAvatar::saveData() { settings.beginWriteArray("avatarEntityData"); int avatarEntityIndex = 0; - for (auto entityID : _avatarEntityData.keys()) { - settings.setArrayIndex(avatarEntityIndex); - settings.setValue("id", entityID); - settings.setValue("properties", _avatarEntityData.value(entityID)); - avatarEntityIndex++; - } + _avatarEntitiesLock.withReadLock([&] { + for (auto entityID : _avatarEntityData.keys()) { + settings.setArrayIndex(avatarEntityIndex); + settings.setValue("id", entityID); + settings.setValue("properties", _avatarEntityData.value(entityID)); + avatarEntityIndex++; + } + }); settings.endArray(); settings.setValue("displayName", _displayName); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 0443c65453..f0ae221566 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "Application.h" #include "DomainHandler.h" #include "MainWindow.h" @@ -23,6 +25,10 @@ #include "WindowScriptingInterface.h" +static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); +static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation"; + + WindowScriptingInterface::WindowScriptingInterface() { const DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged); @@ -101,6 +107,14 @@ QString fixupPathForMac(const QString& directory) { return path; } +QString WindowScriptingInterface::getPreviousBrowseLocation() const { + return Setting::Handle(LAST_BROWSE_LOCATION_SETTING, DESKTOP_LOCATION).get(); +} + +void WindowScriptingInterface::setPreviousBrowseLocation(const QString& location) { + Setting::Handle(LAST_BROWSE_LOCATION_SETTING).set(location); +} + /// Display an open file dialog. If `directory` is an invalid file or directory the browser will start at the current /// working directory. /// \param const QString& title title of the window @@ -108,8 +122,17 @@ QString fixupPathForMac(const QString& directory) { /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` QScriptValue WindowScriptingInterface::browse(const QString& title, const QString& directory, const QString& nameFilter) { - QString path = fixupPathForMac(directory); + QString path = directory; + if (path.isEmpty()) { + path = getPreviousBrowseLocation(); + } +#ifndef Q_OS_WIN + path = fixupPathForMac(directory); +#endif QString result = OffscreenUi::getOpenFileName(nullptr, title, path, nameFilter); + if (!result.isEmpty()) { + setPreviousBrowseLocation(QFileInfo(result).absolutePath()); + } return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); } @@ -120,8 +143,17 @@ QScriptValue WindowScriptingInterface::browse(const QString& title, const QStrin /// \param const QString& nameFilter filter to filter filenames by - see `QFileDialog` /// \return QScriptValue file path as a string if one was selected, otherwise `QScriptValue::NullValue` QScriptValue WindowScriptingInterface::save(const QString& title, const QString& directory, const QString& nameFilter) { - QString path = fixupPathForMac(directory); + QString path = directory; + if (path.isEmpty()) { + path = getPreviousBrowseLocation(); + } +#ifndef Q_OS_WIN + path = fixupPathForMac(directory); +#endif QString result = OffscreenUi::getSaveFileName(nullptr, title, path, nameFilter); + if (!result.isEmpty()) { + setPreviousBrowseLocation(QFileInfo(result).absolutePath()); + } return result.isEmpty() ? QScriptValue::NullValue : QScriptValue(result); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index dfe02a5064..b92114c1bf 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -49,6 +49,10 @@ signals: private slots: WebWindowClass* doCreateWebWindow(const QString& title, const QString& url, int width, int height); + +private: + QString getPreviousBrowseLocation() const; + void setPreviousBrowseLocation(const QString& location); }; #endif // hifi_WindowScriptingInterface_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ff7438bb17..6d99d6ad81 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -900,7 +900,11 @@ bool AvatarData::processAvatarIdentity(const Identity& identity) { hasIdentityChanged = true; } - if (identity.avatarEntityData != _avatarEntityData) { + bool avatarEntityDataChanged = false; + _avatarEntitiesLock.withReadLock([&] { + avatarEntityDataChanged = (identity.avatarEntityData != _avatarEntityData); + }); + if (avatarEntityDataChanged) { setAvatarEntityData(identity.avatarEntityData); hasIdentityChanged = true; } @@ -914,7 +918,9 @@ QByteArray AvatarData::identityByteArray() { QUrl emptyURL(""); const QUrl& urlToSend = _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL; - identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData; + _avatarEntitiesLock.withReadLock([&] { + identityStream << getSessionUUID() << urlToSend << _attachmentData << _displayName << _avatarEntityData; + }); return identityData; } @@ -1306,16 +1312,18 @@ QJsonObject AvatarData::toJson() const { root[JSON_AVATAR_ATTACHEMENTS] = attachmentsJson; } - if (!_avatarEntityData.empty()) { - QJsonArray avatarEntityJson; - for (auto entityID : _avatarEntityData.keys()) { - QVariantMap entityData; - entityData.insert("id", entityID); - entityData.insert("properties", _avatarEntityData.value(entityID)); - avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); + _avatarEntitiesLock.withReadLock([&] { + if (!_avatarEntityData.empty()) { + QJsonArray avatarEntityJson; + for (auto entityID : _avatarEntityData.keys()) { + QVariantMap entityData; + entityData.insert("id", entityID); + entityData.insert("properties", _avatarEntityData.value(entityID)); + avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); + } + root[JSON_AVATAR_ENTITIES] = avatarEntityJson; } - root[JSON_AVATAR_ENTITIES] = avatarEntityJson; - } + }); auto recordingBasis = getRecordingBasis(); bool success; @@ -1604,8 +1612,10 @@ void AvatarData::updateAvatarEntity(const QUuid& entityID, const QByteArray& ent QMetaObject::invokeMethod(this, "updateAvatarEntity", Q_ARG(const QUuid&, entityID), Q_ARG(QByteArray, entityData)); return; } - _avatarEntityData.insert(entityID, entityData); - _avatarEntityDataLocallyEdited = true; + _avatarEntitiesLock.withWriteLock([&] { + _avatarEntityData.insert(entityID, entityData); + _avatarEntityDataLocallyEdited = true; + }); } void AvatarData::clearAvatarEntity(const QUuid& entityID) { @@ -1613,18 +1623,25 @@ void AvatarData::clearAvatarEntity(const QUuid& entityID) { QMetaObject::invokeMethod(this, "clearAvatarEntity", Q_ARG(const QUuid&, entityID)); return; } - _avatarEntityData.remove(entityID); - _avatarEntityDataLocallyEdited = true; + + _avatarEntitiesLock.withWriteLock([&] { + _avatarEntityData.remove(entityID); + _avatarEntityDataLocallyEdited = true; + }); } AvatarEntityMap AvatarData::getAvatarEntityData() const { + AvatarEntityMap result; if (QThread::currentThread() != thread()) { - AvatarEntityMap result; QMetaObject::invokeMethod(const_cast(this), "getAvatarEntityData", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AvatarEntityMap, result)); return result; } - return _avatarEntityData; + + _avatarEntitiesLock.withReadLock([&] { + result = _avatarEntityData; + }); + return result; } void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { @@ -1632,29 +1649,33 @@ void AvatarData::setAvatarEntityData(const AvatarEntityMap& avatarEntityData) { QMetaObject::invokeMethod(this, "setAvatarEntityData", Q_ARG(const AvatarEntityMap&, avatarEntityData)); return; } - if (_avatarEntityData != avatarEntityData) { - // keep track of entities that were attached to this avatar but no longer are - AvatarEntityIDs previousAvatarEntityIDs = QSet::fromList(_avatarEntityData.keys()); + _avatarEntitiesLock.withWriteLock([&] { + if (_avatarEntityData != avatarEntityData) { + // keep track of entities that were attached to this avatar but no longer are + AvatarEntityIDs previousAvatarEntityIDs = QSet::fromList(_avatarEntityData.keys()); - _avatarEntityData = avatarEntityData; - setAvatarEntityDataChanged(true); + _avatarEntityData = avatarEntityData; + setAvatarEntityDataChanged(true); - foreach (auto entityID, previousAvatarEntityIDs) { - if (!_avatarEntityData.contains(entityID)) { - _avatarEntityDetached.insert(entityID); + foreach (auto entityID, previousAvatarEntityIDs) { + if (!_avatarEntityData.contains(entityID)) { + _avatarEntityDetached.insert(entityID); + } } } - } + }); } AvatarEntityIDs AvatarData::getAndClearRecentlyDetachedIDs() { + AvatarEntityIDs result; if (QThread::currentThread() != thread()) { - AvatarEntityIDs result; QMetaObject::invokeMethod(const_cast(this), "getRecentlyDetachedIDs", Qt::BlockingQueuedConnection, Q_RETURN_ARG(AvatarEntityIDs, result)); return result; } - AvatarEntityIDs result = _avatarEntityDetached; - _avatarEntityDetached.clear(); + _avatarEntitiesLock.withWriteLock([&] { + result = _avatarEntityDetached; + _avatarEntityDetached.clear(); + }); return result; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 61ee649273..2dd1079b49 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -418,6 +418,7 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; + mutable ReadWriteLockable _avatarEntitiesLock; AvatarEntityIDs _avatarEntityDetached; // recently detached from this avatar AvatarEntityMap _avatarEntityData; bool _avatarEntityDataLocallyEdited { false }; diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index bb90c04c95..0063f4a701 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME entities-renderer) -AUTOSCRIBE_SHADER_LIB(gpu model render render-utils) +AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) diff --git a/libraries/entities-renderer/src/RenderableProceduralItemShader.h b/libraries/entities-renderer/src/RenderableProceduralItemShader.h deleted file mode 100644 index 4762f619bf..0000000000 --- a/libraries/entities-renderer/src/RenderableProceduralItemShader.h +++ /dev/null @@ -1,380 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/09/05 -// Copyright 2013-2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// Shader includes portions of webgl-noise: -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - - -const QString SHADER_COMMON = R"SHADER( -layout(location = 0) out vec4 _fragColor0; -layout(location = 1) out vec4 _fragColor1; -layout(location = 2) out vec4 _fragColor2; - -// the alpha threshold -uniform float alphaThreshold; - -vec2 signNotZero(vec2 v) { - return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); -} - -vec2 float32x3_to_oct(in vec3 v) { - vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z))); - return ((v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p); -} - - -vec3 oct_to_float32x3(in vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - if (v.z < 0) { - v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy); - } - return normalize(v); -} - -vec3 snorm12x2_to_unorm8x3(vec2 f) { - vec2 u = vec2(round(clamp(f, -1.0, 1.0) * 2047.0 + 2047.0)); - float t = floor(u.y / 256.0); - - return floor(vec3( - u.x / 16.0, - fract(u.x / 16.0) * 256.0 + t, - u.y - t * 256.0 - )) / 255.0; -} - -vec2 unorm8x3_to_snorm12x2(vec3 u) { - u *= 255.0; - u.y *= (1.0 / 16.0); - vec2 s = vec2( u.x * 16.0 + floor(u.y), - fract(u.y) * (16.0 * 256.0) + u.z); - return clamp(s * (1.0 / 2047.0) - 1.0, vec2(-1.0), vec2(1.0)); -} - -float mod289(float x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec2 mod289(vec2 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -float permute(float x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec3 permute(vec3 x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec4 permute(vec4 x) { - return mod289(((x*34.0)+1.0)*x); -} - -float taylorInvSqrt(float r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 taylorInvSqrt(vec4 r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 grad4(float j, vec4 ip) { - const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); - vec4 p, s; - - p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; - p.w = 1.5 - dot(abs(p.xyz), ones.xyz); - s = vec4(lessThan(p, vec4(0.0))); - p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www; - - return p; -} - -// (sqrt(5) - 1)/4 = F4, used once below -#define F4 0.309016994374947451 - -float snoise(vec4 v) { - const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4 - 0.276393202250021, // 2 * G4 - 0.414589803375032, // 3 * G4 - -0.447213595499958); // -1 + 4 * G4 - - // First corner - vec4 i = floor(v + dot(v, vec4(F4))); - vec4 x0 = v - i + dot(i, C.xxxx); - - // Other corners - - // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) - vec4 i0; - vec3 isX = step(x0.yzw, x0.xxx); - vec3 isYZ = step(x0.zww, x0.yyz); - i0.x = isX.x + isX.y + isX.z; - i0.yzw = 1.0 - isX; - i0.y += isYZ.x + isYZ.y; - i0.zw += 1.0 - isYZ.xy; - i0.z += isYZ.z; - i0.w += 1.0 - isYZ.z; - - // i0 now contains the unique values 0,1,2,3 in each channel - vec4 i3 = clamp(i0, 0.0, 1.0); - vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0); - vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0); - - vec4 x1 = x0 - i1 + C.xxxx; - vec4 x2 = x0 - i2 + C.yyyy; - vec4 x3 = x0 - i3 + C.zzzz; - vec4 x4 = x0 + C.wwww; - - // Permutations - i = mod289(i); - float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x); - vec4 j1 = permute( - permute( - permute( - permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z - + vec4(i1.z, i2.z, i3.z, 1.0)) + i.y - + vec4(i1.y, i2.y, i3.y, 1.0)) + i.x - + vec4(i1.x, i2.x, i3.x, 1.0)); - - // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope - // 7*7*6 = 294, which is close to the ring size 17*17 = 289. - vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0); - - vec4 p0 = grad4(j0, ip); - vec4 p1 = grad4(j1.x, ip); - vec4 p2 = grad4(j1.y, ip); - vec4 p3 = grad4(j1.z, ip); - vec4 p4 = grad4(j1.w, ip); - - // Normalise gradients - vec4 norm = taylorInvSqrt( - vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - p4 *= taylorInvSqrt(dot(p4, p4)); - - // Mix contributions from the five corners - vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0); - vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0); - m0 = m0 * m0; - m1 = m1 * m1; - return 49.0 - * (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2))) - + dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4)))); - -} - -float snoise(vec3 v) { - const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - - // First corner - vec3 i = floor(v + dot(v, C.yyy)); - vec3 x0 = v - i + dot(i, C.xxx); - - // Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min(g.xyz, l.zxy); - vec3 i2 = max(g.xyz, l.zxy); - - vec3 x1 = x0 - i1 + C.xxx; - vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y - vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y - - // Permutations - i = mod289(i); - vec4 p = permute( - permute( - permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y - + vec4(0.0, i1.y, i2.y, 1.0)) + i.x - + vec4(0.0, i1.x, i2.x, 1.0)); - - // Gradients: 7x7 points over a square, mapped onto an octahedron. - // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) - float n_ = 0.142857142857; // 1.0/7.0 - vec3 ns = n_ * D.wyz - D.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_); // mod(j,N) - - vec4 x = x_ * ns.x + ns.yyyy; - vec4 y = y_ * ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4(x.xy, y.xy); - vec4 b1 = vec4(x.zw, y.zw); - - //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; - //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; - vec4 s0 = floor(b0) * 2.0 + 1.0; - vec4 s1 = floor(b1) * 2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; - vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; - - vec3 p0 = vec3(a0.xy, h.x); - vec3 p1 = vec3(a0.zw, h.y); - vec3 p2 = vec3(a1.xy, h.z); - vec3 p3 = vec3(a1.zw, h.w); - - //Normalise gradients - vec4 norm = taylorInvSqrt( - vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - - // Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), - 0.0); - m = m * m; - return 42.0 - * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); -} - -float snoise(vec2 v) { - const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); // 1.0 / 41.0 - // First corner - vec2 i = floor(v + dot(v, C.yy)); - vec2 x0 = v - i + dot(i, C.xx); - - // Other corners - vec2 i1; - i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); - vec4 x12 = x0.xyxy + C.xxzz; - x12.xy -= i1; - - // Permutations - i = mod289(i); // Avoid truncation effects in permutation - vec3 p = permute( - permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); - - vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), - 0.0); - m = m * m; - m = m * m; - - // Gradients: 41 points uniformly over a line, mapped onto a diamond. - // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) - - vec3 x = 2.0 * fract(p * C.www) - 1.0; - vec3 h = abs(x) - 0.5; - vec3 ox = floor(x + 0.5); - vec3 a0 = x - ox; - - // Normalise gradients implicitly by scaling m - // Approximation of: m *= inversesqrt( a0*a0 + h*h ); - m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h); - - // Compute final noise value at P - vec3 g; - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * x12.xz + h.yz * x12.yw; - return 130.0 * dot(m, g); -} - -// the interpolated normal -in vec3 _normal; -in vec3 _color; -in vec2 _texCoord0; -in vec4 _position; - -// TODO add more uniforms -uniform float iGlobalTime; // shader playback time (in seconds) -uniform vec3 iWorldScale; // the dimensions of the object being rendered - -// TODO add support for textures -// TODO document available inputs other than the uniforms -// TODO provide world scale in addition to the untransformed position - -const vec3 DEFAULT_SPECULAR = vec3(0.1); -const float DEFAULT_SHININESS = 10; - -)SHADER"; - -// V1 shaders, only support emissive -// vec4 getProceduralColor() -const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE( - -#line 1001 -%1 -#line 317 - -void main(void) { - vec4 emissive = getProceduralColor(); - - float alpha = emissive.a; - if (alpha != 1.0) { - discard; - } - - vec4 diffuse = vec4(_color.rgb, alpha); - vec4 normal = vec4(packNormal(normalize(_normal)), 0.5); - - _fragColor0 = diffuse; - _fragColor1 = normal; - _fragColor2 = vec4(emissive.rgb, DEFAULT_SHININESS / 128.0); -} - -)SCRIBE"; - -// void getProceduralDiffuseAndEmissive(out vec4 diffuse, out vec4 emissive) -const QString SHADER_TEMPLATE_V2 = SHADER_COMMON + R"SCRIBE( -// FIXME should we be doing the swizzle here? -vec3 iResolution = iWorldScale.xzy; - -// FIXME Mouse X,Y coordinates, and Z,W are for the click position if clicked (not supported in High Fidelity at the moment) -vec4 iMouse = vec4(0); - -// FIXME We set the seconds (iDate.w) of iDate to iGlobalTime, which contains the current date in seconds -vec4 iDate = vec4(0, 0, 0, iGlobalTime); - - -#line 1001 -%1 -#line 351 - -void main(void) { - vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; - - float emissiveAmount = getProceduralColors(diffuse, specular, shininess); - - _fragColor0 = vec4(diffuse.rgb, 1.0); - _fragColor1 = vec4(packNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0)); - _fragColor2 = vec4(specular, shininess / 128.0); -} -)SCRIBE"; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index c93ae252e3..ec07e10ccf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -98,7 +98,7 @@ void RenderableShapeEntityItem::render(RenderArgs* args) { } batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation if (_procedural->ready()) { - _procedural->prepare(batch, getPosition(), getDimensions()); + _procedural->prepare(batch, getPosition(), getDimensions(), getOrientation()); auto outColor = _procedural->getColor(color); batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); DependencyManager::get()->renderShape(batch, MAPPING[_shape]); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 893ae83cc5..a29ea8e2c8 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -261,7 +261,14 @@ void EntitySimulation::moveSimpleKinematics(const quint64& now) { SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin(); while (itemItr != _simpleKinematicEntities.end()) { EntityItemPointer entity = *itemItr; - if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo()) { + + // The entity-server doesn't know where avatars are, so don't attempt to do simple extrapolation for + // children of avatars. See related code in EntityMotionState::remoteSimulationOutOfSync. + bool ancestryIsKnown; + entity->getMaximumAACube(ancestryIsKnown); + bool hasAvatarAncestor = entity->hasAncestorOfType(NestableType::Avatar); + + if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo() && ancestryIsKnown && !hasAvatarAncestor) { entity->simulate(now); _entitiesToSort.insert(entity); ++itemItr; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 7b1133c2aa..4ba4ad5676 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -17,6 +17,7 @@ #include "EntityItem.h" #include "EntityItemProperties.h" #include "EntityTypes.h" +#include "EntitiesLogging.h" #include "LightEntityItem.h" #include "ModelEntityItem.h" @@ -63,6 +64,9 @@ EntityTypes::EntityType EntityTypes::getEntityTypeFromName(const QString& name) if (matchedTypeName != _nameToTypeMap.end()) { return matchedTypeName.value(); } + if (name.size() > 0 && name[0].isLower()) { + qCDebug(entities) << "Entity types must start with an uppercase letter. Please change the type" << name; + } return Unknown; } diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index dfac6dd516..398fdd04d6 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,5 +1,4 @@ set(TARGET_NAME gpu-gl) -AUTOSCRIBE_SHADER_LIB(gpu) setup_hifi_library() link_hifi_libraries(shared gl gpu) GroupSources("src") diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index ece1ee730c..e18b784018 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -114,6 +114,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_glUniform3fv), (&::gpu::gl::GLBackend::do_glUniform4fv), (&::gpu::gl::GLBackend::do_glUniform4iv), + (&::gpu::gl::GLBackend::do_glUniformMatrix3fv), (&::gpu::gl::GLBackend::do_glUniformMatrix4fv), (&::gpu::gl::GLBackend::do_glColor4f), @@ -515,6 +516,22 @@ void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) { (void)CHECK_GL_ERROR(); } +void GLBackend::do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) { + if (_pipeline._program == 0) { + // We should call updatePipeline() to bind the program but we are not doing that + // because these uniform setters are deprecated and we don;t want to create side effect + return; + } + updatePipeline(); + + glUniformMatrix3fv( + GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int), + batch._params[paramOffset + 2]._uint, + batch._params[paramOffset + 1]._uint, + (const GLfloat*)batch.editData(batch._params[paramOffset + 0]._uint)); + (void)CHECK_GL_ERROR(); +} + void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 610672f44f..5255a6cb25 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -136,6 +136,7 @@ public: virtual void do_glUniform3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniform4iv(Batch& batch, size_t paramOffset) final; + virtual void do_glUniformMatrix3fv(Batch& batch, size_t paramOffset) final; virtual void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) final; virtual void do_glColor4f(Batch& batch, size_t paramOffset) final; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 9126f11acf..6dc1d63ca8 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -567,6 +567,16 @@ void Batch::_glUniform4iv(int32 location, int count, const int32* value) { _params.push_back(location); } +void Batch::_glUniformMatrix3fv(int32 location, int count, uint8 transpose, const float* value) { + ADD_COMMAND(glUniformMatrix3fv); + + const int MATRIX3_SIZE = 9 * sizeof(float); + _params.push_back(cacheData(count * MATRIX3_SIZE, value)); + _params.push_back(transpose); + _params.push_back(count); + _params.push_back(location); +} + void Batch::_glUniformMatrix4fv(int32 location, int count, uint8 transpose, const float* value) { ADD_COMMAND(glUniformMatrix4fv); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index a2ee57759f..4e51038368 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -269,6 +270,7 @@ public: void _glUniform3fv(int location, int count, const float* value); void _glUniform4fv(int location, int count, const float* value); void _glUniform4iv(int location, int count, const int* value); + void _glUniformMatrix3fv(int location, int count, unsigned char transpose, const float* value); void _glUniformMatrix4fv(int location, int count, unsigned char transpose, const float* value); void _glUniform(int location, int v0) { @@ -291,6 +293,10 @@ public: _glUniform4f(location, v.x, v.y, v.z, v.w); } + void _glUniform(int location, const glm::mat3& v) { + _glUniformMatrix3fv(location, 1, false, glm::value_ptr(v)); + } + void _glColor4f(float red, float green, float blue, float alpha); enum Command { @@ -348,6 +354,7 @@ public: COMMAND_glUniform3fv, COMMAND_glUniform4fv, COMMAND_glUniform4iv, + COMMAND_glUniformMatrix3fv, COMMAND_glUniformMatrix4fv, COMMAND_glColor4f, @@ -446,7 +453,7 @@ public: Params _params; Bytes _data; - // SSBO class... layout MUST match the layout in TransformCamera.slh + // SSBO class... layout MUST match the layout in Transform.slh class TransformObject { public: Mat4 _model; diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index cead2c623d..652338f911 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -95,7 +95,7 @@ public: virtual void syncCache() = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - // UBO class... layout MUST match the layout in TransformCamera.slh + // UBO class... layout MUST match the layout in Transform.slh class TransformCamera { public: mutable Mat4 _view; diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 246167e186..20629c5f32 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -27,6 +27,10 @@ layout(std140) uniform transformCameraBuffer { TransformCamera getTransformCamera() { return _camera; } + +vec3 getEyeWorldPos() { + return _camera._viewInverse[3].xyz; +} <@endfunc@> diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index bac031885f..26b3801ec1 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -173,6 +173,7 @@ void AccountManager::setAuthURL(const QUrl& authURL) { << "from previous settings file"; } } + settings.endGroup(); if (_accountInfo.getAccessToken().token.isEmpty()) { qCWarning(networking) << "Unable to load account file. No existing account settings will be loaded."; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 6880b7a329..170669dede 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -97,7 +97,6 @@ void DomainHandler::softReset() { clearSettings(); - _domainConnectionRefusals.clear(); _connectionDenialsSinceKeypairRegen = 0; // cancel the failure timeout for any pending requests for settings @@ -118,6 +117,9 @@ void DomainHandler::hardReset() { _hostname = QString(); _sockAddr.clear(); + _hasSignalledProtocolMismatch = false; + _domainConnectionRefusals.clear(); + _hasCheckedForAccessToken = false; // clear any pending path we may have wanted to ask the previous DS about @@ -405,9 +407,25 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer(); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 1328174e87..3ab583d597 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -144,7 +144,8 @@ private: QString _pendingPath; QTimer _settingsTimer; - QStringList _domainConnectionRefusals; + QList _domainConnectionRefusals; + bool _hasSignalledProtocolMismatch { false }; bool _hasCheckedForAccessToken { false }; int _connectionDenialsSinceKeypairRegen { 0 }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 053bfcbd85..8f22c576f0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -85,10 +85,10 @@ void EntityMotionState::updateServerPhysicsVariables() { return; } - _serverPosition = _entity->getPosition(); - _serverRotation = _entity->getRotation(); - _serverVelocity = _entity->getVelocity(); - _serverAngularVelocity = _entity->getAngularVelocity(); + Transform localTransform; + _entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity); + _serverPosition = localTransform.getTranslation(); + _serverRotation = localTransform.getRotation(); _serverAcceleration = _entity->getAcceleration(); _serverActionData = _entity->getActionData(); } @@ -271,14 +271,25 @@ bool EntityMotionState::isCandidateForOwnership() const { bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // NOTE: we only get here if we think we own the simulation assert(_body); + + bool parentTransformSuccess; + Transform localToWorld = _entity->getParentTransform(parentTransformSuccess); + Transform worldToLocal; + Transform worldVelocityToLocal; + if (parentTransformSuccess) { + localToWorld.evalInverse(worldToLocal); + worldVelocityToLocal = worldToLocal; + worldVelocityToLocal.setTranslation(glm::vec3(0.0f)); + } + // if we've never checked before, our _lastStep will be 0, and we need to initialize our state if (_lastStep == 0) { btTransform xform = _body->getWorldTransform(); - _serverPosition = bulletToGLM(xform.getOrigin()); - _serverRotation = bulletToGLM(xform.getRotation()); - _serverVelocity = getBodyLinearVelocityGTSigma(); + _serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin())); + _serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation()); + _serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma()); _serverAcceleration = Vectors::ZERO; - _serverAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _serverAngularVelocity = worldVelocityToLocal.transform(bulletToGLM(_body->getAngularVelocity())); _lastStep = simulationStep; _serverActionData = _entity->getActionData(); _numInactiveUpdates = 1; @@ -315,11 +326,21 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { _lastStep = simulationStep; if (glm::length2(_serverVelocity) > 0.0f) { - _serverVelocity += _serverAcceleration * dt; - _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); - // NOTE: we ignore the second-order acceleration term when integrating - // the position forward because Bullet also does this. - _serverPosition += dt * _serverVelocity; + // the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of + // avatars. We are trying to guess what values the entity server has, so we don't do it here, either. See + // related code in EntitySimulation::moveSimpleKinematics. + bool ancestryIsKnown; + _entity->getMaximumAACube(ancestryIsKnown); + bool hasAvatarAncestor = _entity->hasAncestorOfType(NestableType::Avatar); + + if (ancestryIsKnown && !hasAvatarAncestor) { + _serverVelocity += _serverAcceleration * dt; + _serverVelocity *= powf(1.0f - _body->getLinearDamping(), dt); + + // NOTE: we ignore the second-order acceleration term when integrating + // the position forward because Bullet also does this. + _serverPosition += dt * _serverVelocity; + } } if (_entity->actionDataNeedsTransmit()) { @@ -341,7 +362,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { // compute position error btTransform worldTrans = _body->getWorldTransform(); - glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); + glm::vec3 position = worldToLocal.transform(bulletToGLM(worldTrans.getOrigin())); float dx2 = glm::distance2(position, _serverPosition); const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // corresponds to 2mm @@ -376,7 +397,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } } const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation - glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); + glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation()); #ifdef WANT_DEBUG if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) { @@ -481,11 +502,11 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } // remember properties for local server prediction - _serverPosition = _entity->getPosition(); - _serverRotation = _entity->getRotation(); - _serverVelocity = _entity->getVelocity(); + Transform localTransform; + _entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity); + _serverPosition = localTransform.getTranslation(); + _serverRotation = localTransform.getRotation(); _serverAcceleration = _entity->getAcceleration(); - _serverAngularVelocity = _entity->getAngularVelocity(); _serverActionData = _entity->getActionData(); EntityItemProperties properties; @@ -590,7 +611,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { if (_body && _entity) { dirtyFlags = _entity->getDirtyFlags(); - if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { + if (dirtyFlags & Simulation::DIRTY_SIMULATOR_ID) { // when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR) uint8_t entityCollisionMask = _entity->getCollisionless() ? 0 : _entity->getCollisionMask(); @@ -603,8 +624,12 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMovingRelativeToParent(); - if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || - (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { + + if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) // || + // TODO -- there is opportunity for an optimization here, but this currently causes + // excessive re-insertion of the rigid body. + // (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving) + ) { dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } } diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 781b508bc7..a9a297a2e1 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -19,7 +19,7 @@ #include #include -#include "ProceduralShaders.h" +#include "ProceduralCommon_frag.h" // Userdata parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; @@ -39,6 +39,7 @@ static const std::string STANDARD_UNIFORM_NAMES[Procedural::NUM_STANDARD_UNIFORM "iFrameCount", "iWorldScale", "iWorldPosition", + "iWorldOrientation", "iChannelResolution" }; @@ -202,9 +203,10 @@ bool Procedural::ready() { return true; } -void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size) { +void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation) { _entityDimensions = size; _entityPosition = position; + _entityOrientation = glm::mat3_cast(orientation); if (_shaderUrl.isLocalFile()) { auto lastModified = (quint64)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); if (lastModified > _shaderModified) { @@ -227,7 +229,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm std::string fragmentShaderSource = _fragmentSource; size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); if (replaceIndex != std::string::npos) { - fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), SHADER_COMMON); + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag); } replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); @@ -404,10 +406,10 @@ void Procedural::setupUniforms() { }); } - if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[SCALE]) { + if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[ORIENTATION]) { // FIXME move into the 'set once' section, since this doesn't change over time _uniforms.push_back([=](gpu::Batch& batch) { - batch._glUniform(_standardUniformSlots[SCALE], _entityDimensions); + batch._glUniform(_standardUniformSlots[ORIENTATION], _entityOrientation); }); } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index f928d0e594..6991b47946 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -38,7 +38,7 @@ public: void parse(const QString& userDataJson); bool ready(); - void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size); + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation); const gpu::ShaderPointer& getShader() const { return _shader; } glm::vec4 getColor(const glm::vec4& entityColor); @@ -56,6 +56,7 @@ public: FRAME_COUNT, SCALE, POSITION, + ORIENTATION, CHANNEL_RESOLUTION, NUM_STANDARD_UNIFORMS }; @@ -93,6 +94,7 @@ protected: // Entity metadata glm::vec3 _entityDimensions; glm::vec3 _entityPosition; + glm::mat3 _entityOrientation; private: // This should only be called from the render thread, as it shares data with Procedural::prepare diff --git a/libraries/procedural/src/procedural/ProceduralShaders.h b/libraries/procedural/src/procedural/ProceduralCommon.slf similarity index 93% rename from libraries/procedural/src/procedural/ProceduralShaders.h rename to libraries/procedural/src/procedural/ProceduralCommon.slf index eddf53cb09..128723265f 100644 --- a/libraries/procedural/src/procedural/ProceduralShaders.h +++ b/libraries/procedural/src/procedural/ProceduralCommon.slf @@ -1,3 +1,5 @@ +<@include gpu/Config.slh@> +// Generated on <$_SCRIBE_DATE$> // // Created by Bradley Austin Davis on 2015/09/05 // Copyright 2013-2015 High Fidelity, Inc. @@ -17,11 +19,11 @@ // https://github.com/ashima/webgl-noise // - -const std::string SHADER_COMMON = R"SHADER( +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> float mod289(float x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; + return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { @@ -262,11 +264,6 @@ float snoise(vec2 v) { return 130.0 * dot(m, g); } -// shader playback time (in seconds) -uniform float iGlobalTime; -// the dimensions of the object being rendered -uniform vec3 iWorldScale; - #define PROCEDURAL 1 //PROCEDURAL_VERSION @@ -286,15 +283,16 @@ const float iSampleRate = 1.0; const vec4 iChannelTime = vec4(0.0); +uniform float iGlobalTime; // shader playback time (in seconds) uniform vec4 iDate; uniform int iFrameCount; -uniform vec3 iWorldPosition; +uniform vec3 iWorldPosition; // the position of the object being rendered +uniform vec3 iWorldScale; // the dimensions of the object being rendered +uniform mat3 iWorldOrientation; // the orientation of the object being rendered uniform vec3 iChannelResolution[4]; uniform sampler2D iChannel0; uniform sampler2D iChannel1; uniform sampler2D iChannel2; uniform sampler2D iChannel3; -#endif - -)SHADER"; +#endif \ No newline at end of file diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 1aa59c90d7..9e9a26d902 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -52,7 +52,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, batch.setModelTransform(Transform()); // only for Mac auto& procedural = skybox._procedural; - procedural.prepare(batch, glm::vec3(0), glm::vec3(1)); + procedural.prepare(batch, glm::vec3(0), glm::vec3(1), glm::quat()); auto textureSlot = procedural.getShader()->getTextures().findLocation("cubeMap"); auto bufferSlot = procedural.getShader()->getBuffers().findLocation("skyboxBuffer"); skybox.prepare(batch, textureSlot, bufferSlot); diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index c4f28aeffd..2a7d33e33a 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME render-utils) -AUTOSCRIBE_SHADER_LIB(gpu model render) +AUTOSCRIBE_SHADER_LIB(gpu model render procedural) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Widgets OpenGL Network Qml Quick Script) diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 76fc8303ce..c5cfdf3668 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME render) -AUTOSCRIBE_SHADER_LIB(gpu model) +AUTOSCRIBE_SHADER_LIB(gpu model procedural) setup_hifi_library() link_hifi_libraries(shared gpu model) diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp index 29c223f4b3..beddc21787 100644 --- a/libraries/script-engine/src/ScriptEngines.cpp +++ b/libraries/script-engine/src/ScriptEngines.cpp @@ -334,6 +334,7 @@ void ScriptEngines::clearScripts() { Settings settings; settings.beginWriteArray(SETTINGS_KEY); settings.remove(""); + settings.endArray(); } void ScriptEngines::saveScripts() { diff --git a/libraries/shared/src/SettingHandle.cpp b/libraries/shared/src/SettingHandle.cpp index b2f23f5a04..13f9ea48ce 100644 --- a/libraries/shared/src/SettingHandle.cpp +++ b/libraries/shared/src/SettingHandle.cpp @@ -18,6 +18,7 @@ const QString Settings::firstRun { "firstRun" }; + Settings::Settings() : _manager(DependencyManager::get()), _locker(&(_manager->getLock())) @@ -25,6 +26,9 @@ Settings::Settings() : } Settings::~Settings() { + if (_prefixes.size() != 0) { + qFatal("Unstable Settings Prefixes: You must call endGroup for every beginGroup and endArray for every begin*Array call"); + } } void Settings::remove(const QString& key) { @@ -50,14 +54,17 @@ bool Settings::contains(const QString& key) const { } int Settings::beginReadArray(const QString & prefix) { + _prefixes.push(prefix); return _manager->beginReadArray(prefix); } void Settings::beginWriteArray(const QString& prefix, int size) { + _prefixes.push(prefix); _manager->beginWriteArray(prefix, size); } void Settings::endArray() { + _prefixes.pop(); _manager->endArray(); } @@ -66,10 +73,12 @@ void Settings::setArrayIndex(int i) { } void Settings::beginGroup(const QString& prefix) { + _prefixes.push(prefix); _manager->beginGroup(prefix); } void Settings::endGroup() { + _prefixes.pop(); _manager->endGroup(); } diff --git a/libraries/shared/src/SettingHandle.h b/libraries/shared/src/SettingHandle.h index e83c563036..8e07d28dad 100644 --- a/libraries/shared/src/SettingHandle.h +++ b/libraries/shared/src/SettingHandle.h @@ -58,8 +58,10 @@ public: void setQuatValue(const QString& name, const glm::quat& quatValue); void getQuatValueIfValid(const QString& name, glm::quat& quatValue); +private: QSharedPointer _manager; QWriteLocker _locker; + QStack _prefixes; }; namespace Setting { @@ -75,15 +77,40 @@ namespace Setting { virtual ~Handle() { deinit(); } // Returns setting value, returns its default value if not found - T get() { return get(_defaultValue); } + T get() const { + return get(_defaultValue); + } + // Returns setting value, returns other if not found - T get(const T& other) { maybeInit(); return (_isSet) ? _value : other; } - T getDefault() const { return _defaultValue; } + T get(const T& other) const { + maybeInit(); + return (_isSet) ? _value : other; + } + + const T& getDefault() const { + return _defaultValue; + } - void set(const T& value) { maybeInit(); _value = value; _isSet = true; } - void reset() { set(_defaultValue); } - - void remove() { maybeInit(); _isSet = false; } + void reset() { + set(_defaultValue); + } + + void set(const T& value) { + maybeInit(); + if ((!_isSet && (value != _defaultValue)) || _value != value) { + _value = value; + _isSet = true; + save(); + } + } + + void remove() { + maybeInit(); + if (_isSet) { + _isSet = false; + save(); + } + } protected: virtual void setVariant(const QVariant& variant); diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 630d52bf7d..95c6bc1efc 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -98,6 +98,8 @@ namespace Setting { // Register Handle manager->registerHandle(this); _isInitialized = true; + } else { + qWarning() << "Settings interface used after manager destroyed"; } // Load value from disk @@ -117,9 +119,9 @@ namespace Setting { } - void Interface::maybeInit() { + void Interface::maybeInit() const { if (!_isInitialized) { - init(); + const_cast(this)->init(); } } diff --git a/libraries/shared/src/SettingInterface.h b/libraries/shared/src/SettingInterface.h index 2b32e8a3b4..5e23d42223 100644 --- a/libraries/shared/src/SettingInterface.h +++ b/libraries/shared/src/SettingInterface.h @@ -39,19 +39,20 @@ namespace Setting { virtual ~Interface() = default; void init(); - void maybeInit(); + void maybeInit() const; void deinit(); void save(); void load(); - - bool _isInitialized = false; + bool _isSet = false; const QString _key; + + private: + mutable bool _isInitialized = false; friend class Manager; - - QWeakPointer _manager; + mutable QWeakPointer _manager; }; } diff --git a/libraries/shared/src/SettingManager.cpp b/libraries/shared/src/SettingManager.cpp index bacec2ee0c..abb8525b03 100644 --- a/libraries/shared/src/SettingManager.cpp +++ b/libraries/shared/src/SettingManager.cpp @@ -33,8 +33,8 @@ namespace Setting { void Manager::customDeleter() { } - void Manager::registerHandle(Setting::Interface* handle) { - QString key = handle->getKey(); + void Manager::registerHandle(Interface* handle) { + const QString& key = handle->getKey(); withWriteLock([&] { if (_handles.contains(key)) { qWarning() << "Setting::Manager::registerHandle(): Key registered more than once, overriding: " << key; @@ -58,7 +58,9 @@ namespace Setting { } else { loadedValue = value(key); } - handle->setVariant(loadedValue); + if (loadedValue.isValid()) { + handle->setVariant(loadedValue); + } }); } @@ -94,6 +96,7 @@ namespace Setting { } void Manager::saveAll() { + bool forceSync = false; withWriteLock([&] { for (auto key : _pendingChanges.keys()) { auto newValue = _pendingChanges[key]; @@ -101,15 +104,21 @@ namespace Setting { if (newValue == savedValue) { continue; } - if (newValue == UNSET_VALUE) { + if (newValue == UNSET_VALUE || !newValue.isValid()) { + forceSync = true; remove(key); } else { + forceSync = true; setValue(key, newValue); } } _pendingChanges.clear(); }); + if (forceSync) { + sync(); + } + // Restart timer if (_saveTimer) { _saveTimer->start(); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 04bb57a688..c2563a1188 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -144,6 +144,15 @@ public: bool hasAncestorOfType(NestableType nestableType); + void getLocalTransformAndVelocities(Transform& localTransform, + glm::vec3& localVelocity, + glm::vec3& localAngularVelocity) const; + + void setLocalTransformAndVelocities( + const Transform& localTransform, + const glm::vec3& localVelocity, + const glm::vec3& localAngularVelocity); + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -151,13 +160,6 @@ protected: quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer(bool& success) const; - void getLocalTransformAndVelocities(Transform& localTransform, glm::vec3& localVelocity, glm::vec3& localAngularVelocity) const; - - void setLocalTransformAndVelocities( - const Transform& localTransform, - const glm::vec3& localVelocity, - const glm::vec3& localAngularVelocity); - mutable SpatiallyNestableWeakPointer _parent; virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 0d2cdc940a..a7a0a2f56f 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -363,6 +363,10 @@ void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint } else if (button == vr::k_EButton_SteamVR_Touchpad) { _buttonPressedMap.insert(isLeftHand ? LS : RS); } + } else { + if (button == vr::k_EButton_Grip) { + _axisStateMap[isLeftHand ? LEFT_GRIP : RIGHT_GRIP] = 0.0f; + } } if (touched) { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1232c8d94d..42eddf11c3 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1221,8 +1221,7 @@ function handeMenuEvent(menuItem) { if (!selectionManager.hasSelection()) { Window.alert("No entities have been selected."); } else { - var filename = "entities__" + Window.location.hostname + ".svo.json"; - filename = Window.save("Select Where to Save", filename, "*.json") + var filename = Window.save("Select Where to Save", "", "*.json") if (filename) { var success = Clipboard.exportEntities(filename, selectionManager.selections); if (!success) { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 2a82d8fa74..c8edbdb369 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -546,17 +546,10 @@ disableProperties(); } else { - var activeElement = document.activeElement; - - try { - var selected = (activeElement - && activeElement.selectionStart == 0 - && activeElement.selectionEnd == activeElement.value.length); - } catch (e) { - var selected = false; - } + properties = data.selections[0].properties; + elID.innerHTML = properties.id; elType.innerHTML = properties.type; @@ -571,7 +564,6 @@ } else { enableProperties(); } - elName.value = properties.name; @@ -811,11 +803,10 @@ elYTextureURL.value = properties.yTextureURL; elZTextureURL.value = properties.zTextureURL; } - - if (selected) { - activeElement.focus(); - activeElement.select(); - } + + var activeElement = document.activeElement; + + activeElement.select(); } } }); @@ -1178,7 +1169,7 @@ for (var i = 0; i < els.length; i++) { var clicked = false; var originalText; - els[i].onfocus = function() { + els[i].onfocus = function(e) { originalText = this.value; this.select(); clicked = false;