From 5a843b13427e3d884f6779abb3af55efd67fc3c7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 14 Dec 2017 11:03:59 -0800 Subject: [PATCH 01/83] adding support for filters to get old properties --- libraries/entities/src/EntityEditFilters.cpp | 11 ++++-- libraries/entities/src/EntityEditFilters.h | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- .../entity_edit_filters/postition-example.js | 36 +++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 scripts/tutorials/entity_edit_filters/postition-example.js diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 550c8f17c4..09c165e9cb 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -42,7 +42,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { } bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, - EntityTree::FilterType filterType, EntityItemID& itemID) { + EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { // get the ids of all the zones (plus the global entity edit filter) that the position // lies within @@ -68,9 +68,15 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper propertiesIn.setDesiredProperties(oldProperties); auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. + + // get the current properties for then entity and include them for the filter call + auto currentProperties = existingEntity ? existingEntity->getProperties() : EntityItemProperties(); + QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + QScriptValueList args; args << inputValues; args << filterType; + args << currentValues; QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); if (filterData.uncaughtExceptions()) { @@ -182,8 +188,8 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { qDebug() << "script request completed for entity " << entityID; auto scriptRequest = qobject_cast(sender()); - const QString urlString = scriptRequest->getUrl().toString(); if (scriptRequest && scriptRequest->getResult() == ResourceRequest::Success) { + const QString urlString = scriptRequest->getUrl().toString(); auto scriptContents = scriptRequest->getData(); qInfo() << "Downloaded script:" << scriptContents; QScriptProgram program(scriptContents, urlString); @@ -227,6 +233,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { } } } else if (scriptRequest) { + const QString urlString = scriptRequest->getUrl().toString(); qCritical() << "Failed to download script at" << urlString; // See HTTPResourceRequest::onRequestFinished for interpretation of codes. For example, a 404 is code 6 and 403 is 3. A timeout is 2. Go figure. qCritical() << "ResourceRequest error was" << scriptRequest->getResult(); diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index 6aeb347603..f25c3c092e 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -43,7 +43,7 @@ public: void removeFilter(EntityItemID entityID); bool filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, - EntityTree::FilterType filterType, EntityItemID& entityID); + EntityTree::FilterType filterType, EntityItemID& entityID, EntityItemPointer& existingEntity); signals: void filterAdded(EntityItemID id, bool success); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e62399ce95..aa7215f53f 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1099,7 +1099,7 @@ bool EntityTree::filterProperties(EntityItemPointer& existingEntity, EntityItemP if (entityEditFilters) { auto position = existingEntity ? existingEntity->getWorldPosition() : propertiesIn.getPosition(); auto entityID = existingEntity ? existingEntity->getEntityItemID() : EntityItemID(); - accepted = entityEditFilters->filter(position, propertiesIn, propertiesOut, wasChanged, filterType, entityID); + accepted = entityEditFilters->filter(position, propertiesIn, propertiesOut, wasChanged, filterType, entityID, existingEntity); } return accepted; diff --git a/scripts/tutorials/entity_edit_filters/postition-example.js b/scripts/tutorials/entity_edit_filters/postition-example.js new file mode 100644 index 0000000000..00f7391809 --- /dev/null +++ b/scripts/tutorials/entity_edit_filters/postition-example.js @@ -0,0 +1,36 @@ +function filter(properties, type, originalProperties) { + + /* Clamp position changes.*/ + var maxChange = 5; + function sign(val) { + if (val > 0) { + return 1; + } else if (val < 0) { + return -1; + } else { + return 0; + } + } + + function clamp(val, min, max) { + if (val > max) { + val = max; + } else if (val < min) { + val = min; + } + return val; + } + + + if (properties.position) { + /* Random near-zero value used as "zero" to prevent two sequential updates from being + exactly the same (which would cause them to be ignored) */ + var nearZero = 0.0001 * Math.random() + 0.001; + var maxFudgeChange = (maxChange + nearZero); + properties.position.x = clamp(properties.position.x, originalProperties.position.x - maxFudgeChange, originalProperties.position.x + maxFudgeChange); + properties.position.y = clamp(properties.position.y, originalProperties.position.y - maxFudgeChange, originalProperties.position.y + maxFudgeChange); + properties.position.z = clamp(properties.position.z, originalProperties.position.z - maxFudgeChange, originalProperties.position.z + maxFudgeChange); + } + + return properties; +} \ No newline at end of file From 17288386aeddbad5ce953087903a744e23d08105 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 14 Dec 2017 12:20:03 -0800 Subject: [PATCH 02/83] implement support for zone properties in filters --- libraries/entities/src/EntityEditFilters.cpp | 25 +++++++++++++++++++ .../keep-in-zone-example.js | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 scripts/tutorials/entity_edit_filters/keep-in-zone-example.js diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 09c165e9cb..13be7ebc7d 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -73,12 +73,37 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto currentProperties = existingEntity ? existingEntity->getProperties() : EntityItemProperties(); QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + // get the zone properties + auto zoneEntity = _tree->findEntityByEntityItemID(id); + auto zoneProperties = zoneEntity ? zoneEntity->getProperties() : EntityItemProperties(); + QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); + + if (zoneEntity) { + bool success = true; + AABox aaBox = zoneEntity->getAABox(success); + + if (success) { + QScriptValue boundingBox = filterData.engine->newObject(); + QScriptValue bottomRightNear = vec3toScriptValue(filterData.engine, aaBox.getCorner()); + QScriptValue topFarLeft = vec3toScriptValue(filterData.engine, aaBox.calcTopFarLeft()); + QScriptValue center = vec3toScriptValue(filterData.engine, aaBox.calcCenter()); + QScriptValue boundingBoxDimensions = vec3toScriptValue(filterData.engine, aaBox.getDimensions()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + boundingBox.setProperty("dimensions", boundingBoxDimensions); + zoneValues.setProperty("boundingBox", boundingBox); + } + } + QScriptValueList args; args << inputValues; args << filterType; args << currentValues; + args << zoneValues; QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); + if (filterData.uncaughtExceptions()) { return false; } diff --git a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js new file mode 100644 index 0000000000..13355129f5 --- /dev/null +++ b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js @@ -0,0 +1,24 @@ +function filter(properties, type, originalProperties, zoneProperties) { + + var nearZero = 0.0001 * Math.random() + 0.001; + + /* Clamp position changes to bounding box of zone.*/ + function clamp(val, min, max) { + /* Random near-zero value used as "zero" to prevent two sequential updates from being + exactly the same (which would cause them to be ignored) */ + if (val > max) { + val = max - nearZero; + } else if (val < min) { + val = min + nearZero; + } + return val; + } + + if (properties.position) { + properties.position.x = clamp(properties.position.x, zoneProperties.boundingBox.brn.x, zoneProperties.boundingBox.tfl.x); + properties.position.y = clamp(properties.position.y, zoneProperties.boundingBox.brn.y, zoneProperties.boundingBox.tfl.y); + properties.position.z = clamp(properties.position.z, zoneProperties.boundingBox.brn.z, zoneProperties.boundingBox.tfl.z); + } + + return properties; +} \ No newline at end of file From 32d05bc163c16303ef5625e65df73f756228080d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 19 Dec 2017 07:34:56 -0800 Subject: [PATCH 03/83] CR feedback --- scripts/tutorials/entity_edit_filters/keep-in-zone-example.js | 2 +- .../{postition-example.js => position-example.js} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename scripts/tutorials/entity_edit_filters/{postition-example.js => position-example.js} (99%) diff --git a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js index 13355129f5..9013edda96 100644 --- a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js +++ b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js @@ -21,4 +21,4 @@ function filter(properties, type, originalProperties, zoneProperties) { } return properties; -} \ No newline at end of file +} diff --git a/scripts/tutorials/entity_edit_filters/postition-example.js b/scripts/tutorials/entity_edit_filters/position-example.js similarity index 99% rename from scripts/tutorials/entity_edit_filters/postition-example.js rename to scripts/tutorials/entity_edit_filters/position-example.js index 00f7391809..5f17f04542 100644 --- a/scripts/tutorials/entity_edit_filters/postition-example.js +++ b/scripts/tutorials/entity_edit_filters/position-example.js @@ -33,4 +33,4 @@ function filter(properties, type, originalProperties) { } return properties; -} \ No newline at end of file +} From 8aa0525f4536b965a6b3bd1586291ca38df164a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Jan 2018 10:32:28 -0800 Subject: [PATCH 04/83] CR style feedback --- .../keep-in-zone-example.js | 15 +++++++- .../entity_edit_filters/position-example.js | 37 +++++++++++-------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js index 9013edda96..eb9cfbeb4d 100644 --- a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js +++ b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js @@ -1,8 +1,21 @@ +// +// keep-in-zone-example.js +// +// +// Created by Brad Hefta-Gaub to use Entities on Dec. 15, 2017 +// Copyright 2017 High Fidelity, Inc. +// +// This sample entity edit filter script will keep any entity inside the bounding box of the zone this filter is applied to. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + function filter(properties, type, originalProperties, zoneProperties) { var nearZero = 0.0001 * Math.random() + 0.001; - /* Clamp position changes to bounding box of zone.*/ + /* Clamp position changes to bounding box of zone.*/ function clamp(val, min, max) { /* Random near-zero value used as "zero" to prevent two sequential updates from being exactly the same (which would cause them to be ignored) */ diff --git a/scripts/tutorials/entity_edit_filters/position-example.js b/scripts/tutorials/entity_edit_filters/position-example.js index 5f17f04542..a6cafe6bcb 100644 --- a/scripts/tutorials/entity_edit_filters/position-example.js +++ b/scripts/tutorials/entity_edit_filters/position-example.js @@ -1,16 +1,20 @@ +// +// position-example.js +// +// +// Created by Brad Hefta-Gaub to use Entities on Dec. 15, 2017 +// Copyright 2017 High Fidelity, Inc. +// +// This sample entity edit filter script will only allow position to be changed by no more than 5 meters on any axis. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + function filter(properties, type, originalProperties) { - - /* Clamp position changes.*/ - var maxChange = 5; - function sign(val) { - if (val > 0) { - return 1; - } else if (val < 0) { - return -1; - } else { - return 0; - } - } + + /* Clamp position changes.*/ + var maxChange = 5; function clamp(val, min, max) { if (val > max) { @@ -27,9 +31,12 @@ function filter(properties, type, originalProperties) { exactly the same (which would cause them to be ignored) */ var nearZero = 0.0001 * Math.random() + 0.001; var maxFudgeChange = (maxChange + nearZero); - properties.position.x = clamp(properties.position.x, originalProperties.position.x - maxFudgeChange, originalProperties.position.x + maxFudgeChange); - properties.position.y = clamp(properties.position.y, originalProperties.position.y - maxFudgeChange, originalProperties.position.y + maxFudgeChange); - properties.position.z = clamp(properties.position.z, originalProperties.position.z - maxFudgeChange, originalProperties.position.z + maxFudgeChange); + properties.position.x = clamp(properties.position.x, originalProperties.position.x + - maxFudgeChange, originalProperties.position.x + maxFudgeChange); + properties.position.y = clamp(properties.position.y, originalProperties.position.y + - maxFudgeChange, originalProperties.position.y + maxFudgeChange); + properties.position.z = clamp(properties.position.z, originalProperties.position.z + - maxFudgeChange, originalProperties.position.z + maxFudgeChange); } return properties; From 612f9621b449f07a64425312d8cc16533b675cd0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Jan 2018 10:00:49 -0800 Subject: [PATCH 05/83] adding filter properties to allow optimization --- libraries/entities/src/EntityEditFilters.cpp | 136 ++++++++++++++---- libraries/entities/src/EntityEditFilters.h | 6 + .../keep-in-zone-example.js | 4 + .../entity_edit_filters/position-example.js | 2 + 4 files changed, 117 insertions(+), 31 deletions(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 13be7ebc7d..2b0dcc9f73 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -61,6 +61,7 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper if (filterData.rejectAll) { return false; } + auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); @@ -69,38 +70,44 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper auto in = QJsonValue::fromVariant(inputValues.toVariant()); // grab json copy now, because the inputValues might be side effected by the filter. - // get the current properties for then entity and include them for the filter call - auto currentProperties = existingEntity ? existingEntity->getProperties() : EntityItemProperties(); - QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); - - // get the zone properties - auto zoneEntity = _tree->findEntityByEntityItemID(id); - auto zoneProperties = zoneEntity ? zoneEntity->getProperties() : EntityItemProperties(); - QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); - - if (zoneEntity) { - bool success = true; - AABox aaBox = zoneEntity->getAABox(success); - - if (success) { - QScriptValue boundingBox = filterData.engine->newObject(); - QScriptValue bottomRightNear = vec3toScriptValue(filterData.engine, aaBox.getCorner()); - QScriptValue topFarLeft = vec3toScriptValue(filterData.engine, aaBox.calcTopFarLeft()); - QScriptValue center = vec3toScriptValue(filterData.engine, aaBox.calcCenter()); - QScriptValue boundingBoxDimensions = vec3toScriptValue(filterData.engine, aaBox.getDimensions()); - boundingBox.setProperty("brn", bottomRightNear); - boundingBox.setProperty("tfl", topFarLeft); - boundingBox.setProperty("center", center); - boundingBox.setProperty("dimensions", boundingBoxDimensions); - zoneValues.setProperty("boundingBox", boundingBox); - } - } - QScriptValueList args; args << inputValues; args << filterType; - args << currentValues; - args << zoneValues; + + // get the current properties for then entity and include them for the filter call + if (existingEntity && filterData.wantsOriginalProperties) { + auto currentProperties = existingEntity->getProperties(filterData.includedOriginalProperties); + QScriptValue currentValues = currentProperties.copyToScriptValue(filterData.engine, false, true, true); + args << currentValues; + } + + + // get the zone properties + if (filterData.wantsZoneProperties) { + auto zoneEntity = _tree->findEntityByEntityItemID(id); + if (zoneEntity) { + auto zoneProperties = zoneEntity->getProperties(filterData.includedZoneProperties); + QScriptValue zoneValues = zoneProperties.copyToScriptValue(filterData.engine, false, true, true); + + if (filterData.wantsZoneBoundingBox) { + bool success = true; + AABox aaBox = zoneEntity->getAABox(success); + if (success) { + QScriptValue boundingBox = filterData.engine->newObject(); + QScriptValue bottomRightNear = vec3toScriptValue(filterData.engine, aaBox.getCorner()); + QScriptValue topFarLeft = vec3toScriptValue(filterData.engine, aaBox.calcTopFarLeft()); + QScriptValue center = vec3toScriptValue(filterData.engine, aaBox.calcCenter()); + QScriptValue boundingBoxDimensions = vec3toScriptValue(filterData.engine, aaBox.getDimensions()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + boundingBox.setProperty("dimensions", boundingBoxDimensions); + zoneValues.setProperty("boundingBox", boundingBox); + } + } + args << zoneValues; + } + } QScriptValue result = filterData.filterFn.call(_nullObjectForFilter, args); @@ -245,8 +252,75 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { delete engine; filterData.rejectAll=true; } - - + + // check to see if the filterFn has properties asking for Original props + QScriptValue wantsOriginalPropertiesValue = filterData.filterFn.property("wantsOriginalProperties"); + // if the wantsOriginalProperties is a boolean, or a string, or list of strings, then evaluate as follows: + // - boolean - true - include all original properties + // false - no properties at all + // - string - empty - no properties at all + // any valid property - include just that property in the Original properties + // - list of strings - include only those properties in the Original properties + if (wantsOriginalPropertiesValue.isBool()) { + filterData.wantsOriginalProperties = wantsOriginalPropertiesValue.toBool(); + } else if (wantsOriginalPropertiesValue.isString()) { + auto stringValue = wantsOriginalPropertiesValue.toString(); + filterData.wantsOriginalProperties = !stringValue.isEmpty(); + if (filterData.wantsOriginalProperties) { + EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); + } + } else if (wantsOriginalPropertiesValue.isArray()) { + auto length = wantsOriginalPropertiesValue.property("length").toInteger(); + for (int i; i < length; i++) { + auto stringValue = wantsOriginalPropertiesValue.property(i).toString(); + if (!stringValue.isEmpty()) { + filterData.wantsOriginalProperties = true; + break; + } + } + if (filterData.wantsOriginalProperties) { + EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); + } + } + + // check to see if the filterFn has properties asking for Zone props + QScriptValue wantsZonePropertiesValue = filterData.filterFn.property("wantsZoneProperties"); + // if the wantsZoneProperties is a boolean, or a string, or list of strings, then evaluate as follows: + // - boolean - true - include all Zone properties + // false - no properties at all + // - string - empty - no properties at all + // any valid property - include just that property in the Zone properties + // - list of strings - include only those properties in the Zone properties + if (wantsZonePropertiesValue.isBool()) { + filterData.wantsZoneProperties = wantsZonePropertiesValue.toBool(); + filterData.wantsZoneBoundingBox = filterData.wantsZoneProperties; // include this too + } else if (wantsZonePropertiesValue.isString()) { + auto stringValue = wantsZonePropertiesValue.toString(); + filterData.wantsZoneProperties = !stringValue.isEmpty(); + if (filterData.wantsZoneProperties) { + EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); + } + } else if (wantsZonePropertiesValue.isArray()) { + auto length = wantsZonePropertiesValue.property("length").toInteger(); + for (int i; i < length; i++) { + auto stringValue = wantsZonePropertiesValue.property(i).toString(); + if (!stringValue.isEmpty()) { + filterData.wantsZoneProperties = true; + + // boundingBox is a special case since it's not a true EntityPropertyFlag, so we + // need to detect it here. + if (stringValue == "boundingBox") { + filterData.wantsZoneBoundingBox = true; + break; // we can break here, since there are no other special cases + } + + } + } + if (filterData.wantsZoneProperties) { + EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); + } + } + _lock.lockForWrite(); _filterDataMap.insert(entityID, filterData); _lock.unlock(); diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index f25c3c092e..be3df50d3f 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -28,6 +28,12 @@ class EntityEditFilters : public QObject, public Dependency { public: struct FilterData { QScriptValue filterFn; + bool wantsOriginalProperties { false }; + bool wantsZoneProperties { false }; + EntityPropertyFlags includedOriginalProperties; + EntityPropertyFlags includedZoneProperties; + bool wantsZoneBoundingBox { false }; + std::function uncaughtExceptions; QScriptEngine* engine; bool rejectAll; diff --git a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js index eb9cfbeb4d..6d83ce1410 100644 --- a/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js +++ b/scripts/tutorials/entity_edit_filters/keep-in-zone-example.js @@ -35,3 +35,7 @@ function filter(properties, type, originalProperties, zoneProperties) { return properties; } + +filter.wantsOriginalProperties = true; +filter.wantsZoneProperties = true; +filter; \ No newline at end of file diff --git a/scripts/tutorials/entity_edit_filters/position-example.js b/scripts/tutorials/entity_edit_filters/position-example.js index a6cafe6bcb..01eabee7db 100644 --- a/scripts/tutorials/entity_edit_filters/position-example.js +++ b/scripts/tutorials/entity_edit_filters/position-example.js @@ -41,3 +41,5 @@ function filter(properties, type, originalProperties) { return properties; } +filter.wantsOriginalProperties = true; +filter; \ No newline at end of file From 241849139ffe1c0a28181c7cd32a0d65857379dd Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 15 Jan 2018 10:21:16 -0800 Subject: [PATCH 06/83] wip --- libraries/entities/CMakeLists.txt | 6 +- .../entities/src/EntityItemProperties.cpp | 43 +++++++ libraries/entities/src/EntityItemProperties.h | 37 ++++-- .../entities/src/EntityItemPropertiesMacros.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 7 + libraries/entities/src/EntityTypes.cpp | 2 + libraries/entities/src/EntityTypes.h | 3 +- libraries/entities/src/MaterialEntityItem.cpp | 120 ++++++++++++++++++ libraries/entities/src/MaterialEntityItem.h | 79 ++++++++++++ libraries/shared/src/MaterialMode.h | 18 +++ 10 files changed, 301 insertions(+), 15 deletions(-) create mode 100644 libraries/entities/src/MaterialEntityItem.cpp create mode 100644 libraries/entities/src/MaterialEntityItem.h create mode 100644 libraries/shared/src/MaterialMode.h diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index c23740654e..191e43ebbe 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,4 +1,8 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") -link_hifi_libraries(shared networking octree avatars model) +include_hifi_library_headers(fbx) +include_hifi_library_headers(gpu) +include_hifi_library_headers(image) +include_hifi_library_headers(ktx) +link_hifi_libraries(shared networking octree avatars model model-networking) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8bfce7e2d2..0edec88edf 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -330,6 +330,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); + CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BOUNDS, materialBounds); + // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); CHECK_PROPERTY_CHANGE(PROP_ITEM_DESCRIPTION, itemDescription); @@ -623,6 +630,16 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); } + // Materials + if (_type == EntityTypes::Material) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_TYPE, materialMode); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BOUNDS, materialBounds); + } + if (!skipDefaults && !strictSemantics) { AABox aaBox = getAABox(); QScriptValue boundingBox = engine->newObject(); @@ -755,6 +772,12 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); + COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1490,6 +1513,16 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); } + // Materials + if (properties.getType() == EntityTypes::Material) { + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)properties.getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, properties.getMaterialBounds()); + } + APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); @@ -1845,6 +1878,16 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape); } + // Materials + if (properties.getType() == EntityTypes::Material) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); + } + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c3d04dc7ad..3190d66b63 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -44,6 +44,8 @@ #include "TextEntityItem.h" #include "ZoneEntityItem.h" +#include "MaterialMode.h" + const quint64 UNKNOWN_CREATED_TIME = 0; using ComponentPair = std::pair; @@ -58,19 +60,21 @@ const std::array COMPONENT_MODES = { { /// set of entity item properties via JavaScript hashes/QScriptValues /// all units for SI units (meter, second, radian, etc) class EntityItemProperties { - friend class EntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods - friend class ShapeEntityItem; // TODO: consider removing this friend relationship and use public methods + // TODO: consider removing these friend relationship and use public methods + friend class EntityItem; + friend class ModelEntityItem; + friend class BoxEntityItem; + friend class SphereEntityItem; + friend class LightEntityItem; + friend class TextEntityItem; + friend class ParticleEffectEntityItem; + friend class ZoneEntityItem; + friend class WebEntityItem; + friend class LineEntityItem; + friend class PolyVoxEntityItem; + friend class PolyLineEntityItem; + friend class ShapeEntityItem; + friend class MaterialEntityItem; public: EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); virtual ~EntityItemProperties() = default; @@ -218,6 +222,13 @@ public: DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube()); DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere"); + DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); + DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); + DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); + DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); + // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 278d945ab0..c8c8a658ce 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -184,6 +184,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu } typedef glm::vec3 glmVec3; +typedef glm::vec4 glmVec4; typedef glm::quat glmQuat; typedef QVector qVectorVec3; typedef QVector qVectorQuat; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 7fd72bf0ee..fc9b5cd709 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -226,6 +226,13 @@ enum EntityPropertyList { PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts + PROP_MATERIAL_URL, + PROP_MATERIAL_TYPE, + PROP_MATERIAL_BLEND_FACTOR, + PROP_MATERIAL_PRIORITY, + PROP_PARENT_SHAPE_ID, + PROP_MATERIAL_BOUNDS, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index cb17c28fd7..307371c649 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -29,6 +29,7 @@ #include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" #include "ShapeEntityItem.h" +#include "MaterialEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; @@ -50,6 +51,7 @@ REGISTER_ENTITY_TYPE(PolyLine) REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) +REGISTER_ENTITY_TYPE(Material) const QString& EntityTypes::getEntityTypeName(EntityType entityType) { QMap::iterator matchedTypeName = _typeToNameMap.find(entityType); diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 316bf2b813..62011c6e26 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -49,7 +49,8 @@ public: PolyVox, PolyLine, Shape, - LAST = Shape + Material, + LAST = Material } EntityType; static const QString& getEntityTypeName(EntityType entityType); diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp new file mode 100644 index 0000000000..19daa11490 --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -0,0 +1,120 @@ +// +// Created by Sam Gondelman on 1/12/18 +// Copyright 2018 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 "MaterialEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Material; +} + +EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMode, getMaterialMode); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialBounds, getMaterialBounds); + return properties; +} + +bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialBounds, setMaterialBounds); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "MaterialEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); + READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); + READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, int, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, int, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time +EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_MATERIAL_URL; + requestedProperties += PROP_MATERIAL_TYPE; + requestedProperties += PROP_MATERIAL_BLEND_FACTOR; + requestedProperties += PROP_MATERIAL_PRIORITY; + requestedProperties += PROP_PARENT_SHAPE_ID; + requestedProperties += PROP_MATERIAL_BOUNDS; + return requestedProperties; +} + +void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); +} + +void MaterialEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qCDebug(entities) << "MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " url:" << _materialURL; + qCDebug(entities) << " material type:" << _materialMode; + qCDebug(entities) << " blend factor:" << _blendFactor; + qCDebug(entities) << " priority:" << _priority; + qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; +} diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h new file mode 100644 index 0000000000..094c94f24c --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.h @@ -0,0 +1,79 @@ +// +// Created by Sam Gondelman on 1/12/18 +// Copyright 2018 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_MaterialEntityItem_h +#define hifi_MaterialEntityItem_h + +#include "EntityItem.h" + +#include "MaterialMode.h" +#include + +class MaterialEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + MaterialEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; + virtual bool setProperties(const EntityItemProperties& properties) override; + + // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + void debugDump() const override; + + const QString& getMaterialURL() { return _materialURL; } + void setMaterialURL(const QString& materialURL) { _materialURL = materialURL; } + + MaterialMode getMaterialType() { return _materialMode; } + void setMaterialMode(MaterialMode mode); + + float getBlendFactor() { return _blendFactor; } + void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + + int getPriority() { return _priority; } + void setPriority(int priority) { _priority = priority; } + + int getShapeID() { return _shapeID; } + void setShapeID(int shapeID) { _shapeID = shapeID; } + + const glm::vec4& getMaterialBounds() { return _materialBounds; } + void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } + +protected: + QString _materialURL; + MaterialMode _materialMode { UV }; + float _blendFactor { 1.0f }; + int _priority { 0 }; + int _shapeID { 0 }; + glm::vec4 _materialBounds { 0, 0, 1, 1 }; + + //NetworkMaterial _material; + +}; + +#endif // hifi_MaterialEntityItem_h diff --git a/libraries/shared/src/MaterialMode.h b/libraries/shared/src/MaterialMode.h new file mode 100644 index 0000000000..05c6d295a5 --- /dev/null +++ b/libraries/shared/src/MaterialMode.h @@ -0,0 +1,18 @@ +// +// Created by Sam Gondelman on 1/12/18. +// Copyright 2018 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_MaterialMode_h +#define hifi_MaterialMode_h + +enum MaterialMode { + UV = 0, + PROJECTED +}; + +#endif // hifi_MaterialMode_h + From 25f5eb6b4fc3288d23b193e274996f72153cdec5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 18 Jan 2018 15:08:13 -0800 Subject: [PATCH 07/83] named property example --- libraries/entities/src/EntityEditFilters.cpp | 3 +++ scripts/tutorials/entity_edit_filters/position-example.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 2b0dcc9f73..a69a8ce7d1 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -299,6 +299,9 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { filterData.wantsZoneProperties = !stringValue.isEmpty(); if (filterData.wantsZoneProperties) { EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); + if (stringValue == "boundingBox") { + filterData.wantsZoneBoundingBox = true; + } } } else if (wantsZonePropertiesValue.isArray()) { auto length = wantsZonePropertiesValue.property("length").toInteger(); diff --git a/scripts/tutorials/entity_edit_filters/position-example.js b/scripts/tutorials/entity_edit_filters/position-example.js index 01eabee7db..314ba0fd9f 100644 --- a/scripts/tutorials/entity_edit_filters/position-example.js +++ b/scripts/tutorials/entity_edit_filters/position-example.js @@ -41,5 +41,5 @@ function filter(properties, type, originalProperties) { return properties; } -filter.wantsOriginalProperties = true; +filter.wantsOriginalProperties = "position"; filter; \ No newline at end of file From c96e395a46df93b652a22d605f2b2ceb4bf68b64 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Jan 2018 12:13:32 -0800 Subject: [PATCH 08/83] fix warning --- libraries/entities/src/EntityEditFilters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index a69a8ce7d1..f5bf699e02 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -271,7 +271,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { } } else if (wantsOriginalPropertiesValue.isArray()) { auto length = wantsOriginalPropertiesValue.property("length").toInteger(); - for (int i; i < length; i++) { + for (int i = 0; i < length; i++) { auto stringValue = wantsOriginalPropertiesValue.property(i).toString(); if (!stringValue.isEmpty()) { filterData.wantsOriginalProperties = true; @@ -305,7 +305,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { } } else if (wantsZonePropertiesValue.isArray()) { auto length = wantsZonePropertiesValue.property("length").toInteger(); - for (int i; i < length; i++) { + for (int i = 0; i < length; i++) { auto stringValue = wantsZonePropertiesValue.property(i).toString(); if (!stringValue.isEmpty()) { filterData.wantsZoneProperties = true; From aea16fe071d1731f783d6f93482c1161e2d513c2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Jan 2018 15:01:29 -0800 Subject: [PATCH 09/83] add delete filter support --- libraries/entities/src/EntityEditFilters.cpp | 1 + libraries/entities/src/EntityTree.cpp | 18 ++++++++++++++++++ libraries/entities/src/EntityTree.h | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index f5bf699e02..4e48c671cb 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -245,6 +245,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { entitiesObject.setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); entitiesObject.setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); entitiesObject.setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); + entitiesObject.setProperty("ERASE_FILTER_TYPE", EntityTree::FilterType::Erase); global.setProperty("Entities", entitiesObject); filterData.filterFn = global.property("filter"); if (!filterData.filterFn.isFunction()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9ab9f63245..629281749e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1928,6 +1928,24 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons #endif EntityItemID entityItemID(entityID); + + EntityItemPointer existingEntity; + + auto startLookup = usecTimestampNow(); + existingEntity = findEntityByEntityItemID(entityItemID); + auto endLookup = usecTimestampNow(); + _totalLookupTime += endLookup - startLookup; + + auto startFilter = usecTimestampNow(); + FilterType filterType = FilterType::Erase; + EntityItemProperties dummyProperties; + bool wasChanged = false; + + bool allowed = (sourceNode->isAllowedEditor()) || filterProperties(existingEntity, dummyProperties, dummyProperties, wasChanged, filterType); + auto endFilter = usecTimestampNow(); + + _totalFilterTime += endFilter - startFilter; + entityItemIDsToDelete << entityItemID; if (wantEditLogging() || wantTerseEditLogging()) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 11a747d624..ba786fbe98 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -57,7 +57,8 @@ public: enum FilterType { Add, Edit, - Physics + Physics, + Erase }; EntityTree(bool shouldReaverage = false); virtual ~EntityTree(); From 6192625942a34242688cb5e087b3fed99ed7e954 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Jan 2018 15:01:50 -0800 Subject: [PATCH 10/83] add delete filter support --- .../prevent-erase-in-zone-example.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js diff --git a/scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js b/scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js new file mode 100644 index 0000000000..356cc55079 --- /dev/null +++ b/scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js @@ -0,0 +1,24 @@ +// +// prevent-erase-in-zone-example.js +// +// +// Created by Brad Hefta-Gaub to use Entities on Jan. 25, 2018 +// Copyright 2018 High Fidelity, Inc. +// +// This sample entity edit filter script will keep prevent any entity inside the zone from being erased. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function filter(properties, type, originalProperties, zoneProperties) { + + if (type == Entities.ERASE_FILTER_TYPE) { + return false; + } + return properties; +} + +filter.wantsOriginalProperties = true; +filter.wantsZoneProperties = true; +filter; \ No newline at end of file From aa82ad885561411daf1d97778193f22cd18b612b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Jan 2018 14:57:36 -0800 Subject: [PATCH 11/83] adjust client to only delete entities on server echo --- libraries/entities/src/EntityScriptingInterface.cpp | 5 ++++- libraries/entities/src/EntityTree.cpp | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 206065beeb..877225de77 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -585,7 +585,10 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { if (entity->getLocked()) { shouldDelete = false; } else { - _entityTree->deleteEntity(entityID); + // only delete local entities, server entities will round trip through the server filters + if (entity->getClientOnly()) { + _entityTree->deleteEntity(entityID); + } } } }); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 629281749e..8071a8f9b7 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1946,12 +1946,16 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons _totalFilterTime += endFilter - startFilter; - entityItemIDsToDelete << entityItemID; - - if (wantEditLogging() || wantTerseEditLogging()) { - qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID; + if (allowed) { + entityItemIDsToDelete << entityItemID; + if (wantEditLogging() || wantTerseEditLogging()) { + qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID; + } + } else if (wantEditLogging() || wantTerseEditLogging()) { + qCDebug(entities) << "User [" << sourceNode->getUUID() << "] attempted to deleteentity. ID:" << entityItemID << " Filter rejected erase."; } + } deleteEntities(entityItemIDsToDelete, true, true); } From a3d86a02423eeaa22fe373b29531d0fc1f77a52b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Jan 2018 17:37:24 -0800 Subject: [PATCH 12/83] cleanup --- libraries/entities/src/EntityEditFilters.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 62 ++++++++++--------- libraries/entities/src/EntityTree.h | 4 +- ...e.js => prevent-delete-in-zone-example.js} | 6 +- 4 files changed, 41 insertions(+), 33 deletions(-) rename scripts/tutorials/entity_edit_filters/{prevent-erase-in-zone-example.js => prevent-delete-in-zone-example.js} (81%) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 4e48c671cb..4b66b61d93 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -245,7 +245,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { entitiesObject.setProperty("ADD_FILTER_TYPE", EntityTree::FilterType::Add); entitiesObject.setProperty("EDIT_FILTER_TYPE", EntityTree::FilterType::Edit); entitiesObject.setProperty("PHYSICS_FILTER_TYPE", EntityTree::FilterType::Physics); - entitiesObject.setProperty("ERASE_FILTER_TYPE", EntityTree::FilterType::Erase); + entitiesObject.setProperty("DELETE_FILTER_TYPE", EntityTree::FilterType::Delete); global.setProperty("Entities", entitiesObject); filterData.filterFn = global.property("filter"); if (!filterData.filterFn.isFunction()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 8071a8f9b7..57540092da 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1850,6 +1850,37 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) { } +bool EntityTree::shouldEraseEntity(EntityItemID entityID, const SharedNodePointer& sourceNode) { + EntityItemPointer existingEntity; + + auto startLookup = usecTimestampNow(); + existingEntity = findEntityByEntityItemID(entityID); + auto endLookup = usecTimestampNow(); + _totalLookupTime += endLookup - startLookup; + + auto startFilter = usecTimestampNow(); + FilterType filterType = FilterType::Delete; + EntityItemProperties dummyProperties; + bool wasChanged = false; + + bool allowed = (sourceNode->isAllowedEditor()) || filterProperties(existingEntity, dummyProperties, dummyProperties, wasChanged, filterType); + auto endFilter = usecTimestampNow(); + + _totalFilterTime += endFilter - startFilter; + + if (allowed) { + if (wantEditLogging() || wantTerseEditLogging()) { + qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityID; + } + } + else if (wantEditLogging() || wantTerseEditLogging()) { + qCDebug(entities) << "User [" << sourceNode->getUUID() << "] attempted to deleteentity. ID:" << entityID << " Filter rejected erase."; + } + + return allowed; +} + + // TODO: consider consolidating processEraseMessageDetails() and processEraseMessage() int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { #ifdef EXTRA_ERASE_DEBUGGING @@ -1877,12 +1908,10 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo #endif EntityItemID entityItemID(entityID); - entityItemIDsToDelete << entityItemID; - if (wantEditLogging() || wantTerseEditLogging()) { - qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID; + if (shouldEraseEntity(entityID, sourceNode)) { + entityItemIDsToDelete << entityItemID; } - } deleteEntities(entityItemIDsToDelete, true, true); } @@ -1929,33 +1958,10 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons EntityItemID entityItemID(entityID); - EntityItemPointer existingEntity; - - auto startLookup = usecTimestampNow(); - existingEntity = findEntityByEntityItemID(entityItemID); - auto endLookup = usecTimestampNow(); - _totalLookupTime += endLookup - startLookup; - - auto startFilter = usecTimestampNow(); - FilterType filterType = FilterType::Erase; - EntityItemProperties dummyProperties; - bool wasChanged = false; - - bool allowed = (sourceNode->isAllowedEditor()) || filterProperties(existingEntity, dummyProperties, dummyProperties, wasChanged, filterType); - auto endFilter = usecTimestampNow(); - - _totalFilterTime += endFilter - startFilter; - - if (allowed) { + if (shouldEraseEntity(entityID, sourceNode)) { entityItemIDsToDelete << entityItemID; - if (wantEditLogging() || wantTerseEditLogging()) { - qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityItemID; - } - } else if (wantEditLogging() || wantTerseEditLogging()) { - qCDebug(entities) << "User [" << sourceNode->getUUID() << "] attempted to deleteentity. ID:" << entityItemID << " Filter rejected erase."; } - } deleteEntities(entityItemIDsToDelete, true, true); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index ba786fbe98..4c5fcdb0f7 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -58,7 +58,7 @@ public: Add, Edit, Physics, - Erase + Delete }; EntityTree(bool shouldReaverage = false); virtual ~EntityTree(); @@ -194,6 +194,8 @@ public: int processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode); int processEraseMessageDetails(const QByteArray& buffer, const SharedNodePointer& sourceNode); + bool shouldEraseEntity(EntityItemID entityID, const SharedNodePointer& sourceNode); + EntityTreeElementPointer getContainingElement(const EntityItemID& entityItemID) /*const*/; void addEntityMapEntry(EntityItemPointer entity); diff --git a/scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js b/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js similarity index 81% rename from scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js rename to scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js index 356cc55079..94ee58738d 100644 --- a/scripts/tutorials/entity_edit_filters/prevent-erase-in-zone-example.js +++ b/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js @@ -1,11 +1,11 @@ // -// prevent-erase-in-zone-example.js +// prevent-delete-in-zone-example.js // // // Created by Brad Hefta-Gaub to use Entities on Jan. 25, 2018 // Copyright 2018 High Fidelity, Inc. // -// This sample entity edit filter script will keep prevent any entity inside the zone from being erased. +// This sample entity edit filter script will keep prevent any entity inside the zone from being deleted. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -13,7 +13,7 @@ function filter(properties, type, originalProperties, zoneProperties) { - if (type == Entities.ERASE_FILTER_TYPE) { + if (type == Entities.DELETE_FILTER_TYPE) { return false; } return properties; From b883d006c83f6c333d74be14a4b22a90950a8cd1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Jan 2018 18:26:48 -0800 Subject: [PATCH 13/83] add flags to support asking for specific messages, update examples --- libraries/entities/src/EntityEditFilters.cpp | 26 +++++++++++++++++++ libraries/entities/src/EntityEditFilters.h | 6 +++++ .../prevent-all-deletes.js | 22 ++++++++++++++++ .../prevent-delete-in-zone-example.js | 8 +++--- 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 scripts/tutorials/entity_edit_filters/prevent-all-deletes.js diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 4b66b61d93..cd1982bdb4 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -62,6 +62,16 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper return false; } + // check to see if this filter wants to filter this message type + if ((!filterData.wantsToFilterEdit && filterType == EntityTree::FilterType::Edit) || + (!filterData.wantsToFilterPhysics && filterType == EntityTree::FilterType::Physics) || + (!filterData.wantsToFilterDelete && filterType == EntityTree::FilterType::Delete) || + (!filterData.wantsToFilterAdd && filterType == EntityTree::FilterType::Add)) { + + wasChanged = false; + return true; // accept the message + } + auto oldProperties = propertiesIn.getDesiredProperties(); auto specifiedProperties = propertiesIn.getChangedProperties(); propertiesIn.setDesiredProperties(specifiedProperties); @@ -254,6 +264,22 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { filterData.rejectAll=true; } + // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true + QScriptValue wantsToFilterAddValue = filterData.filterFn.property("wantsToFilterAdd"); + filterData.wantsToFilterAdd = wantsToFilterAddValue.isBool() ? wantsToFilterAddValue.toBool() : true; + + // if the wantsToFilterEdit is a boolean evaluate as a boolean, otherwise assume true + QScriptValue wantsToFilterEditValue = filterData.filterFn.property("wantsToFilterEdit"); + filterData.wantsToFilterEdit = wantsToFilterEditValue.isBool() ? wantsToFilterEditValue.toBool() : true; + + // if the wantsToFilterPhysics is a boolean evaluate as a boolean, otherwise assume true + QScriptValue wantsToFilterPhysicsValue = filterData.filterFn.property("wantsToFilterPhysics"); + filterData.wantsToFilterPhysics = wantsToFilterPhysicsValue.isBool() ? wantsToFilterPhysicsValue.toBool() : true; + + // if the wantsToFilterDelete is a boolean evaluate as a boolean, otherwise assume false + QScriptValue wantsToFilterDeleteValue = filterData.filterFn.property("wantsToFilterDelete"); + filterData.wantsToFilterDelete = wantsToFilterDeleteValue.isBool() ? wantsToFilterDeleteValue.toBool() : false; + // check to see if the filterFn has properties asking for Original props QScriptValue wantsOriginalPropertiesValue = filterData.filterFn.property("wantsOriginalProperties"); // if the wantsOriginalProperties is a boolean, or a string, or list of strings, then evaluate as follows: diff --git a/libraries/entities/src/EntityEditFilters.h b/libraries/entities/src/EntityEditFilters.h index be3df50d3f..cb99c97762 100644 --- a/libraries/entities/src/EntityEditFilters.h +++ b/libraries/entities/src/EntityEditFilters.h @@ -30,6 +30,12 @@ public: QScriptValue filterFn; bool wantsOriginalProperties { false }; bool wantsZoneProperties { false }; + + bool wantsToFilterAdd { true }; + bool wantsToFilterEdit { true }; + bool wantsToFilterPhysics { true }; + bool wantsToFilterDelete { true }; + EntityPropertyFlags includedOriginalProperties; EntityPropertyFlags includedZoneProperties; bool wantsZoneBoundingBox { false }; diff --git a/scripts/tutorials/entity_edit_filters/prevent-all-deletes.js b/scripts/tutorials/entity_edit_filters/prevent-all-deletes.js new file mode 100644 index 0000000000..0e2c54a04a --- /dev/null +++ b/scripts/tutorials/entity_edit_filters/prevent-all-deletes.js @@ -0,0 +1,22 @@ +// +// prevent-all-deletes.js +// +// +// Created by Brad Hefta-Gaub to use Entities on Jan. 25, 2018 +// Copyright 2018 High Fidelity, Inc. +// +// This sample entity edit filter script will prevent deletes of any entities. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function filter() { + return false; // all deletes are blocked +} + +filter.wantsToFilterAdd = false; // don't run on adds +filter.wantsToFilterEdit = false; // don't run on edits +filter.wantsToFilterPhysics = false; // don't run on physics +filter.wantsToFilterDelete = true; // do run on deletes +filter; \ No newline at end of file diff --git a/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js b/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js index 94ee58738d..521bb94d00 100644 --- a/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js +++ b/scripts/tutorials/entity_edit_filters/prevent-delete-in-zone-example.js @@ -5,13 +5,14 @@ // Created by Brad Hefta-Gaub to use Entities on Jan. 25, 2018 // Copyright 2018 High Fidelity, Inc. // -// This sample entity edit filter script will keep prevent any entity inside the zone from being deleted. +// This sample entity edit filter script will get all edits, adds, physcis, and deletes, but will only block +// deletes, and will pass through all others. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -function filter(properties, type, originalProperties, zoneProperties) { +function filter(properties, type) { if (type == Entities.DELETE_FILTER_TYPE) { return false; @@ -19,6 +20,5 @@ function filter(properties, type, originalProperties, zoneProperties) { return properties; } -filter.wantsOriginalProperties = true; -filter.wantsZoneProperties = true; +filter.wantsToFilterDelete = true; // do run on deletes filter; \ No newline at end of file From efc63a41e9551583c3eeb62c41e52e37789594c9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Jan 2018 18:49:55 -0800 Subject: [PATCH 14/83] make sure true results for delete actually work, add more examples --- libraries/entities/src/EntityEditFilters.cpp | 13 +++++++++- ...event-add-of-entities-named-bob-example.js | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 scripts/tutorials/entity_edit_filters/prevent-add-of-entities-named-bob-example.js diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index cd1982bdb4..12bf1ac231 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -125,7 +125,7 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper return false; } - if (result.isObject()){ + if (result.isObject()) { // make propertiesIn reflect the changes, for next filter... propertiesIn.copyFromScriptValue(result, false); @@ -134,6 +134,17 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // Javascript objects are == only if they are the same object. To compare arbitrary values, we need to use JSON. auto out = QJsonValue::fromVariant(result.toVariant()); wasChanged |= (in != out); + } else if (result.isBool()) { + + // if the filter returned false, then it's authoritative + if (!result.toBool()) { + return false; + } + + // otherwise, assume it wants to pass all properties + propertiesOut = propertiesIn; + wasChanged = false; + } else { return false; } diff --git a/scripts/tutorials/entity_edit_filters/prevent-add-of-entities-named-bob-example.js b/scripts/tutorials/entity_edit_filters/prevent-add-of-entities-named-bob-example.js new file mode 100644 index 0000000000..03fbe97430 --- /dev/null +++ b/scripts/tutorials/entity_edit_filters/prevent-add-of-entities-named-bob-example.js @@ -0,0 +1,26 @@ +// +// prevent-add-of-entities-named-bob-example.js +// +// +// Created by Brad Hefta-Gaub to use Entities on Jan. 25, 2018 +// Copyright 2018 High Fidelity, Inc. +// +// This sample entity edit filter script will get all edits, adds, physcis, and deletes, but will only block +// deletes, and will pass through all others. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +function filter(properties, type) { + if (properties.name == "bob") { + return false; + } + return properties; +} + +filter.wantsToFilterAdd = true; // do run on add +filter.wantsToFilterEdit = false; // do not run on edit +filter.wantsToFilterPhysics = false; // do not run on physics +filter.wantsToFilterDelete = false; // do not run on delete +filter; \ No newline at end of file From d7f4b033e8f6d5249e43001dac5f1453093a4e06 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 17 Jan 2018 15:56:18 -0800 Subject: [PATCH 15/83] wip finish adding material entity --- .../resources/qml/hifi/tablet/EditTabView.qml | 11 + .../qml/hifi/tablet/NewMaterialDialog.qml | 174 +++++++++++++ .../src/RenderableEntityItem.cpp | 7 +- .../src/RenderableEntityItem.h | 1 - .../src/RenderableMaterialEntityItem.cpp | 238 ++++++++++++++++++ .../src/RenderableMaterialEntityItem.h | 54 ++++ .../entities/src/EntityItemProperties.cpp | 63 ++++- .../entities/src/EntityItemPropertiesMacros.h | 23 ++ libraries/entities/src/MaterialEntityItem.cpp | 229 +++++++++++++++-- libraries/entities/src/MaterialEntityItem.h | 34 ++- libraries/graphics/src/graphics/Material.cpp | 2 +- .../src/model-networking/ModelCache.cpp | 91 ++++++- .../src/model-networking/ModelCache.h | 20 +- .../src/model-networking/TextureCache.cpp | 2 + .../src/model-networking/TextureCache.h | 1 - libraries/networking/src/ResourceCache.cpp | 9 +- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 3 +- libraries/octree/src/OctreePacketData.h | 4 + .../src/CauterizedMeshPartPayload.cpp | 4 +- .../src/CauterizedMeshPartPayload.h | 2 +- libraries/render-utils/src/GeometryCache.cpp | 1 - .../render-utils/src/MeshPartPayload.cpp | 152 +---------- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render/CMakeLists.txt | 6 +- libraries/render/src/render/ShapePipeline.cpp | 121 +++++++++ libraries/render/src/render/ShapePipeline.h | 4 + libraries/shared/src/MaterialMode.cpp | 24 ++ libraries/shared/src/MaterialMode.h | 7 + scripts/developer/tests/toolbarTest.js | 12 +- scripts/system/edit.js | 45 +++- scripts/system/html/css/edit-style.css | 49 +++- scripts/system/html/entityProperties.html | 45 ++++ scripts/system/html/js/entityProperties.js | 52 +++- scripts/system/libraries/entityList.js | 10 +- 35 files changed, 1291 insertions(+), 219 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/NewMaterialDialog.qml create mode 100644 libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp create mode 100644 libraries/entities-renderer/src/RenderableMaterialEntityItem.h create mode 100644 libraries/shared/src/MaterialMode.cpp diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index e94325f399..65dd871fb2 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -133,6 +133,17 @@ TabView { editTabView.currentIndex = 4 } } + + NewEntityButton { + icon: "icons/create-icons/94-model-01.svg" + text: "MATERIAL" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" } + }); + editTabView.currentIndex = 2 + } + } } HifiControls.Button { diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml new file mode 100644 index 0000000000..6d3477187b --- /dev/null +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -0,0 +1,174 @@ +// +// NewMaterialDialog.qml +// qml/hifi +// +// Created by Sam Gondelman on 1/17/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import "../../styles-uit" +import "../../controls-uit" +import "../dialogs" + +Rectangle { + id: newMaterialDialog + // width: parent.width + // height: parent.height + HifiConstants { id: hifi } + color: hifi.colors.baseGray; + signal sendToScript(var message); + property bool keyboardEnabled: false + property bool punctuationMode: false + property bool keyboardRasied: false + + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); + } + + Item { + id: column1 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + anchors.bottomMargin: 10 + anchors.topMargin: 10 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: keyboard.top + + Text { + id: text1 + text: qsTr("Material URL") + color: "#ffffff" + font.pixelSize: 12 + } + + TextInput { + id: materialURL + height: 20 + text: qsTr("") + color: "white" + anchors.top: text1.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + font.pixelSize: 12 + + onAccepted: { + newMaterialDialog.keyboardEnabled = false; + } + + MouseArea { + anchors.fill: parent + onClicked: { + newMaterialDialog.keyboardEnabled = HMD.active + parent.focus = true; + parent.forceActiveFocus(); + materialURL.cursorPosition = materialURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters); + } + } + } + + Rectangle { + id: textInputBox + color: "white" + anchors.fill: materialURL + opacity: 0.1 + } + + Row { + id: row1 + height: 400 + spacing: 30 + anchors.top: materialURL.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + Column { + id: column3 + height: 400 + spacing: 10 + + Text { + id: text3 + text: qsTr("Material Mode") + color: "#ffffff" + font.pixelSize: 12 + } + + ComboBox { + id: materialMode + property var materialArray: ["UV space material", + "3D projected material"] + + width: 200 + z: 100 + transformOrigin: Item.Center + model: materialArray + } + + Row { + id: row3 + width: 200 + height: 400 + spacing: 5 + + anchors.horizontalCenter: column3.horizontalCenter + anchors.horizontalCenterOffset: -20 + + Button { + id: button1 + text: qsTr("Add") + z: -1 + onClicked: { + newMaterialDialog.sendToScript({ + method: "newMaterialDialogAdd", + params: { + textInput: materialURL.text, + comboBox: materialMode.currentIndex + } + }); + } + } + + Button { + id: button2 + z: -1 + text: qsTr("Cancel") + onClicked: { + newMaterialDialog.sendToScript({method: "newMaterialDialogCancel"}) + } + } + } + } + } + } + + Keyboard { + id: keyboard + raised: parent.keyboardEnabled + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } +} diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index fb9aba636b..cbd2df86ad 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -25,6 +25,7 @@ #include "RenderableTextEntityItem.h" #include "RenderableWebEntityItem.h" #include "RenderableZoneEntityItem.h" +#include "RenderableMaterialEntityItem.h" using namespace render; @@ -247,6 +248,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; + case Type::Material: + result = make_renderer(entity); + break; + default: break; } @@ -388,4 +393,4 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { entity->deregisterChangeHandler(_changeHandlerId); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); -} +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 8eb82e2c6e..e54ae2f6b4 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -59,7 +59,6 @@ protected: virtual void onAddToScene(const EntityItemPointer& entity); virtual void onRemoveFromScene(const EntityItemPointer& entity); -protected: EntityRenderer(const EntityItemPointer& entity); ~EntityRenderer(); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp new file mode 100644 index 0000000000..83754c1c16 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -0,0 +1,238 @@ +// +// Created by Sam Gondelman on 1/18/2018 +// Copyright 2018 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 "RenderableMaterialEntityItem.h" + +using namespace render; +using namespace render::entities; + +bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { + if (entity->getMaterial() != _drawMaterial) { + return true; + } + return false; +} + +void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + withWriteLock([&] { + _drawMaterial = entity->getMaterial(); + _renderTransform = getModelTransform(); + const float MATERIAL_ENTITY_SCALE = 0.5f; + _renderTransform.postScale(MATERIAL_ENTITY_SCALE); + _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); + }); +} + +ItemKey MaterialEntityRenderer::getKey() { + ItemKey::Builder builder; + builder.withTypeShape(); + + if (!_visible) { + builder.withInvisible(); + } + + if (_drawMaterial) { + auto matKey = _drawMaterial->getKey(); + if (matKey.isTranslucent()) { + builder.withTransparent(); + } + } + + return builder.build(); +} + +ShapeKey MaterialEntityRenderer::getShapeKey() { + graphics::MaterialKey drawMaterialKey; + if (_drawMaterial) { + drawMaterialKey = _drawMaterial->getKey(); + } + + bool isTranslucent = drawMaterialKey.isTranslucent(); + bool hasTangents = drawMaterialKey.isNormalMap(); + bool hasSpecular = drawMaterialKey.isMetallicMap(); + bool hasLightmap = drawMaterialKey.isLightmapMap(); + bool isUnlit = drawMaterialKey.isUnlit(); + + ShapeKey::Builder builder; + builder.withMaterial(); + + if (isTranslucent) { + builder.withTranslucent(); + } + if (hasTangents) { + builder.withTangents(); + } + if (hasSpecular) { + builder.withSpecular(); + } + if (hasLightmap) { + builder.withLightmap(); + } + if (isUnlit) { + builder.withUnlit(); + } + + return builder.build(); +} + +glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) { + return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi)); +} + +glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) { + return glm::vec3(-glm::cos(theta) * glm::cos(phi), 0, -glm::cos(theta) * glm::sin(phi)); +} + +void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) { + buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z); + buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z); + buffer.push_back(uv.x); buffer.push_back(uv.y); +} + +void MaterialEntityRenderer::addTriangleFan(std::vector& buffer, int stack, int step) { + float v1 = ((float)stack) / STACKS; + float theta1 = v1 * M_PI; + glm::vec3 tip = getVertexPos(0, theta1); + float v2 = ((float)(stack + step)) / STACKS; + float theta2 = v2 * M_PI; + for (int i = 0; i < SLICES; i++) { + float u1 = ((float)i) / SLICES; + float u2 = ((float)(i + step)) / SLICES; + float phi1 = u1 * M_PI_TIMES_2; + float phi2 = u2 * M_PI_TIMES_2; + /* (flipped for negative step) + p1 + / \ + / \ + / \ + p3 ------ p2 + */ + + glm::vec3 pos2 = getVertexPos(phi2, theta2); + glm::vec3 pos3 = getVertexPos(phi1, theta2); + + glm::vec3 tan1 = getTangent(0, theta1); + glm::vec3 tan2 = getTangent(phi2, theta2); + glm::vec3 tan3 = getTangent(phi1, theta2); + + glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1); + glm::vec2 uv2 = glm::vec2(u2, v2); + glm::vec2 uv3 = glm::vec2(u1, v2); + + addVertex(buffer, tip, tan1, uv1); + addVertex(buffer, pos2, tan2, uv2); + addVertex(buffer, pos3, tan3, uv3); + + _numVertices += 3; + } +} + +int MaterialEntityRenderer::_numVertices = 0; +std::shared_ptr MaterialEntityRenderer::_streamFormat = nullptr; +std::shared_ptr MaterialEntityRenderer::_stream = nullptr; +std::shared_ptr MaterialEntityRenderer::_verticesBuffer = nullptr; + +void MaterialEntityRenderer::generateMesh() { + _streamFormat = std::make_shared(); + _stream = std::make_shared(); + _verticesBuffer = std::make_shared(); + + const int NUM_POS_COORDS = 3; + const int NUM_TANGENT_COORDS = 3; + const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float); + const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float); + + _streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + _streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + _streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET); + _streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); + + _stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride); + + std::vector vertexBuffer; + + // Top + addTriangleFan(vertexBuffer, 0, 1); + + // Middle section + for (int j = 1; j < STACKS - 1; j++) { + float v1 = ((float)j) / STACKS; + float v2 = ((float)(j + 1)) / STACKS; + float theta1 = v1 * M_PI; + float theta2 = v2 * M_PI; + for (int i = 0; i < SLICES; i++) { + float u1 = ((float)i) / SLICES; + float u2 = ((float)(i + 1)) / SLICES; + float phi1 = u1 * M_PI_TIMES_2; + float phi2 = u2 * M_PI_TIMES_2; + + /* + p2 ---- p3 + | / | + | / | + | / | + p1 ---- p4 + */ + + glm::vec3 pos1 = getVertexPos(phi1, theta2); + glm::vec3 pos2 = getVertexPos(phi1, theta1); + glm::vec3 pos3 = getVertexPos(phi2, theta1); + glm::vec3 pos4 = getVertexPos(phi2, theta2); + + glm::vec3 tan1 = getTangent(phi1, theta2); + glm::vec3 tan2 = getTangent(phi1, theta1); + glm::vec3 tan3 = getTangent(phi2, theta1); + glm::vec3 tan4 = getTangent(phi2, theta2); + + glm::vec2 uv1 = glm::vec2(u1, v2); + glm::vec2 uv2 = glm::vec2(u1, v1); + glm::vec2 uv3 = glm::vec2(u2, v1); + glm::vec2 uv4 = glm::vec2(u2, v2); + + addVertex(vertexBuffer, pos1, tan1, uv1); + addVertex(vertexBuffer, pos2, tan2, uv2); + addVertex(vertexBuffer, pos3, tan3, uv3); + + addVertex(vertexBuffer, pos3, tan3, uv3); + addVertex(vertexBuffer, pos4, tan4, uv4); + addVertex(vertexBuffer, pos1, tan1, uv1); + + _numVertices += 6; + } + } + + // Bottom + addTriangleFan(vertexBuffer, STACKS, -1); + + _verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data()); +} + +void MaterialEntityRenderer::doRender(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); + Q_ASSERT(args->_batch); + + gpu::Batch& batch = *args->_batch; + + batch.setModelTransform(_renderTransform); + + // bind the material + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_details._materialSwitches++; + + // Draw! + if (_numVertices == 0) { + generateMesh(); + } + + batch.setInputFormat(_streamFormat); + batch.setInputStream(0, *_stream); + batch.draw(gpu::TRIANGLES, _numVertices, 0); + + const int NUM_VERTICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE; +} diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h new file mode 100644 index 0000000000..166ad762cc --- /dev/null +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -0,0 +1,54 @@ +// +// Created by Sam Gondelman on 1/18/2018 +// Copyright 2018 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_RenderableMaterialEntityItem_h +#define hifi_RenderableMaterialEntityItem_h + +#include "RenderableEntityItem.h" + +#include + +class NetworkMaterial; + +namespace render { namespace entities { + +class MaterialEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + using Pointer = std::shared_ptr; +public: + MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {} + +private: + virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRender(RenderArgs* args) override; + + ItemKey getKey() override; + ShapeKey getShapeKey() override; + + Transform _renderTransform; + + std::shared_ptr _drawMaterial; + + static int _numVertices; + static std::shared_ptr _streamFormat; + static std::shared_ptr _stream; + static std::shared_ptr _verticesBuffer; + + void generateMesh(); + void addTriangleFan(std::vector& buffer, int stack, int step); + static glm::vec3 getVertexPos(float phi, float theta); + static glm::vec3 getTangent(float phi, float theta); + static void addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); + const int SLICES = 15; + const int STACKS = 9; + const float M_PI_TIMES_2 = 2.0f * M_PI; +}; + +} } +#endif // hifi_RenderableMaterialEntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f8f8859d73..77300be399 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -115,6 +115,17 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_STATIC_MESH); } +QHash stringToMaterialModeLookup; + +void addMaterialMode(MaterialMode mode) { + stringToMaterialModeLookup[MaterialModeHelpers::getNameForMaterialMode(mode)] = mode; +} + +void buildStringToMaterialModeLookup() { + addMaterialMode(UV); + addMaterialMode(PROJECTED); +} + QString getCollisionGroupAsString(uint8_t group) { switch (group) { case USER_COLLISION_GROUP_DYNAMIC: @@ -259,6 +270,21 @@ void EntityItemProperties::setSkyboxModeFromString(const QString& skyboxMode) { } } +QString EntityItemProperties::getMaterialModeAsString() const { + return MaterialModeHelpers::getNameForMaterialMode(_materialMode); +} + +void EntityItemProperties::setMaterialModeFromString(const QString& materialMode) { + if (stringToMaterialModeLookup.empty()) { + buildStringToMaterialModeLookup(); + } + auto materialModeItr = stringToMaterialModeLookup.find(materialMode.toLower()); + if (materialModeItr != stringToMaterialModeLookup.end()) { + _materialMode = materialModeItr.value(); + _materialModeChanged = true; + } +} + EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; @@ -329,7 +355,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); @@ -635,7 +660,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Materials if (_type == EntityTypes::Material) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_TYPE, materialMode); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_TYPE, materialMode, getMaterialModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); @@ -776,7 +801,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); @@ -1135,6 +1160,13 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float); ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); + ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); + // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString); @@ -2067,6 +2099,13 @@ void EntityItemProperties::markAllChanged() { //_alphaStartChanged = true; //_alphaFinishChanged = true; + _materialURLChanged = true; + _materialModeChanged = true; + _blendFactorChanged = true; + _priorityChanged = true; + _shapeIDChanged = true; + _materialBoundsChanged = true; + // Certifiable Properties _itemNameChanged = true; _itemDescriptionChanged = true; @@ -2390,6 +2429,24 @@ QList EntityItemProperties::listChangedProperties() { if (radiusFinishChanged()) { out += "radiusFinish"; } + if (materialURLChanged()) { + out += "materialURL"; + } + if (materialModeChanged()) { + out += "materialMode"; + } + if (blendFactorChanged()) { + out += "blendFactor"; + } + if (priorityChanged()) { + out += "priority"; + } + if (shapeIDChanged()) { + out += "shapeID"; + } + if (materialBoundsChanged()) { + out += "materialBounds"; + } // Certifiable Properties if (itemNameChanged()) { diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index c8c8a658ce..557a8476fa 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -242,6 +242,29 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } +inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = false; /// assume it can't be converted + QScriptValue x = v.property("x"); + QScriptValue y = v.property("y"); + QScriptValue z = v.property("z"); + QScriptValue w = v.property("w"); + if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { + glm::vec4 newValue(0); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + newValue.z = z.toVariant().toFloat(); + newValue.w = w.toVariant().toFloat(); + isValid = !glm::isnan(newValue.x) && + !glm::isnan(newValue.y) && + !glm::isnan(newValue.z) && + !glm::isnan(newValue.w); + if (isValid) { + return newValue; + } + } + return glm::vec4(0); +} + inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; AACube result; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 19daa11490..bbcc691879 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -10,6 +10,9 @@ #include "EntityItemProperties.h" +#include "QJsonDocument" +#include "QJsonArray" + EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); @@ -34,7 +37,7 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); @@ -55,6 +58,139 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } +bool MaterialEntityItem::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { + if (array.isArray()) { + QJsonArray colorArray = array.toArray(); + if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { + isSRGB = true; + if (colorArray.size() >= 4) { + if (colorArray[3].isBool()) { + isSRGB = colorArray[3].toBool(); + } + } + color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); + return true; + } + } + return false; +} + +void MaterialEntityItem::parseJSONMaterial(const QJsonObject& materialJSON) { + QString name = ""; + std::shared_ptr material = std::make_shared(); + for (auto& key : materialJSON.keys()) { + if (key == "name") { + auto nameJSON = materialJSON.value(key); + if (nameJSON.isString()) { + name = nameJSON.toString(); + } + } else if (key == "emissive") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setEmissive(color, isSRGB); + } + } else if (key == "opacity") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setOpacity(value.toDouble()); + } + } else if (key == "albedo") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setAlbedo(color, isSRGB); + } + } else if (key == "roughness") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setRoughness(value.toDouble()); + } + } else if (key == "fresnel") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setFresnel(color, isSRGB); + } + } else if (key == "metallic") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setMetallic(value.toDouble()); + } + } else if (key == "scattering") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setScattering(value.toDouble()); + } + } else if (key == "emissiveMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setEmissiveMap(value.toString()); + } + } else if (key == "albedoMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + bool useAlphaChannel = false; + auto opacityMap = materialJSON.find("opacityMap"); + if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { + useAlphaChannel = true; + } + material->setAlbedoMap(value.toString(), useAlphaChannel); + } + } else if (key == "roughnessMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), false); + } + } else if (key == "glossMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), true); + } + } else if (key == "metallicMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), false); + } + } else if (key == "specularMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), true); + } + } else if (key == "normalMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), false); + } + } else if (key == "bumpMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), true); + } + } else if (key == "occlusionMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setOcclusionMap(value.toString()); + } + } else if (key == "scatteringMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setScatteringMap(value.toString()); + } + } else if (key == "lightMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setLightmapMap(value.toString()); + } + } + } + _materials[name] = material; + _materialNames.push_back(name); +} + int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -66,8 +202,8 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, int, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, int, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); return bytesRead; @@ -96,25 +232,82 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, getMaterialMode()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); } void MaterialEntityItem::debugDump() const { quint64 now = usecTimestampNow(); - qCDebug(entities) << "MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " name:" << _name; - qCDebug(entities) << " url:" << _materialURL; - qCDebug(entities) << " material type:" << _materialMode; - qCDebug(entities) << " blend factor:" << _blendFactor; - qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent shape ID:" << _shapeID; - qCDebug(entities) << " material bounds:" << _materialBounds; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; + qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " material json:" << _materialURL; + qCDebug(entities) << " current material name:" << _currentMaterialName; + qCDebug(entities) << " material type:" << _materialMode; + qCDebug(entities) << " blend factor:" << _blendFactor; + qCDebug(entities) << " priority:" << _priority; + qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); + qCDebug(entities) << "MATERIAL EntityItem Ptr:" << this; } + +void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { + EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS); +} + +std::shared_ptr MaterialEntityItem::getMaterial() const { + auto material = _materials.find(_currentMaterialName); + if (material != _materials.end()) { + return material.value(); + } else { + return nullptr; + } +} + +void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { + if (materialURLString.startsWith("userData")) { + QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); + _materials.clear(); + _materialNames.clear(); + if (!materialJSON.isNull()) { + if (materialJSON.isArray()) { + QJsonArray materials = materialJSON.array(); + for (auto& material : materials) { + if (!material.isNull() && material.isObject()) { + parseJSONMaterial(material.toObject()); + } + } + } else if (materialJSON.isObject()) { + parseJSONMaterial(materialJSON.object()); + } + } + } + _materialURL = materialURLString; + + // TODO: if URL ends with ?string, set _currentMaterialName = string + + // Since our JSON changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); +} + +void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { + auto material = _materials.find(currentMaterialName); + if (material != _materials.end()) { + _currentMaterialName = currentMaterialName; + } else if (_materialNames.size() > 0) { + setCurrentMaterialName(_materialNames[0]); + } +} + +void MaterialEntityItem::setUserData(const QString& userData) { + EntityItem::setUserData(userData); + if (_materialURL.startsWith("userData")) { + // Trigger material update when user data changes + setMaterialURL(_materialURL); + } +} \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 094c94f24c..80fe226b68 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -46,25 +46,34 @@ public: void debugDump() const override; - const QString& getMaterialURL() { return _materialURL; } - void setMaterialURL(const QString& materialURL) { _materialURL = materialURL; } + virtual void setUnscaledDimensions(const glm::vec3& value) override; - MaterialMode getMaterialType() { return _materialMode; } - void setMaterialMode(MaterialMode mode); + QString getMaterialURL() const { return _materialURL; } + void setMaterialURL(const QString& materialURLString); - float getBlendFactor() { return _blendFactor; } + QString getCurrentMaterialName() const { return _currentMaterialName; } + void setCurrentMaterialName(const QString& currentMaterialName); + + MaterialMode getMaterialMode() const { return _materialMode; } + void setMaterialMode(MaterialMode mode) { _materialMode = mode; } + + float getBlendFactor() const { return _blendFactor; } void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } - int getPriority() { return _priority; } + int getPriority() const { return _priority; } void setPriority(int priority) { _priority = priority; } - int getShapeID() { return _shapeID; } + int getShapeID() const { return _shapeID; } void setShapeID(int shapeID) { _shapeID = shapeID; } - const glm::vec4& getMaterialBounds() { return _materialBounds; } + glm::vec4 getMaterialBounds() const { return _materialBounds; } void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } -protected: + std::shared_ptr getMaterial() const; + + void setUserData(const QString& userData) override; + +private: QString _materialURL; MaterialMode _materialMode { UV }; float _blendFactor { 1.0f }; @@ -72,7 +81,12 @@ protected: int _shapeID { 0 }; glm::vec4 _materialBounds { 0, 0, 1, 1 }; - //NetworkMaterial _material; + QHash> _materials; + std::vector _materialNames; + QString _currentMaterialName; + + void parseJSONMaterial(const QJsonObject& materialJSON); + static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); }; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index ea5bd331c9..6cc6b8472f 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -221,4 +221,4 @@ bool Material::calculateMaterialInfo() const { _hasCalculatedTextureInfo = allTextures; } return _hasCalculatedTextureInfo; -} +} \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 07f7283bfa..1fe3648838 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -425,7 +425,7 @@ bool Geometry::areTexturesLoaded() const { return true; } -const std::shared_ptr Geometry::getShapeMaterial(int partID) const { +const std::shared_ptr Geometry::getShapeMaterial(int partID) const { if ((partID >= 0) && (partID < (int)_meshParts->size())) { int materialID = _meshParts->at(partID)->materialID; if ((materialID >= 0) && (materialID < (int)_materials.size())) { @@ -491,6 +491,15 @@ void GeometryResourceWatcher::resourceRefreshed() { // _instance.reset(); } +NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : + Material(m), + _textures(m._textures), + _albedoTransform(m._albedoTransform), + _lightmapParams(m._lightmapParams), + _lightmapTransform(m._lightmapTransform), + _isOriginal(m._isOriginal) +{} + const QString NetworkMaterial::NO_TEXTURE = QString(); const QString& NetworkMaterial::getTextureName(MapChannel channel) { @@ -532,19 +541,85 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl } graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) { - const auto texture = DependencyManager::get()->getTexture(url, type); - _textures[channel].texture = texture; + auto textureCache = DependencyManager::get(); + if (textureCache) { + auto texture = textureCache->getTexture(url, type); + _textures[channel].texture = texture; - auto map = std::make_shared(); - map->setTextureSource(texture->_textureSource); + auto map = std::make_shared(); + if (texture) { + map->setTextureSource(texture->_textureSource); + emit textureFinished(); + } - return map; + return map; + } + return nullptr; +} + +void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); + if (map) { + map->setUseAlphaChannel(useAlphaChannel); + setTextureMap(MapChannel::ALBEDO_MAP, map); + } +} + +void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) { + auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP); + if (map) { + setTextureMap(MapChannel::NORMAL_MAP, map); + } +} + +void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) { + auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + if (map) { + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } +} + +void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) { + auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + if (map) { + setTextureMap(MapChannel::METALLIC_MAP, map); + } +} + +void NetworkMaterial::setOcclusionMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + if (map) { + setTextureMap(MapChannel::OCCLUSION_MAP, map); + } +} + +void NetworkMaterial::setEmissiveMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + if (map) { + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } +} + +void NetworkMaterial::setScatteringMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP); + if (map) { + setTextureMap(MapChannel::SCATTERING_MAP, map); + } +} + +void NetworkMaterial::setLightmapMap(const QString& url) { + auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (map) { + //map->setTextureTransform(_lightmapTransform); + //map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } } NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) : - graphics::Material(*material._material) + graphics::Material(*material._material), + _textures(MapChannel::NUM_MAP_CHANNELS) { - _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index f650b3f2eb..575f94f9bf 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -48,7 +48,7 @@ public: const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; } const GeometryMeshes& getMeshes() const { return *_meshes; } - const std::shared_ptr getShapeMaterial(int shapeID) const; + const std::shared_ptr getShapeMaterial(int shapeID) const; const QVariantMap getTextures() const; void setTextures(const QVariantMap& textureMap); @@ -131,7 +131,6 @@ private: Geometry::Pointer& _geometryRef; }; - /// Stores cached model geometries. class ModelCache : public ResourceCache, public Dependency { Q_OBJECT @@ -157,11 +156,26 @@ private: virtual ~ModelCache() = default; }; -class NetworkMaterial : public graphics::Material { +class NetworkMaterial : public QObject, public graphics::Material { + Q_OBJECT public: using MapChannel = graphics::Material::MapChannel; + NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {} NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); + NetworkMaterial(const NetworkMaterial& material); + + void setAlbedoMap(const QString& url, bool useAlphaChannel); + void setNormalMap(const QString& url, bool isBumpmap); + void setRoughnessMap(const QString& url, bool isGloss); + void setMetallicMap(const QString& url, bool isSpecular); + void setOcclusionMap(const QString& url); + void setEmissiveMap(const QString& url); + void setScatteringMap(const QString& url); + void setLightmapMap(const QString& url); + +signals: + void textureFinished(); protected: friend class Geometry; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8153dba3a5..3402758ef1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -275,6 +275,8 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh return QSharedPointer(texture, &Resource::deleter); } +int networkTexturePointerMetaTypeId = qRegisterMetaType>(); + NetworkTexture::NetworkTexture(const QUrl& url) : Resource(url), _type(), diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 742d003d02..6a88eb641a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -163,7 +163,6 @@ public: NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE, const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); - gpu::TexturePointer getTextureByHash(const std::string& hash); gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index a3ac995bcf..7ba7cca96d 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -340,14 +340,6 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& return resource; } - if (QThread::currentThread() != thread()) { - qCDebug(networking) << "Fetching asynchronously:" << url; - QMetaObject::invokeMethod(this, "getResource", - Q_ARG(QUrl, url), Q_ARG(QUrl, fallback)); - // Cannot use extra parameter as it might be freed before the invocation - return QSharedPointer(); - } - if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { return getResource(fallback, QUrl()); } @@ -358,6 +350,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& extra); resource->setSelf(resource); resource->setCache(this); + resource->moveToThread(qApp->thread()); connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); { QWriteLocker locker(&_resourcesLock); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 711aeb2cc2..98ad1ab323 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::SoftEntities); + return static_cast(EntityVersion::MaterialEntities); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 458666571c..e13809810c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -206,7 +206,8 @@ enum class EntityVersion : PacketVersion { OwnershipChallengeFix, ZoneLightInheritModes = 82, ZoneStageRemoved, - SoftEntities + SoftEntities, + MaterialEntities }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index ef4e98798f..7f8eb49101 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -33,6 +33,8 @@ #include #include +#include "MaterialMode.h" + #include "OctreeConstants.h" #include "OctreeElement.h" @@ -249,6 +251,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } @@ -257,6 +260,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; } static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result); static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result); diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index 3d213840dd..41a5bf5faf 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -38,7 +38,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { @@ -46,7 +46,7 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, locations, renderMode); + ModelMeshPartPayload::bindTransform(batch, renderMode); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 2337632047..3c0f90fcb5 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ public: void updateTransformForCauterizedMesh(const Transform& renderTransform); - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 1fd6ca2980..0d76b2c093 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1318,7 +1318,6 @@ void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, in renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id); } - void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner, const glm::vec4& color, int id) { diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index c506887fc4..dd5809093e 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -125,126 +125,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const { - if (!_drawMaterial) { - return; - } - - auto textureCache = DependencyManager::get(); - - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); - batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); - - const auto& materialKey = _drawMaterial->getKey(); - const auto& textureMaps = _drawMaterial->getTextureMaps(); - - int numUnlit = 0; - if (materialKey.isUnlit()) { - numUnlit++; - } - - if (!enableTextures) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return; - } - - // Albedo - if (materialKey.isAlbedoMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); - } - } - - // Roughness map - if (materialKey.isRoughnessMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - } - } - - // Normal map - if (materialKey.isNormalMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - } - } - - // Metallic map - if (materialKey.isMetallicMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - } - } - - // Occlusion map - if (materialKey.isOcclusionMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - } - } - - // Scattering map - if (materialKey.isScatteringMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - } - } - - // Emissive / Lightmap - if (materialKey.isLightmapMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); - } - } else if (materialKey.isEmissiveMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - } - } -} - -void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { batch.setModelTransform(_drawTransform); } @@ -252,23 +133,21 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Loca void MeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("MeshPartPayload::render"); + if (!args) { + return; + } + gpu::Batch& batch = *(args->_batch); - auto locations = args->_shapePipeline->locations; - assert(locations); - // Bind the model transform and the skinCLusterMatrices if needed - bindTransform(batch, locations, args->_renderMode); + bindTransform(batch, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); // apply material properties - bindMaterial(batch, locations, args->_enableTexturing); - - if (args) { - args->_details._materialSwitches++; - } + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_details._materialSwitches++; // Draw! { @@ -276,10 +155,8 @@ void MeshPartPayload::render(RenderArgs* args) { drawCall(batch); } - if (args) { - const int INDICES_PER_TRIANGLE = 3; - args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; - } + const int INDICES_PER_TRIANGLE = 3; + args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; } namespace render { @@ -500,7 +377,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { } } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { if (_clusterBuffer) { batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer); } @@ -515,17 +392,14 @@ void ModelMeshPartPayload::render(RenderArgs* args) { } gpu::Batch& batch = *(args->_batch); - auto locations = args->_shapePipeline->locations; - assert(locations); - bindTransform(batch, locations, args->_renderMode); + bindTransform(batch, args->_renderMode); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); // apply material properties - bindMaterial(batch, locations, args->_enableTexturing); - + args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 8160b9f009..7ec02ae7f0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -17,7 +17,6 @@ #include #include -#include #include @@ -49,8 +48,7 @@ public: // ModelMeshPartPayload functions to perform render void drawCall(gpu::Batch& batch) const; virtual void bindMesh(gpu::Batch& batch); - virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool enableTextures) const; - virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const; // Payload resource cached values Transform _drawTransform; @@ -63,7 +61,7 @@ public: mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; - std::shared_ptr _drawMaterial; + std::shared_ptr _drawMaterial; graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } @@ -109,7 +107,7 @@ public: // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch) override; - void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; void computeAdjustedLocalBound(const std::vector& clusterTransforms); diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 1d88c3e5f5..4f8673cde6 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -2,7 +2,9 @@ set(TARGET_NAME render) AUTOSCRIBE_SHADER_LIB(gpu graphics) setup_hifi_library() -# render needs octree only for getAccuracyAngle(float, int) -link_hifi_libraries(shared ktx gpu graphics octree) +# render needs octree only for getAccuracyAngle(float, int), and model-networking for TextureCache +link_hifi_libraries(shared ktx gpu graphics octree model-networking) +include_hifi_library_headers(networking) +include_hifi_library_headers(image) target_nsight() diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 4254280fa1..db4ff604ca 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -15,6 +15,8 @@ #include +#include + using namespace render; ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap; @@ -157,3 +159,122 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke return shapePipeline; } + +void ShapePipeline::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const { + if (!material) { + return; + } + + auto textureCache = DependencyManager::get(); + + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material->getSchemaBuffer()); + batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, material->getTexMapArrayBuffer()); + + const auto& materialKey = material->getKey(); + const auto& textureMaps = material->getTextureMaps(); + + int numUnlit = 0; + if (materialKey.isUnlit()) { + numUnlit++; + } + + if (!enableTextures) { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + return; + } + + // Albedo + if (materialKey.isAlbedoMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); + } + } + + // Roughness map + if (materialKey.isRoughnessMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + } + } + + // Normal map + if (materialKey.isNormalMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + } + } + + // Metallic map + if (materialKey.isMetallicMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + } + } + + // Occlusion map + if (materialKey.isOcclusionMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + } + } + + // Scattering map + if (materialKey.isScatteringMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); + + // texcoord are assumed to be the same has albedo + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + } + } + + // Emissive / Lightmap + if (materialKey.isLightmapMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + } + } else if (materialKey.isEmissiveMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + } + } +} diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index be77e2f95e..3e358e9ac2 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -18,6 +18,8 @@ #include "Args.h" +#include + namespace render { class Item; class ShapePlumber; @@ -294,6 +296,8 @@ public: void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape); + void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const; + protected: friend class ShapePlumber; diff --git a/libraries/shared/src/MaterialMode.cpp b/libraries/shared/src/MaterialMode.cpp new file mode 100644 index 0000000000..cb656a7bf7 --- /dev/null +++ b/libraries/shared/src/MaterialMode.cpp @@ -0,0 +1,24 @@ +// +// Created by Sam Gondelman on 1/17/2018 +// Copyright 2018 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 "MaterialMode.h" + +const char* materialModeNames[] = { + "uv", + "projected" +}; + +static const size_t MATERIAL_MODE_NAMES = (sizeof(materialModeNames) / sizeof((materialModeNames)[0])); + +QString MaterialModeHelpers::getNameForMaterialMode(MaterialMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + mode = (MaterialMode)0; + } + + return materialModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/MaterialMode.h b/libraries/shared/src/MaterialMode.h index 05c6d295a5..a933693f75 100644 --- a/libraries/shared/src/MaterialMode.h +++ b/libraries/shared/src/MaterialMode.h @@ -9,10 +9,17 @@ #ifndef hifi_MaterialMode_h #define hifi_MaterialMode_h +#include "QString" + enum MaterialMode { UV = 0, PROJECTED }; +class MaterialModeHelpers { +public: + static QString getNameForMaterialMode(MaterialMode mode); +}; + #endif // hifi_MaterialMode_h diff --git a/scripts/developer/tests/toolbarTest.js b/scripts/developer/tests/toolbarTest.js index e21fbd8e19..dfc97ebe39 100644 --- a/scripts/developer/tests/toolbarTest.js +++ b/scripts/developer/tests/toolbarTest.js @@ -11,7 +11,8 @@ var toolBar = (function() { newTextButton, newWebButton, newZoneButton, - newParticleButton + newParticleButton, + newMaterialButton var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/"); @@ -89,6 +90,13 @@ var toolBar = (function() { visible: false }); + newMaterialButton = toolBar.addButton({ + objectName: "newMaterialButton", + imageURL: toolIconUrl + "model-01.svg", + alpha: 0.9, + visible: false + }); + that.setActive(false); newModelButton.clicked(); } @@ -109,8 +117,8 @@ var toolBar = (function() { newTextButton.writeProperty('visible', doShow); newWebButton.writeProperty('visible', doShow); newZoneButton.writeProperty('visible', doShow); - newModelButton.writeProperty('visible', doShow); newParticleButton.writeProperty('visible', doShow); + newMaterialButton.writeProperty('visible', doShow); }; initialize(); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 87cd3e0faf..928d8ba1fa 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -251,7 +251,7 @@ var toolBar = (function () { // Align entity with Avatar orientation. properties.rotation = MyAvatar.orientation; - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. @@ -354,6 +354,9 @@ var toolBar = (function () { var SHAPE_TYPE_SPHERE = 5; var DYNAMIC_DEFAULT = false; + var MATERIAL_MODE_UV = 0; + var MATERIAL_MODE_PROJECTED = 1; + function handleNewModelDialogResult(result) { if (result) { var url = result.textInput; @@ -394,6 +397,28 @@ var toolBar = (function () { } } + function handleNewMaterialDialogResult(result) { + if (result) { + var json = result.textInput; + var materialMode; + switch (result.comboBox) { + case MATERIAL_MODE_PROJECTED: + materialMode = "projected"; + break; + default: + shapeType = "uv"; + } + + if (json) { + createNewEntity({ + type: "Material", + materialURL: json, + materialMode: materialMode + }); + } + } + } + function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.popFromStack(); @@ -404,6 +429,9 @@ var toolBar = (function () { case "newEntityButtonClicked": buttonHandlers[message.params.buttonName](); break; + case "newMaterialDialogAdd": + handleNewMaterialDialogResult(message.params); + break; } } @@ -614,6 +642,17 @@ var toolBar = (function () { }); }); + addButton("newMaterialButton", "model-01.svg", function () { + var MATERIAL_MODES = []; + MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material"; + MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material"; + var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV; + + // tablet version of new material dialog + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + tablet.pushOntoStack("NewMaterialDialog.qml"); + }); + that.setActive(false); } @@ -1983,7 +2022,7 @@ var PropertiesTool = function (opts) { ); } Entities.editEntity(selectionManager.selections[0], data.properties); - if (data.properties.name !== undefined || data.properties.modelURL !== undefined || + if (data.properties.name !== undefined || data.properties.modelURL !== undefined || data.properties.materialURL !== undefined || data.properties.visible !== undefined || data.properties.locked !== undefined) { entityListTool.sendUpdate(); } @@ -1994,7 +2033,7 @@ var PropertiesTool = function (opts) { parentSelectedEntities(); } else if (data.type === 'unparent') { unparentSelectedEntities(); - } else if (data.type === 'saveUserData'){ + } else if (data.type === 'saveUserData') { //the event bridge and json parsing handle our avatar id string differently. var actualID = data.id.split('"')[1]; Entities.editEntity(actualID, data.properties); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 736d42d593..96084f355f 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -448,7 +448,7 @@ input[type=checkbox]:checked + label:hover { border: 1.5pt solid black; } -.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section { +.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section, .material-section { display: table; } @@ -570,6 +570,7 @@ hr { .physical-group[collapsed="true"] ~ .physical-group, .behavior-group[collapsed="true"] ~ .behavior-group, .model-group[collapsed="true"] ~ .model-group, +.material-group[collapsed="true"] ~ .material-group, .light-group[collapsed="true"] ~ .light-group { display: none !important; } @@ -1386,7 +1387,7 @@ input#reset-to-natural-dimensions { } -#static-userdata{ +#static-userdata { display: none; z-index: 99; position: absolute; @@ -1397,7 +1398,7 @@ input#reset-to-natural-dimensions { background-color: #2e2e2e; } -#userdata-saved{ +#userdata-saved { margin-top:5px; font-size:16px; display:none; @@ -1454,6 +1455,9 @@ input#reset-to-natural-dimensions { order: 6; } +#properties-list.ShapeMenu #material, +#properties-list.BoxMenu #material, +#properties-list.SphereMenu #material, #properties-list.ShapeMenu #light, #properties-list.BoxMenu #light, #properties-list.SphereMenu #light, @@ -1490,6 +1494,7 @@ input#reset-to-natural-dimensions { } /* items to hide */ +#properties-list.ParticleEffectMenu #material, #properties-list.ParticleEffectMenu #base-color-section, #properties-list.ParticleEffectMenu #hyperlink, #properties-list.ParticleEffectMenu #light, @@ -1524,6 +1529,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.LightMenu #material, #properties-list.LightMenu #model, #properties-list.LightMenu #zone, #properties-list.LightMenu #text, @@ -1560,6 +1566,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.ModelMenu #material, #properties-list.ModelMenu #light, #properties-list.ModelMenu #zone, #properties-list.ModelMenu #text, @@ -1596,6 +1603,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.ZoneMenu #material, #properties-list.ZoneMenu #light, #properties-list.ZoneMenu #model, #properties-list.ZoneMenu #text, @@ -1632,6 +1640,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.WebMenu #material, #properties-list.WebMenu #light, #properties-list.WebMenu #model, #properties-list.WebMenu #zone, @@ -1669,6 +1678,7 @@ input#reset-to-natural-dimensions { order: 7; } /* sections to hide */ +#properties-list.TextMenu #material, #properties-list.TextMenu #light, #properties-list.TextMenu #model, #properties-list.TextMenu #zone, @@ -1681,6 +1691,39 @@ input#reset-to-natural-dimensions { display: none } +/* ----- Order of Menu items for Material ----- */ +#properties-list.MaterialMenu #general { + order: 1; +} +#properties-list.MaterialMenu #material { + order: 2; +} +#properties-list.MaterialMenu #spatial { + order: 3; +} +#properties-list.MaterialMenu #hyperlink { + order: 4; +} +#properties-list.MaterialMenu #behavior { + order: 5; +} + +/* sections to hide */ +#properties-list.MaterialMenu #physical, +#properties-list.MaterialMenu #collision-info, +#properties-list.MaterialMenu #model, +#properties-list.MaterialMenu #light, +#properties-list.MaterialMenu #zone, +#properties-list.MaterialMenu #text, +#properties-list.MaterialMenu #web { + display: none; +} +/* items to hide */ +#properties-list.MaterialMenu #shape-list, +#properties-list.MaterialMenu #base-color-section { + display: none +} + /* Currently always hidden */ #properties-list #polyvox { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index b93974ee77..93d22180c9 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -761,6 +761,51 @@ +
+ + MaterialM + +
+
+ + +
+
+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ +
+
+ diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 72092b66ca..af9d106149 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -24,7 +24,8 @@ var ICON_FOR_TYPE = { Zone: "o", PolyVox: "", Multiple: "", - PolyLine: "" + PolyLine: "", + Material: "" }; var EDITOR_TIMEOUT_DURATION = 1500; @@ -77,7 +78,6 @@ function disableProperties() { if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) { showStaticUserData(); } - } function showElements(els, show) { @@ -192,6 +192,19 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el }; } +function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) { + return function () { + var properties = {}; + properties[property] = { + x: elX.value, + y: elY.value, + z: elZ.value, + w: elW.value + }; + updateProperties(properties); + }; +} + function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var properties = {}; @@ -473,7 +486,6 @@ function bindAllNonJSONEditorElements() { } else { if ($('#userdata-editor').css('height') !== "0px") { saveJSONUserData(true); - } } }); @@ -621,6 +633,16 @@ function loaded() { var elModelTextures = document.getElementById("property-model-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures"); + var elMaterialURL = document.getElementById("property-material-url"); + var elMaterialMode = document.getElementById("property-material-mode"); + var elBlendFactor = document.getElementById("property-blend-factor"); + var elPriority = document.getElementById("property-priority"); + var elShapeID = document.getElementById("property-shape-id"); + var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); + var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); + var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); + var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); + var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -1105,6 +1127,17 @@ function loaded() { elXTextureURL.value = properties.xTextureURL; elYTextureURL.value = properties.yTextureURL; elZTextureURL.value = properties.zTextureURL; + } else if (properties.type === "Material") { + elMaterialURL.value = properties.materialURL; + elMaterialMode.value = properties.materialMode; + setDropdownText(elMaterialMode); + elBlendFactor.value = properties.blendFactor.toFixed(2); + elPriority.value = properties.priority; + elShapeID.value = properties.shapeID; + elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); + elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); + elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); + //elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); } if (properties.locked) { @@ -1375,6 +1408,19 @@ function loaded() { elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); + elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); + elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); + elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); + elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); + elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); + + var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', + elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); + elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); + elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); + elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight')); diff --git a/scripts/system/libraries/entityList.js b/scripts/system/libraries/entityList.js index 9d9689000e..d53766ab4e 100644 --- a/scripts/system/libraries/entityList.js +++ b/scripts/system/libraries/entityList.js @@ -77,18 +77,24 @@ EntityListTool = function(opts) { var properties = Entities.getEntityProperties(id); if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) { + var url = ""; + if (properties.type == "Model") { + url = properties.modelURL; + } else if (properties.type == "Material") { + url = properties.materialURL; + } entities.push({ id: id, name: properties.name, type: properties.type, - url: properties.type == "Model" ? properties.modelURL : "", + url: url, locked: properties.locked, visible: properties.visible, verticesCount: valueIfDefined(properties.renderInfo.verticesCount), texturesCount: valueIfDefined(properties.renderInfo.texturesCount), texturesSize: valueIfDefined(properties.renderInfo.texturesSize), hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent), - isBaked: properties.type == "Model" ? properties.modelURL.toLowerCase().endsWith(".baked.fbx") : false, + isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false, drawCalls: valueIfDefined(properties.renderInfo.drawCalls), hasScript: properties.script !== "" }); From 71a8e96d5a209a6435c480748559b9f05f1ef543 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 2 Feb 2018 18:14:12 -0800 Subject: [PATCH 16/83] fix several CR requests --- libraries/entities/src/EntityEditFilters.cpp | 29 ++++++++++---------- libraries/entities/src/EntityTree.cpp | 3 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 12bf1ac231..676b1ce518 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -41,8 +41,8 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { return zones; } -bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, - EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { +bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, + bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { // get the ids of all the zones (plus the global entity edit filter) that the position // lies within @@ -115,6 +115,15 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper zoneValues.setProperty("boundingBox", boundingBox); } } + + // If this is an add or delete, or original properties weren't requested + // there won't be original properties in the args, but zone properties need + // to be the fourth parameter, so we need to pad the args accordingly + int EXPECTED_ARGS = 3; + if (args.length() < EXPECTED_ARGS) { + args << QScriptValue(); + } + assert(args.length() == EXPECTED_ARGS); // we MUST have 3 args by now! args << zoneValues; } } @@ -308,17 +317,8 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); } } else if (wantsOriginalPropertiesValue.isArray()) { - auto length = wantsOriginalPropertiesValue.property("length").toInteger(); - for (int i = 0; i < length; i++) { - auto stringValue = wantsOriginalPropertiesValue.property(i).toString(); - if (!stringValue.isEmpty()) { - filterData.wantsOriginalProperties = true; - break; - } - } - if (filterData.wantsOriginalProperties) { - EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); - } + EntityPropertyFlagsFromScriptValue(wantsOriginalPropertiesValue, filterData.includedOriginalProperties); + filterData.wantsOriginalProperties = !filterData.includedOriginalProperties.isEmpty(); } // check to see if the filterFn has properties asking for Zone props @@ -336,9 +336,10 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { auto stringValue = wantsZonePropertiesValue.toString(); filterData.wantsZoneProperties = !stringValue.isEmpty(); if (filterData.wantsZoneProperties) { - EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); if (stringValue == "boundingBox") { filterData.wantsZoneBoundingBox = true; + } else { + EntityPropertyFlagsFromScriptValue(wantsZonePropertiesValue, filterData.includedZoneProperties); } } } else if (wantsZonePropertiesValue.isArray()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4cc643bae6..d5dc6399f4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1882,8 +1882,7 @@ bool EntityTree::shouldEraseEntity(EntityItemID entityID, const SharedNodePointe if (wantEditLogging() || wantTerseEditLogging()) { qCDebug(entities) << "User [" << sourceNode->getUUID() << "] deleting entity. ID:" << entityID; } - } - else if (wantEditLogging() || wantTerseEditLogging()) { + } else if (wantEditLogging() || wantTerseEditLogging()) { qCDebug(entities) << "User [" << sourceNode->getUUID() << "] attempted to deleteentity. ID:" << entityID << " Filter rejected erase."; } From d842e532ee61e80b444e860ee851651dddeda741 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 14:02:30 +1300 Subject: [PATCH 17/83] Remove Window.customPrompt() from JavaScript API --- interface/src/Application.cpp | 1 - .../scripting/WindowScriptingInterface.cpp | 22 ------------------- .../src/scripting/WindowScriptingInterface.h | 20 ----------------- libraries/ui/src/OffscreenUi.cpp | 17 -------------- libraries/ui/src/OffscreenUi.h | 2 -- 5 files changed, 62 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a54c94d53..31c0b3555c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5857,7 +5857,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe DependencyManager::get().data()->setToolbarScriptingInterface(toolbarScriptingInterface); scriptEngine->registerGlobalObject("Window", DependencyManager::get().data()); - qScriptRegisterMetaType(scriptEngine.data(), CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue); scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter, "Window"); // register `location` on the global object. diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index d419d7484b..65873dc1dc 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -32,20 +32,6 @@ static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation"; static const QString LAST_BROWSE_ASSETS_LOCATION_SETTING = "LastBrowseAssetsLocation"; -QScriptValue CustomPromptResultToScriptValue(QScriptEngine* engine, const CustomPromptResult& result) { - if (!result.value.isValid()) { - return QScriptValue::UndefinedValue; - } - - Q_ASSERT(result.value.userType() == qMetaTypeId()); - return engine->toScriptValue(result.value.toMap()); -} - -void CustomPromptResultFromScriptValue(const QScriptValue& object, CustomPromptResult& result) { - result.value = object.toVariant(); -} - - WindowScriptingInterface::WindowScriptingInterface() { const DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged); @@ -140,14 +126,6 @@ void WindowScriptingInterface::disconnectedFromDomain() { emit domainChanged(""); } -CustomPromptResult WindowScriptingInterface::customPrompt(const QVariant& config) { - CustomPromptResult result; - bool ok = false; - auto configMap = config.toMap(); - result.value = OffscreenUi::getCustomInfo(OffscreenUi::ICON_NONE, "", configMap, &ok); - return ok ? result : CustomPromptResult(); -} - QString fixupPathForMac(const QString& directory) { // On OS X `directory` does not work as expected unless a file is included in the path, so we append a bogus // filename if the directory is valid. diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index dc71611c5b..d5f40b83c6 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -22,17 +22,6 @@ #include -class CustomPromptResult { -public: - QVariant value; -}; - -Q_DECLARE_METATYPE(CustomPromptResult); - -QScriptValue CustomPromptResultToScriptValue(QScriptEngine* engine, const CustomPromptResult& result); -void CustomPromptResultFromScriptValue(const QScriptValue& object, CustomPromptResult& result); - - /**jsdoc * The Window API provides various facilities not covered elsewhere: window dimensions, window focus, normal or entity camera * view, clipboard, announcements, user connections, common dialog boxes, snapshots, file import, domain changes, domain @@ -142,15 +131,6 @@ public slots: */ void promptAsync(const QString& message = "", const QString& defaultText = ""); - /**jsdoc - * Prompt the user for input in a custom, modal dialog. - * @deprecated This function is deprecated and will soon be removed. - * @function Window.customPrompt - * @param {object} config - Configures the modal dialog. - * @returns {object} The user's response. - */ - CustomPromptResult customPrompt(const QVariant& config); - /**jsdoc * Prompt the user to choose a directory. Displays a modal dialog that navigates the directory tree. * @function Window.browseDir diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 221f5013bf..f28e1954e4 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -384,19 +384,6 @@ QString OffscreenUi::getItem(const Icon icon, const QString& title, const QStrin return result.toString(); } -QVariant OffscreenUi::getCustomInfo(const Icon icon, const QString& title, const QVariantMap& config, bool* ok) { - if (ok) { - *ok = false; - } - - QVariant result = DependencyManager::get()->customInputDialog(icon, title, config); - if (ok && result.isValid()) { - *ok = true; - } - - return result; -} - ModalDialogListener* OffscreenUi::getTextAsync(const Icon icon, const QString& title, const QString& label, const QString& text) { return DependencyManager::get()->inputDialogAsync(icon, title, label, text); } @@ -418,10 +405,6 @@ ModalDialogListener* OffscreenUi::getItemAsync(const Icon icon, const QString& t return inputDialogListener; } -ModalDialogListener* OffscreenUi::getCustomInfoAsync(const Icon icon, const QString& title, const QVariantMap& config) { - return DependencyManager::get()->customInputDialogAsync(icon, title, config); -} - QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { QVariant result; diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index ab3a209820..8e10ebde08 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -231,10 +231,8 @@ public: static QString getText(const Icon icon, const QString & title, const QString & label, const QString & text = QString(), bool * ok = 0); static QString getItem(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0); - static QVariant getCustomInfo(const Icon icon, const QString& title, const QVariantMap& config, bool* ok = 0); static ModalDialogListener* getTextAsync(const Icon icon, const QString & title, const QString & label, const QString & text = QString()); static ModalDialogListener* getItemAsync(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true); - static ModalDialogListener* getCustomInfoAsync(const Icon icon, const QString& title, const QVariantMap& config); unsigned int getMenuUserDataId() const; QList &getModalDialogListeners(); From 8e2a3e8c99ff2bc1f36349db28d5d9a92d3dbfc7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 14:15:48 +1300 Subject: [PATCH 18/83] Remove Overlays.getOverlayObject() from JavaScript API --- interface/src/ui/overlays/Overlays.cpp | 15 --------------- interface/src/ui/overlays/Overlays.h | 9 --------- scripts/system/libraries/WebTablet.js | 4 ---- 3 files changed, 28 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 6898b5ed2b..35274e4fbe 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -388,21 +388,6 @@ QString Overlays::getOverlayType(OverlayID overlayId) { return ""; } -QObject* Overlays::getOverlayObject(OverlayID id) { - if (QThread::currentThread() != thread()) { - QObject* result; - PROFILE_RANGE(script, __FUNCTION__); - BLOCKING_INVOKE_METHOD(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id)); - return result; - } - - Overlay::Pointer thisOverlay = getOverlay(id); - if (thisOverlay) { - return qobject_cast(&(*thisOverlay)); - } - return nullptr; -} - OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { if (!_enabled) { return UNKNOWN_OVERLAY_ID; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 113ee92b80..2da375f6e4 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -227,15 +227,6 @@ public slots: */ QString getOverlayType(OverlayID overlayId); - /**jsdoc - * Get the overlay script object. - * @function Overlays.getOverlayObject - * @deprecated This function is deprecated and will soon be removed. - * @param {Uuid} overlayID - The ID of the overlay to get the script object of. - * @returns {object} The script object for the overlay if found. - */ - QObject* getOverlayObject(OverlayID id); - /**jsdoc * Get the ID of the 2D overlay at a particular point on the screen or HUD. * @function Overlays.getOverlayAtPoint diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 05b4963280..2b7c0343e2 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -305,10 +305,6 @@ WebTablet.prototype.setScriptURL = function (scriptURL) { Overlays.editOverlay(this.webOverlayID, { scriptURL: scriptURL }); }; -WebTablet.prototype.getOverlayObject = function () { - return Overlays.getOverlayObject(this.webOverlayID); -}; - WebTablet.prototype.setWidth = function (width) { // imported from libraries/utils.js resizeTablet(width); From dd5cc8677d5a86f0772170b407916ecd2a84db63 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 14:46:49 +1300 Subject: [PATCH 19/83] Remove Overlays.findRayIntersectionVector() from JavaScript API --- interface/src/ui/overlays/Overlays.h | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 2da375f6e4..3efe94c206 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -98,6 +98,11 @@ public: OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } OverlayID addOverlay(const Overlay::Pointer& overlay); + RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly = false, bool collidableOnly = false); + bool mousePressEvent(QMouseEvent* event); bool mouseDoublePressEvent(QMouseEvent* event); bool mouseReleaseEvent(QMouseEvent* event); @@ -347,28 +352,6 @@ public slots: bool visibleOnly = false, bool collidableOnly = false); - // TODO: Apart from the name, this function signature on JavaScript is identical to that of findRayIntersection() and should - // probably be removed from the JavaScript API so as not to cause confusion. - /**jsdoc - * Find the closest 3D overlay intersected by a {@link PickRay}. - * @function Overlays.findRayIntersectionVector - * @deprecated Use {@link Overlays.findRayIntersection} instead; it has identical parameters and results. - * @param {PickRay} pickRay - The PickRay to use for finding overlays. - * @param {boolean} [precisionPicking=false] - Unused; exists to match Entity API. - * @param {Array.} [overlayIDsToInclude=[]] - Whitelist for intersection test. If empty then the result isn't limited - * to overlays in the list. - * @param {Array.} [overlayIDsToExclude=[]] - Blacklist for intersection test. If empty then the result doesn't - * exclude overlays in the list. - * @param {boolean} [visibleOnly=false] - Unused; exists to match Entity API. - * @param {boolean} [collidableOnly=false] - Unused; exists to match Entity API. - * @returns {Overlays.RayToOverlayIntersectionResult} The closest 3D overlay intersected by pickRay, taking - * into account overlayIDsToInclude and overlayIDsToExclude if they're not empty. - */ - RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToDiscard, - bool visibleOnly = false, bool collidableOnly = false); - /**jsdoc * Return a list of 3D overlays with bounding boxes that touch a search sphere. * @function Overlays.findOverlays From 0c0734a255a181cc6c5ee1f1d62f972d894d01cf Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 14:54:14 +1300 Subject: [PATCH 20/83] Remove unused Overlays property, borderSize, and associated code --- interface/src/Application.cpp | 1 - interface/src/ui/overlays/Cube3DOverlay.cpp | 13 ------------- interface/src/ui/overlays/Cube3DOverlay.h | 5 ----- interface/src/ui/overlays/Shape3DOverlay.cpp | 12 ------------ interface/src/ui/overlays/Shape3DOverlay.h | 5 ----- scripts/developer/debugging/queryAACubeInspector.js | 1 - scripts/system/libraries/entitySelectionTool.js | 12 ++++-------- 7 files changed, 4 insertions(+), 45 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 31c0b3555c..bc567c0452 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4717,7 +4717,6 @@ void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm if (_keyboardFocusHighlightID == UNKNOWN_OVERLAY_ID || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) { _keyboardFocusHighlight = std::make_shared(); _keyboardFocusHighlight->setAlpha(1.0f); - _keyboardFocusHighlight->setBorderSize(1.0f); _keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 }); _keyboardFocusHighlight->setIsSolid(false); _keyboardFocusHighlight->setPulseMin(0.5); diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index f13f782482..29c4f592f5 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -125,13 +125,6 @@ Cube3DOverlay* Cube3DOverlay::createClone() const { void Cube3DOverlay::setProperties(const QVariantMap& properties) { Volume3DOverlay::setProperties(properties); - - auto borderSize = properties["borderSize"]; - - if (borderSize.isValid()) { - float value = borderSize.toFloat(); - setBorderSize(value); - } } /**jsdoc @@ -177,14 +170,8 @@ void Cube3DOverlay::setProperties(const QVariantMap& properties) { * parentID is an avatar skeleton. A value of 65535 means "no joint". * * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: scale, size. - * - * @property {number} borderSize - Not used. */ QVariant Cube3DOverlay::getProperty(const QString& property) { - if (property == "borderSize") { - return _borderSize; - } - return Volume3DOverlay::getProperty(property); } diff --git a/interface/src/ui/overlays/Cube3DOverlay.h b/interface/src/ui/overlays/Cube3DOverlay.h index e7b58ad911..5d83cbb2c1 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.h +++ b/interface/src/ui/overlays/Cube3DOverlay.h @@ -29,10 +29,6 @@ public: virtual Cube3DOverlay* createClone() const override; - float getBorderSize() const { return _borderSize; } - - void setBorderSize(float value) { _borderSize = value; } - void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; @@ -40,7 +36,6 @@ protected: Transform evalRenderTransform() override; private: - float _borderSize; // edges on a cube std::array _geometryIds; }; diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index 97342a80ab..64acdcccdb 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -99,13 +99,6 @@ void Shape3DOverlay::setProperties(const QVariantMap& properties) { } } } - - auto borderSize = properties["borderSize"]; - - if (borderSize.isValid()) { - float value = borderSize.toFloat(); - setBorderSize(value); - } } /**jsdoc @@ -153,13 +146,8 @@ void Shape3DOverlay::setProperties(const QVariantMap& properties) { * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: scale, size. * * @property {Shape} shape=Hexagon - The geometrical shape of the overlay. - * @property {number} borderSize - Not used. */ QVariant Shape3DOverlay::getProperty(const QString& property) { - if (property == "borderSize") { - return _borderSize; - } - if (property == "shape") { return shapeStrings[_shape]; } diff --git a/interface/src/ui/overlays/Shape3DOverlay.h b/interface/src/ui/overlays/Shape3DOverlay.h index 7fc95ec981..0196c707d7 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.h +++ b/interface/src/ui/overlays/Shape3DOverlay.h @@ -30,10 +30,6 @@ public: virtual Shape3DOverlay* createClone() const override; - float getBorderSize() const { return _borderSize; } - - void setBorderSize(float value) { _borderSize = value; } - void setProperties(const QVariantMap& properties) override; QVariant getProperty(const QString& property) override; @@ -41,7 +37,6 @@ protected: Transform evalRenderTransform() override; private: - float _borderSize; GeometryCache::Shape _shape { GeometryCache::Hexagon }; }; diff --git a/scripts/developer/debugging/queryAACubeInspector.js b/scripts/developer/debugging/queryAACubeInspector.js index 2d585ffce4..d8a87c3cf5 100644 --- a/scripts/developer/debugging/queryAACubeInspector.js +++ b/scripts/developer/debugging/queryAACubeInspector.js @@ -40,7 +40,6 @@ function updateOverlay(entityID, queryAACube) { blue: 255 }, alpha: 1, - // borderSize: ..., solid: false }); } diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index b8ba146757..4133447f97 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -339,8 +339,7 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - drawInFront: true, - borderSize: 1.4 + drawInFront: true }; var grabberPropertiesEdge = { @@ -351,8 +350,7 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - drawInFront: true, - borderSize: 1.4 + drawInFront: true }; var grabberPropertiesFace = { @@ -363,8 +361,7 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - drawInFront: true, - borderSize: 1.4 + drawInFront: true }; var grabberPropertiesCloner = { @@ -375,8 +372,7 @@ SelectionDisplay = (function() { solid: grabberSolid, visible: false, dashed: false, - drawInFront: true, - borderSize: 1.4 + drawInFront: true }; var spotLightLineProperties = { From 42498314f1d783727707a0a8b9b3c54f31580371 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 14:59:06 +1300 Subject: [PATCH 21/83] Remove further unused variable noticed in passing --- interface/src/ui/ApplicationOverlay.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index b36b4f02df..23055cf246 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -42,8 +42,6 @@ private: int _domainStatusBorder; int _magnifierBorder; - ivec2 _previousBorderSize{ -1 }; - gpu::TexturePointer _uiTexture; gpu::TexturePointer _overlayDepthTexture; gpu::TexturePointer _overlayColorTexture; From efddec621f4f98581227285529fec80ebfb986f2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 15:16:20 +1300 Subject: [PATCH 22/83] Remove Menu.addActionGroup() and removeActionGroup() from JavaScript API --- interface/src/Menu.cpp | 1 + .../src/scripting/MenuScriptingInterface.cpp | 16 ---------------- .../src/scripting/MenuScriptingInterface.h | 7 ------- libraries/ui/src/ui/Menu.cpp | 18 ------------------ libraries/ui/src/ui/Menu.h | 3 --- 5 files changed, 1 insertion(+), 44 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f3d8ea2344..464de87fdb 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -210,6 +210,7 @@ Menu::Menu() { auto avatarEntitiesBookmarks = DependencyManager::get(); avatarEntitiesBookmarks->setupMenus(this, avatarMenu); + // Display menu ---------------------------------- // FIXME - this is not yet matching Alan's spec because it doesn't have // menus for "2D"/"3D" - we need to add support for detecting the appropriate diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index d9372978e8..551cb36e65 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -94,22 +94,6 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& return result; } -void MenuScriptingInterface::addActionGroup(const QString& groupName, const QStringList& actionList, - const QString& selected) { - static const char* slot = SLOT(menuItemTriggered()); - QMetaObject::invokeMethod(Menu::getInstance(), "addActionGroup", - Q_ARG(const QString&, groupName), - Q_ARG(const QStringList&, actionList), - Q_ARG(const QString&, selected), - Q_ARG(QObject*, this), - Q_ARG(const char*, slot)); -} - -void MenuScriptingInterface::removeActionGroup(const QString& groupName) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeActionGroup", - Q_ARG(const QString&, groupName)); -} - bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { if (QThread::currentThread() == qApp->thread()) { return Menu::getInstance()->isOptionChecked(menuOption); diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index 59cfc76d21..b4f6178d33 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -163,13 +163,6 @@ public slots: */ bool menuItemExists(const QString& menuName, const QString& menuitem); - /** - * TODO: Not working; don't document until fixed. - */ - void addActionGroup(const QString& groupName, const QStringList& actionList, - const QString& selected = QString()); - void removeActionGroup(const QString& groupName); - /**jsdoc * Check whether a checkable menu item is checked. * @function Menu.isOptionChecked diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 4e61eba28f..577e2564a7 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -539,24 +539,6 @@ void Menu::setGroupingIsVisible(const QString& grouping, bool isVisible) { QMenuBar::repaint(); } -void Menu::addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected, QObject* receiver, const char* slot) { - auto menu = addMenu(groupName); - - QActionGroup* actionGroup = new QActionGroup(menu); - actionGroup->setExclusive(true); - - for (auto action : actionList) { - auto item = addCheckableActionToQMenuAndActionHash(menu, action, 0, action == selected, receiver, slot); - actionGroup->addAction(item); - } - - QMenuBar::repaint(); -} - -void Menu::removeActionGroup(const QString& groupName) { - removeMenu(groupName); -} - MenuWrapper::MenuWrapper(ui::Menu& rootMenu, QMenu* menu) : _rootMenu(rootMenu), _realMenu(menu) { auto offscreenUi = DependencyManager::get(); offscreenUi->addMenuInitializer([=](VrMenu* vrMenu) { diff --git a/libraries/ui/src/ui/Menu.h b/libraries/ui/src/ui/Menu.h index 25f8f74063..4ca69b44e6 100644 --- a/libraries/ui/src/ui/Menu.h +++ b/libraries/ui/src/ui/Menu.h @@ -110,9 +110,6 @@ public slots: void removeSeparator(const QString& menuName, const QString& separatorName); void removeMenuItem(const QString& menuName, const QString& menuitem); bool menuItemExists(const QString& menuName, const QString& menuitem); - void addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected = QString(), - QObject* receiver = nullptr, const char* slot = nullptr); - void removeActionGroup(const QString& groupName); bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); From 615e54620b3a0e8da9160a37b956ff012b5943d2 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sun, 4 Feb 2018 15:38:33 +1300 Subject: [PATCH 23/83] Remove Menu.isInfoViewVisible() and closeInfoView() from JavaScript API --- .../src/scripting/MenuScriptingInterface.cpp | 16 ---------------- interface/src/scripting/MenuScriptingInterface.h | 6 ------ libraries/ui/src/ui/Menu.cpp | 10 ---------- libraries/ui/src/ui/Menu.h | 3 --- scripts/system/help.js | 10 ---------- 5 files changed, 45 deletions(-) diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 551cb36e65..d6dc2fa703 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -131,19 +131,3 @@ void MenuScriptingInterface::setMenuEnabled(const QString& menuOption, bool isCh void MenuScriptingInterface::triggerOption(const QString& menuOption) { QMetaObject::invokeMethod(Menu::getInstance(), "triggerOption", Q_ARG(const QString&, menuOption)); } - -void MenuScriptingInterface::closeInfoView(const QString& path) { - QMetaObject::invokeMethod(Menu::getInstance(), "closeInfoView", Q_ARG(const QString&, path)); -} - -bool MenuScriptingInterface::isInfoViewVisible(const QString& path) { - if (QThread::currentThread() == qApp->thread()) { - return Menu::getInstance()->isInfoViewVisible(path); - } - - bool result; - BLOCKING_INVOKE_METHOD(Menu::getInstance(), "isInfoViewVisible", - Q_RETURN_ARG(bool, result), Q_ARG(const QString&, path)); - return result; -} - diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index b4f6178d33..649c444eaf 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -215,12 +215,6 @@ public slots: */ void setMenuEnabled(const QString& menuName, bool isEnabled); - /** - * TODO: Not used or useful; will not document until used. - */ - void closeInfoView(const QString& path); - bool isInfoViewVisible(const QString& path); - signals: /**jsdoc * Triggered when a menu item is clicked (or triggered by {@link Menu.triggerOption}). diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 577e2564a7..d4566dc151 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -268,16 +268,6 @@ bool Menu::isOptionChecked(const QString& menuOption) const { return false; } -void Menu::closeInfoView(const QString& path) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->hide(path); -} - -bool Menu::isInfoViewVisible(const QString& path) { - auto offscreenUi = DependencyManager::get(); - return offscreenUi->isVisible(path); -} - void Menu::triggerOption(const QString& menuOption) { QAction* action = _actionHash.value(menuOption); if (action) { diff --git a/libraries/ui/src/ui/Menu.h b/libraries/ui/src/ui/Menu.h index 4ca69b44e6..2977a5330a 100644 --- a/libraries/ui/src/ui/Menu.h +++ b/libraries/ui/src/ui/Menu.h @@ -122,9 +122,6 @@ public slots: void toggleDeveloperMenus(); void toggleAdvancedMenus(); - bool isInfoViewVisible(const QString& path); - void closeInfoView(const QString& path); - void triggerOption(const QString& menuOption); static bool isSomeSubmenuShown() { return _isSomeSubmenuShown; } diff --git a/scripts/system/help.js b/scripts/system/help.js index 9ab7fa3fb3..494b0a2cdb 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -47,22 +47,12 @@ button.clicked.connect(onClicked); tablet.screenChanged.connect(onScreenChanged); - var POLL_RATE = 500; - var interval = Script.setInterval(function () { - var visible = Menu.isInfoViewVisible('InfoView_html/help.html'); - if (visible !== enabled) { - enabled = visible; - button.editProperties({isActive: enabled}); - } - }, POLL_RATE); - Script.scriptEnding.connect(function () { if (onHelpScreen) { tablet.gotoHomeScreen(); } button.clicked.disconnect(onClicked); tablet.screenChanged.disconnect(onScreenChanged); - Script.clearInterval(interval); if (tablet) { tablet.removeButton(button); } From e3f9cce6e6a3548c917f909b473f3bbb9bcfe105 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 6 Feb 2018 12:14:33 +1300 Subject: [PATCH 24/83] Fix Record app dialog not always opening successfully --- .../marketplace/record/html/js/record.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/unpublishedScripts/marketplace/record/html/js/record.js b/unpublishedScripts/marketplace/record/html/js/record.js index aae4d1c89a..39278e9d7e 100644 --- a/unpublishedScripts/marketplace/record/html/js/record.js +++ b/unpublishedScripts/marketplace/record/html/js/record.js @@ -252,16 +252,17 @@ function onFinishOnOpenClicked() { } function signalBodyLoaded() { - EventBridge.emitWebEvent(JSON.stringify({ - type: EVENT_BRIDGE_TYPE, - action: BODY_LOADED_ACTION - })); + var EVENTBRIDGE_OPEN_DELAY = 500; // Delay required to ensure EventBridge is ready for use. + setTimeout(function () { + EventBridge.scriptEventReceived.connect(onScriptEventReceived); + EventBridge.emitWebEvent(JSON.stringify({ + type: EVENT_BRIDGE_TYPE, + action: BODY_LOADED_ACTION + })); + }, EVENTBRIDGE_OPEN_DELAY); } function onBodyLoaded() { - - EventBridge.scriptEventReceived.connect(onScriptEventReceived); - elRecordings = document.getElementById("recordings"); elRecordingsTable = document.getElementById("recordings-table"); From 7f6471fcd189ad04feaa3cec153583bb3752df69 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 6 Feb 2018 13:24:41 +1300 Subject: [PATCH 25/83] Fix recording just made not being automatically played back --- unpublishedScripts/marketplace/record/record.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unpublishedScripts/marketplace/record/record.js b/unpublishedScripts/marketplace/record/record.js index 68c7ea3f5a..dda78dbd02 100644 --- a/unpublishedScripts/marketplace/record/record.js +++ b/unpublishedScripts/marketplace/record/record.js @@ -139,7 +139,8 @@ } function setMappingCallback(status) { - if (status !== "") { + // FIXME: "" is for RC < 63, null is for RC >= 63. Remove the former when RC63 is no longer used. + if (status !== "" && status !== null) { error("Error mapping recording to " + mappingPath + " on Asset Server!", status); return; } From 75cf22ca7fe7bab1c59ca08d4d99bccf0eba9cf6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 7 Feb 2018 09:45:21 +1300 Subject: [PATCH 26/83] Remove support for old High Fidelity versions --- unpublishedScripts/marketplace/record/record.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unpublishedScripts/marketplace/record/record.js b/unpublishedScripts/marketplace/record/record.js index dda78dbd02..08400dbb85 100644 --- a/unpublishedScripts/marketplace/record/record.js +++ b/unpublishedScripts/marketplace/record/record.js @@ -139,8 +139,7 @@ } function setMappingCallback(status) { - // FIXME: "" is for RC < 63, null is for RC >= 63. Remove the former when RC63 is no longer used. - if (status !== "" && status !== null) { + if (status !== null) { error("Error mapping recording to " + mappingPath + " on Asset Server!", status); return; } From adb6f66a05a7ce4d9181712e5c24b8222983e70b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 8 Feb 2018 09:51:48 +1300 Subject: [PATCH 27/83] Handle tablet entities and overlays not being available --- scripts/system/audio.js | 5 +++-- .../system/controllers/controllerDispatcher.js | 2 +- .../controllers/controllerModules/inEditMode.js | 7 ++++--- .../controllerModules/inVREditMode.js | 5 +++-- .../controllerModules/nearParentGrabOverlay.js | 4 ++-- .../controllers/controllerModules/stylusInput.js | 4 ++-- scripts/system/controllers/grab.js | 5 ++++- scripts/system/edit.js | 8 ++++---- scripts/system/help.js | 5 ++--- scripts/system/libraries/WebTablet.js | 5 ++++- scripts/system/libraries/entitySelectionTool.js | 11 ++++++++--- scripts/system/libraries/utils.js | 14 ++++++++++++++ scripts/system/marketplaces/marketplaces.js | 5 +++-- scripts/system/menu.js | 5 +++-- scripts/system/tablet-ui/tabletUI.js | 16 ++++++++-------- scripts/system/tablet-users.js | 5 ++--- .../marketplace/shapes/modules/laser.js | 12 +++++++++++- 17 files changed, 78 insertions(+), 40 deletions(-) diff --git a/scripts/system/audio.js b/scripts/system/audio.js index a93177ca38..ee82c0c6ea 100644 --- a/scripts/system/audio.js +++ b/scripts/system/audio.js @@ -42,8 +42,9 @@ function onClicked() { // for toolbar-mode: go back to home screen, this will close the window. tablet.gotoHomeScreen(); } else { - var entity = HMD.tabletID; - Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + if (HMD.tabletID) { + Entities.editEntity(HMD.tabletID, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + } tablet.loadQMLSource(AUDIO_QML_SOURCE); } } diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 16f1d086b7..b2455b3f5a 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -146,7 +146,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; this.setIgnorePointerItems = function() { - if (HMD.tabletID !== this.tabletID) { + if (HMD.tabletID && HMD.tabletID !== this.tabletID) { this.tabletID = HMD.tabletID; Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist); Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 763258573d..202290f2df 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -32,7 +32,7 @@ Script.include("/~/system/libraries/utils.js"); this.nearTablet = function(overlays) { for (var i = 0; i < overlays.length; i++) { - if (overlays[i] === HMD.tabletID) { + if (HMD.tabletID && overlays[i] === HMD.tabletID) { return true; } } @@ -44,7 +44,8 @@ Script.include("/~/system/libraries/utils.js"); }; this.pointingAtTablet = function(objectID) { - return objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID; + return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) + || (HMD.homeButtonID && objectID === HMD.homeButtonID); }; this.sendPickData = function(controllerData) { @@ -106,7 +107,7 @@ Script.include("/~/system/libraries/utils.js"); if (nearOverlay) { var nearOverlayReady = nearOverlay.isReady(controllerData); - if (nearOverlayReady.active && nearOverlay.grabbedThingID === HMD.tabletID) { + if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { return this.exitModule(); } } diff --git a/scripts/system/controllers/controllerModules/inVREditMode.js b/scripts/system/controllers/controllerModules/inVREditMode.js index 38eca65dd3..7b78d5e1c4 100644 --- a/scripts/system/controllers/controllerModules/inVREditMode.js +++ b/scripts/system/controllers/controllerModules/inVREditMode.js @@ -31,7 +31,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); ); this.pointingAtTablet = function (objectID) { - return objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID; + return (HMD.tabletScreenID && objectID === HMD.tabletScreenID) + || (HMD.homeButtonID && objectID === HMD.homeButtonID); }; this.isReady = function (controllerData) { @@ -76,7 +77,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); : "LeftNearParentingGrabOverlay"); if (nearOverlay) { var nearOverlayReady = nearOverlay.isReady(controllerData); - if (nearOverlayReady.active && nearOverlay.grabbedThingID === HMD.tabletID) { + if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { return makeRunningValues(false, [], []); } } diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index fa0fe31de2..0f876816b3 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -117,7 +117,7 @@ Script.include("/~/system/libraries/utils.js"); Overlays.editOverlay(this.grabbedThingID, reparentProps); // resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix - if (this.grabbedThingID === HMD.tabletID) { + if (HMD.tabletID && this.grabbedThingID === HMD.tabletID) { resizeTablet(getTabletWidthFromSettings(), reparentProps.parentJointIndex); } @@ -143,7 +143,7 @@ Script.include("/~/system/libraries/utils.js"); }); // resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix - if (this.grabbedThingID === HMD.tabletID) { + if (HMD.tabletID && this.grabbedThingID === HMD.tabletID) { resizeTablet(getTabletWidthFromSettings(), this.previousParentJointIndex[this.grabbedThingID]); } } diff --git a/scripts/system/controllers/controllerModules/stylusInput.js b/scripts/system/controllers/controllerModules/stylusInput.js index aa65135289..a512fd89db 100644 --- a/scripts/system/controllers/controllerModules/stylusInput.js +++ b/scripts/system/controllers/controllerModules/stylusInput.js @@ -20,7 +20,7 @@ Script.include("/~/system/libraries/controllers.js"); var stylusTargetIDs = []; for (var index = 0; index < stylusTargets.length; index++) { var stylusTarget = stylusTargets[index]; - if (stylusTarget.distance <= maxNormalDistance && stylusTarget.id !== HMD.tabletID) { + if (stylusTarget.distance <= maxNormalDistance && !(HMD.tabletID && stylusTarget.id === HMD.tabletID)) { stylusTargetIDs.push(stylusTarget.id); } } @@ -96,7 +96,7 @@ Script.include("/~/system/libraries/controllers.js"); var i, stylusTarget; for (i = 0; i < candidateOverlays.length; i++) { - if (candidateOverlays[i] !== HMD.tabletID && + if (!(HMD.tabletID && candidateOverlays[i] === HMD.tabletID) && Overlays.getProperty(candidateOverlays[i], "visible")) { stylusTarget = getOverlayDistance(controllerPosition, candidateOverlays[i]); if (stylusTarget) { diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index a51cea67f8..b62cb3dd90 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -263,7 +263,10 @@ function Grabber() { filter: Picks.PICK_OVERLAYS, enabled: true }); - RayPick.setIncludeItems(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + var tabletItems = getMainTabletIDs(); + if (tabletItems.length > 0) { + RayPick.setIncludeItems(this.mouseRayOverlays, tabletItems); + } var renderStates = [{name: "grabbed", end: beacon}]; this.mouseRayEntities = Pointers.createPointer(PickType.Ray, { joint: "Mouse", diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 863c185cb4..42c1cc4b51 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -31,6 +31,7 @@ Script.include([ "libraries/entityCameraTool.js", "libraries/gridTool.js", "libraries/entityList.js", + "libraries/utils.js", "particle_explorer/particleExplorerTool.js", "libraries/entityIconOverlayManager.js" ]); @@ -733,8 +734,7 @@ function findClickedEntity(event) { } var pickRay = Camera.computePickRay(event.x, event.y); - - var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + var overlayResult = Overlays.findRayIntersection(pickRay, true, getMainTabletIDs()); if (overlayResult.intersects) { return null; } @@ -922,7 +922,7 @@ function mouseReleaseEvent(event) { function wasTabletClicked(event) { var rayPick = Camera.computePickRay(event.x, event.y); - var result = Overlays.findRayIntersection(rayPick, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + var result = Overlays.findRayIntersection(rayPick, true, getMainTabletIDs()); return result.intersects; } @@ -945,7 +945,7 @@ function mouseClickEvent(event) { toolBar.setActive(true); var pickRay = result.pickRay; var foundEntity = result.entityID; - if (foundEntity === HMD.tabletID) { + if (HMD.tabletID && foundEntity === HMD.tabletID) { return; } properties = Entities.getEntityProperties(foundEntity); diff --git a/scripts/system/help.js b/scripts/system/help.js index 9ab7fa3fb3..6fe0da8a86 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -30,9 +30,8 @@ if (onHelpScreen) { tablet.gotoHomeScreen(); } else { - var tabletEntity = HMD.tabletID; - if (tabletEntity) { - Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + if (HMD.tabletID) { + Entities.editEntity(HMD.tabletID, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); } Menu.triggerOption('Help...'); onHelpScreen = true; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 05b4963280..c4ad2b43a7 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -334,7 +334,7 @@ WebTablet.prototype.destroy = function () { }; WebTablet.prototype.geometryChanged = function (geometry) { - if (!HMD.active) { + if (!HMD.active && HMD.tabletID) { var tabletProperties = {}; // compute position, rotation & parentJointIndex of the tablet this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties); @@ -462,6 +462,9 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMou }; WebTablet.prototype.onHmdChanged = function () { + if (!HMD.tabletID) { + return; + } var tabletProperties = {}; // compute position, rotation & parentJointIndex of the tablet this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index b8ba146757..eea541a430 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -19,7 +19,10 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; -Script.include("./controllers.js"); +Script.include([ + "./controllers.js", + "./utils.js" +]); function objectTranslationPlanePoint(position, dimensions) { var newPosition = { x: position.x, y: position.y, z: position.z }; @@ -3650,7 +3653,8 @@ SelectionDisplay = (function() { var pickRay = generalComputePickRay(event.x, event.y); // TODO_Case6491: Move this out to setup just to make it once - var interactiveOverlays = [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, selectionBox]; + var interactiveOverlays = getMainTabletIDs(); + interactiveOverlays.push(selectionBox); for (var key in grabberTools) { if (grabberTools.hasOwnProperty(key)) { interactiveOverlays.push(key); @@ -3663,7 +3667,8 @@ SelectionDisplay = (function() { var results = testRayIntersect(pickRay, interactiveOverlays); if (results.intersects) { var hitOverlayID = results.overlayID; - if ((hitOverlayID === HMD.tabletID) || (hitOverlayID === HMD.tabletScreenID) || (hitOverlayID === HMD.homeButtonID)) { + if ((HMD.tabletID && hitOverlayID === HMD.tabletID) || (HMD.tabletScreenID && hitOverlayID === HMD.tabletScreenID) + || (HMD.homeButtonID && hitOverlayID === HMD.homeButtonID)) { // EARLY EXIT-(mouse clicks on the tablet should override the edit affordances) return false; } diff --git a/scripts/system/libraries/utils.js b/scripts/system/libraries/utils.js index bc83cc582c..442a9f6d24 100644 --- a/scripts/system/libraries/utils.js +++ b/scripts/system/libraries/utils.js @@ -428,3 +428,17 @@ resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) dimensions: { x: homeButtonDim, y: homeButtonDim, z: homeButtonDim } }); }; + +getMainTabletIDs = function () { + var tabletIDs = []; + if (HMD.tabletID) { + tabletIDs.push(HMD.tabletID); + } + if (HMD.tabletScreenID) { + tabletIDs.push(HMD.tabletScreenID); + } + if (HMD.homeButtonID) { + tabletIDs.push(HMD.homeButtonID); + } + return tabletIDs; +}; \ No newline at end of file diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index facb932eb0..5d905f7553 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -104,8 +104,9 @@ var selectionDisplay = null; // for gridTool.js to ignore tablet.gotoHomeScreen(); } else { Wallet.refreshWalletStatus(); - var entity = HMD.tabletID; - Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + if (HMD.tabletID) { + Entities.editEntity(HMD.tabletID, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + } showMarketplace(); } } diff --git a/scripts/system/menu.js b/scripts/system/menu.js index c7a44d3e48..c27dae6780 100644 --- a/scripts/system/menu.js +++ b/scripts/system/menu.js @@ -28,8 +28,9 @@ var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet- // for toolbar-mode: go back to home screen, this will close the window. tablet.gotoHomeScreen(); } else { - var entity = HMD.tabletID; - Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})}); + if (HMD.tabletID) { + Entities.editEntity(HMD.tabletID, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) }); + } tablet.gotoMenuScreen(); } } diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 36a1cbcdd9..100d0e82ee 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -41,14 +41,14 @@ if (!UIWebTablet) { return false; } - if (Overlays.getProperty(HMD.tabletID, "type") != "model") { + if (Overlays.getProperty(HMD.tabletID, "type") !== "model") { if (debugTablet) { print("TABLET is invalid due to frame: " + JSON.stringify(Overlays.getProperty(HMD.tabletID, "type"))); } return false; } - if (Overlays.getProperty(HMD.homeButtonID, "type") != "circle3d" || - Overlays.getProperty(HMD.tabletScreenID, "type") != "web3d") { + if (Overlays.getProperty(HMD.homeButtonID, "type") !== "circle3d" || + Overlays.getProperty(HMD.tabletScreenID, "type") !== "web3d") { if (debugTablet) { print("TABLET is invalid due to other"); } @@ -112,7 +112,7 @@ } function showTabletUI() { - checkTablet() + checkTablet(); if (!tabletRezzed || !tabletIsValid()) { closeTabletUI(); @@ -157,7 +157,7 @@ } function closeTabletUI() { - checkTablet() + checkTablet(); gTablet.tabletShown = false; if (UIWebTablet) { if (UIWebTablet.onClose) { @@ -178,14 +178,14 @@ print("TABLET closeTabletUI, UIWebTablet is null"); } tabletRezzed = false; - gTablet = null + gTablet = null; } function updateShowTablet() { var now = Date.now(); - checkTablet() + checkTablet(); // close the WebTablet if it we go into toolbar mode. var tabletShown = gTablet.tabletShown; @@ -270,7 +270,7 @@ } if (channel === "home") { if (UIWebTablet) { - checkTablet() + checkTablet(); gTablet.landscape = false; } } diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 6181173818..92aefd1e80 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -48,9 +48,8 @@ // for toolbar-mode: go back to home screen, this will close the window. tablet.gotoHomeScreen(); } else { - var tabletEntity = HMD.tabletID; - if (tabletEntity) { - Entities.editEntity(tabletEntity, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); + if (HMD.tabletID) { + Entities.editEntity(HMD.tabletID, {textures: JSON.stringify({"tex.close" : HOME_BUTTON_TEXTURE})}); } shouldActivateButton = true; tablet.gotoWebScreen(USERS_URL); diff --git a/unpublishedScripts/marketplace/shapes/modules/laser.js b/unpublishedScripts/marketplace/shapes/modules/laser.js index d5feda0e1f..067b605047 100644 --- a/unpublishedScripts/marketplace/shapes/modules/laser.js +++ b/unpublishedScripts/marketplace/shapes/modules/laser.js @@ -173,8 +173,18 @@ Laser = function (side) { // Normal laser operation with trigger. intersection = Overlays.findRayIntersection(pickRay, PRECISION_PICKING, NO_INCLUDE_IDS, NO_EXCLUDE_IDS, VISIBLE_ONLY); + var tabletIDs = []; + if (HMD.tabletID) { + tabletIDs.push(HMD.tabletID); + } + if (HMD.tabletScreenID) { + tabletIDs.push(HMD.tabletScreenID); + } + if (HMD.homeButtonID) { + tabletIDs.push(HMD.homeButtonID); + } if (Reticle.pointingAtSystemOverlay || (intersection.overlayID - && [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID].indexOf(intersection.overlayID) !== -1)) { + && tabletIDs.indexOf(intersection.overlayID) !== -1)) { // No laser if pointing at HUD overlay or tablet; system provides lasers for these cases. if (isLaserOn) { isLaserOn = false; From 2fc954909bf8b721f5aecbfa26aa37494da6409a Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 23 Jan 2018 14:41:46 -0500 Subject: [PATCH 28/83] [Case 4315] Fixes black color preview for color pickers (details below). The original/starting color preview in the picker was black as opposed to reflecting the entity's color upon clicking the color picker. Known Issue(s)/TODO(s): * Color preview restore color functionality isn't working. * Clicking the initial color preview doesn't restore the color. * The original color preview isn't being visually retained when the user changes the color via the picker. Tested HMD & Desktop Modes. Changes Committed: modified: scripts/system/html/js/entityProperties.js --- scripts/system/html/js/entityProperties.js | 94 +++++++++++++++++----- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 7008d0df66..be9bba5f0d 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -29,7 +29,7 @@ var ICON_FOR_TYPE = { var EDITOR_TIMEOUT_DURATION = 1500; var KEY_P = 80; // Key code for letter p used for Parenting hotkey. -var colorPickers = []; +var colorPickers = {}; var lastEntityID = null; function debugPrint(message) { @@ -69,8 +69,8 @@ function enableProperties() { function disableProperties() { disableChildren(document.getElementById("properties-list"), "input, textarea, checkbox, .dropdown dl, .color-picker"); disableChildren(document, ".colpick"); - for (var i = 0; i < colorPickers.length; i++) { - colorPickers[i].colpickHide(); + for (var pickKey in colorPickers) { + colorPickers[pickKey].colpickHide(); } var elLocked = document.getElementById("property-locked"); @@ -83,7 +83,6 @@ function disableProperties() { function showElements(els, show) { for (var i = 0; i < els.length; i++) { els[i].style.display = (show) ? 'table' : 'none'; - } } @@ -1304,13 +1303,19 @@ function loaded() { elColorRed.addEventListener('change', colorChangeFunction); elColorGreen.addEventListener('change', colorChangeFunction); elColorBlue.addEventListener('change', colorChangeFunction); - colorPickers.push($('#property-color-control2').colpick({ + colorPickers['#property-color-control2'] = $('#property-color-control2').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-color-control2').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-color-control2'].colpickSetColor({ + "r": elColorRed.value, + "g": elColorGreen.value, + "b": elColorBlue.value}); }, onHide: function(colpick) { $('#property-color-control2').attr('active', 'false'); @@ -1319,7 +1324,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } - })); + }); elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight')); @@ -1328,13 +1333,20 @@ function loaded() { elLightColorRed.addEventListener('change', lightColorChangeFunction); elLightColorGreen.addEventListener('change', lightColorChangeFunction); elLightColorBlue.addEventListener('change', lightColorChangeFunction); - colorPickers.push($('#property-light-color').colpick({ + colorPickers['#property-light-color'] = $('#property-light-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-light-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-light-color'].colpickSetColor({ + "r": elLightColorRed.value, + "g": elLightColorGreen.value, + "b": elLightColorBlue.value + }); }, onHide: function(colpick) { $('#property-light-color').attr('active', 'false'); @@ -1343,7 +1355,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } - })); + }); elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1)); elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1)); @@ -1383,13 +1395,20 @@ function loaded() { elTextTextColorRed.addEventListener('change', textTextColorChangeFunction); elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction); elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction); - colorPickers.push($('#property-text-text-color').colpick({ + colorPickers['#property-text-text-color'] = $('#property-text-text-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-text-text-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-text-text-color'].colpickSetColor({ + "r": elTextTextColorRed.value, + "g": elTextTextColorGreen.value, + "b": elTextTextColorBlue.value + }); }, onHide: function(colpick) { $('#property-text-text-color').attr('active', 'false'); @@ -1399,7 +1418,7 @@ function loaded() { $(el).attr('active', 'false'); emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b); } - })); + }); var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction( 'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue); @@ -1407,13 +1426,20 @@ function loaded() { elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction); - colorPickers.push($('#property-text-background-color').colpick({ + colorPickers['#property-text-background-color'] = $('#property-text-background-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-text-background-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-text-background-color'].colpickSetColor({ + "r": elTextBackgroundColorRed.value, + "g": elTextBackgroundColorGreen.value, + "b": elTextBackgroundColorBlue.value + }); }, onHide: function(colpick) { $('#property-text-background-color').attr('active', 'false'); @@ -1422,7 +1448,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b); } - })); + }); // Key light var keyLightModeChanged = createZoneComponentModeChangedFunction('keyLightMode', @@ -1432,13 +1458,20 @@ function loaded() { elZoneKeyLightModeDisabled.addEventListener('change', keyLightModeChanged); elZoneKeyLightModeEnabled.addEventListener('change', keyLightModeChanged); - colorPickers.push($('#property-zone-key-light-color').colpick({ + colorPickers['#property-zone-key-light-color'] = $('#property-zone-key-light-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-key-light-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-zone-key-light-color'].colpickSetColor({ + "r": elZoneKeyLightColorRed.value, + "g": elZoneKeyLightColorGreen.value, + "b": elZoneKeyLightColorBlue.value + }); }, onHide: function(colpick) { $('#property-zone-key-light-color').attr('active', 'false'); @@ -1447,7 +1480,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight'); } - })); + }); var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight', 'color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue); @@ -1501,13 +1534,20 @@ function loaded() { elZoneHazeRange.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeRange')); - colorPickers.push($('#property-zone-haze-color').colpick({ + colorPickers['#property-zone-haze-color'] = $('#property-zone-haze-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-haze-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-zone-haze-color'].colpickSetColor({ + "r": elZoneHazeColorRed.value, + "g": elZoneHazeColorGreen.value, + "b": elZoneHazeColorBlue.value + }); }, onHide: function(colpick) { $('#property-zone-haze-color').attr('active', 'false'); @@ -1516,7 +1556,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze'); } - })); + }); var zoneHazeColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('haze', 'hazeColor', elZoneHazeColorRed, elZoneHazeColorGreen, @@ -1526,13 +1566,20 @@ function loaded() { elZoneHazeColorGreen.addEventListener('change', zoneHazeColorChangeFunction); elZoneHazeColorBlue.addEventListener('change', zoneHazeColorChangeFunction); - colorPickers.push($('#property-zone-haze-glare-color').colpick({ + colorPickers['#property-zone-haze-glare-color'] = $('#property-zone-haze-glare-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-zone-haze-glare-color'].colpickSetColor({ + "r": elZoneHazeGlareColorRed.value, + "g": elZoneHazeGlareColorGreen.value, + "b": elZoneHazeGlareColorBlue.value + }); }, onHide: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'false'); @@ -1541,7 +1588,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze'); } - })); + }); var zoneHazeGlareColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('haze', 'hazeGlareColor', elZoneHazeGlareColorRed, elZoneHazeGlareColorGreen, @@ -1568,13 +1615,20 @@ function loaded() { elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction); - colorPickers.push($('#property-zone-skybox-color').colpick({ + colorPickers['#property-zone-skybox-color'] = $('#property-zone-skybox-color').colpick({ colorScheme: 'dark', layout: 'hex', color: '000000', submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-skybox-color').attr('active', 'true'); + // The original color preview within the picker needs to be updated on show because + // prior to the picker being shown we don't have access to the selections' starting color. + colorPickers['#property-zone-skybox-color'].colpickSetColor({ + "r": elZoneSkyboxColorRed.value, + "g": elZoneSkyboxColorGreen.value, + "b": elZoneSkyboxColorBlue.value + }); }, onHide: function(colpick) { $('#property-zone-skybox-color').attr('active', 'false'); @@ -1583,7 +1637,7 @@ function loaded() { $(el).css('background-color', '#' + hex); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); } - })); + }); elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox', 'url')); From 6c5961820ca208f7e1396f555e9a3681281ba1fa Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 23 Jan 2018 15:12:53 -0500 Subject: [PATCH 29/83] [Case 4315] Fixes Color Picker preview restore functionality (details below). * The original color preview is now visually retained when the user changes the color via the picker when using the Non-Submit configuration (No OK button). * Clicking the initial old color preview section restores the original/initial color of the object. Tested Desktop & HMD Modes. Changes Committed: modified: scripts/system/html/css/colpick.css modified: scripts/system/html/js/colpick.js --- scripts/system/html/css/colpick.css | 8 ++++---- scripts/system/html/js/colpick.js | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/css/colpick.css b/scripts/system/html/css/colpick.css index 98417a5e9a..fc50c4b3fb 100644 --- a/scripts/system/html/css/colpick.css +++ b/scripts/system/html/css/colpick.css @@ -279,7 +279,7 @@ colpick Color Picker / colpick.com } /*full layout with no submit button*/ -.colpick_full_ns .colpick_submit, .colpick_full_ns .colpick_current_color{ +.colpick_full_ns .colpick_submit { display:none; } .colpick_full_ns .colpick_new_color { @@ -320,11 +320,11 @@ colpick Color Picker / colpick.com } /*rgbhex layout, no submit button*/ -.colpick_rgbhex_ns .colpick_submit, .colpick_rgbhex_ns .colpick_current_color{ +.colpick_rgbhex_ns .colpick_submit { display:none; } .colpick_rgbhex_ns .colpick_new_color{ - width:68px; + width:34px; border: 1px solid #8f8f8f; } .colpick_rgbhex_ns .colpick_rgb_r { @@ -379,7 +379,7 @@ colpick Color Picker / colpick.com } /*hex layout, no submit button*/ -.colpick_hex_ns .colpick_submit, .colpick_hex_ns .colpick_current_color { +.colpick_hex_ns .colpick_submit { display:none; } .colpick_hex_ns .colpick_hex_field { diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index f808262e9e..99054c6103 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -302,6 +302,9 @@ For usage and examples: colpick.com/plugin setSelector(col, cal.get(0)); setHue(col, cal.get(0)); setNewColor(col, cal.get(0)); + // If the user triggered this behavior, then any prior color change should be negated. + cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), + hsbToRgb(col), cal.data('colpick').el, 0]); }; return { init: function (opt) { From 84cd0e15299d7bfd2d9132b6c6c1c17373ca7faa Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 5 Feb 2018 18:08:36 -0800 Subject: [PATCH 30/83] wip live material swapping on model entities, model overlays, avatars, and albedo swap on shape entities --- domain-server/CMakeLists.txt | 2 + .../icons/create-icons/126-material-01.svg | 9 + .../resources/qml/hifi/tablet/EditTabView.qml | 2 +- interface/src/Application.cpp | 36 +++ interface/src/ui/overlays/ModelOverlay.cpp | 26 ++ interface/src/ui/overlays/ModelOverlay.h | 5 + interface/src/ui/overlays/Overlay.cpp | 10 + interface/src/ui/overlays/Overlay.h | 6 + .../src/avatars-renderer/Avatar.cpp | 30 +++ .../src/avatars-renderer/Avatar.h | 8 + libraries/avatars/CMakeLists.txt | 3 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 5 + .../src/RenderableEntityItem.cpp | 13 + .../src/RenderableEntityItem.h | 6 + .../src/RenderableMaterialEntityItem.cpp | 26 +- .../src/RenderableMaterialEntityItem.h | 5 +- .../src/RenderableModelEntityItem.cpp | 26 ++ .../src/RenderableModelEntityItem.h | 7 + .../src/RenderableShapeEntityItem.cpp | 29 +- .../src/RenderableShapeEntityItem.h | 2 +- .../entities/src/DeleteEntityOperator.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 39 ++- libraries/entities/src/EntityItem.h | 22 +- .../entities/src/EntityItemProperties.cpp | 52 ++-- libraries/entities/src/EntityItemProperties.h | 8 +- .../entities/src/EntityItemPropertiesMacros.h | 43 ++- libraries/entities/src/EntityPropertyFlags.h | 4 +- libraries/entities/src/EntityTree.cpp | 48 +++- libraries/entities/src/EntityTree.h | 15 ++ libraries/entities/src/EntityTreeElement.cpp | 26 +- libraries/entities/src/EntityTreeElement.h | 3 +- libraries/entities/src/MaterialEntityItem.cpp | 253 +++++++++++++++--- libraries/entities/src/MaterialEntityItem.h | 43 ++- libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ShapeEntityItem.cpp | 7 + libraries/entities/src/ShapeEntityItem.h | 6 +- libraries/graphics/src/graphics/Material.cpp | 15 ++ libraries/graphics/src/graphics/Material.h | 36 +++ .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/ModelCache.h | 6 +- libraries/octree/src/OctreePacketData.cpp | 11 + libraries/octree/src/OctreePacketData.h | 5 +- .../render-utils/src/MeshPartPayload.cpp | 32 ++- libraries/render-utils/src/MeshPartPayload.h | 13 +- libraries/render-utils/src/Model.cpp | 44 +++ libraries/render-utils/src/Model.h | 3 + scripts/system/edit.js | 51 ++-- scripts/system/html/css/edit-style.css | 12 +- scripts/system/html/entityProperties.html | 29 +- scripts/system/html/js/entityProperties.js | 61 ++--- tools/jsdoc/package-lock.json | 138 ++++++++++ 52 files changed, 1038 insertions(+), 251 deletions(-) create mode 100644 interface/resources/icons/create-icons/126-material-01.svg create mode 100644 tools/jsdoc/package-lock.json diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index c1e275e4d3..f67be55b92 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -22,6 +22,8 @@ setup_memory_debugger() symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources") # link the shared hifi libraries +include_hifi_library_headers(gpu) +include_hifi_library_headers(graphics) link_hifi_libraries(embedded-webserver networking shared avatars) # find OpenSSL diff --git a/interface/resources/icons/create-icons/126-material-01.svg b/interface/resources/icons/create-icons/126-material-01.svg new file mode 100644 index 0000000000..9b6d92505f --- /dev/null +++ b/interface/resources/icons/create-icons/126-material-01.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 65dd871fb2..6f97664e06 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -135,7 +135,7 @@ TabView { } NewEntityButton { - icon: "icons/create-icons/94-model-01.svg" + icon: "icons/create-icons/126-material-01.svg" text: "MATERIAL" onClicked: { editRoot.sendToScript({ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1a54c94d53..1cf8f0587f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1580,6 +1580,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + auto avatarManager = DependencyManager::get(); + auto avatar = avatarManager->getAvatarBySessionID(avatarID); + if (avatar) { + avatar->removeMaterial(material, shapeID); + return true; + } + return false; + }); + + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->addMaterial(material, shapeID); + return true; + } + return false; + }); + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + auto overlay = _overlays.getOverlay(overlayID); + if (overlay) { + overlay->removeMaterial(material, shapeID); + return true; + } + return false; + }); + // Keyboard focus handling for Web overlays. auto overlays = &(qApp->getOverlays()); connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 4847650163..9e4835a76e 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -632,3 +632,29 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { } return 0; } + +void ModelOverlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelOverlay::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 08c776c426..827f7f2d5b 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -59,6 +59,9 @@ public: void setDrawInFront(bool drawInFront) override; void setDrawHUDLayer(bool drawHUDLayer) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: Transform evalRenderTransform() override; @@ -110,6 +113,8 @@ private: bool _drawInFrontDirty { false }; bool _drawInHUDDirty { false }; + void processMaterials(); + }; #endif // hifi_ModelOverlay_h diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 3c952b8338..368ed04062 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -235,3 +235,13 @@ QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { } return newVector; } + +void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); +} \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index e9271f3c3f..4cb3f7c84d 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -91,6 +91,9 @@ public: unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + protected: float updatePulse(); @@ -117,6 +120,9 @@ protected: static const xColor DEFAULT_OVERLAY_COLOR; static const float DEFAULT_ALPHA; + std::unordered_map _materials; + std::mutex _materialsLock; + private: OverlayID _overlayID; // only used for non-3d overlays }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 86635cd3bf..4cd9bbedd7 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -570,6 +570,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc } transaction.resetItem(_renderItemID, avatarPayloadPointer); _skeletonModel->addToScene(scene, transaction); + processMaterials(); for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); } @@ -761,6 +762,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { _skeletonModel->removeFromScene(scene, transaction); _skeletonModel->addToScene(scene, transaction); + processMaterials(); canTryFade = true; _isAnimatingScale = true; } @@ -1760,3 +1762,31 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { return DEFAULT_AVATAR_EYE_HEIGHT; } } + +void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->addMaterial(material, shapeID); + } +} + +void Avatar::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { + _skeletonModel->removeMaterial(material, shapeID); + } +} + +void Avatar::processMaterials() { + assert(_skeletonModel); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _skeletonModel->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c2b404a925..9c355159d8 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -272,6 +272,9 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + public slots: // FIXME - these should be migrated to use Pose data instead @@ -397,6 +400,11 @@ protected: float _displayNameAlpha { 1.0f }; ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; + + std::unordered_map _materials; + std::mutex _materialsLock; + + void processMaterials(); }; #endif // hifi_Avatar_h diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index fc6d15cced..13fda28f40 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,3 +1,4 @@ set(TARGET_NAME avatars) setup_hifi_library(Network Script) -link_hifi_libraries(shared networking) +include_hifi_library_headers(gpu) +link_hifi_libraries(shared networking graphics) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 74888283df..1bbc8cc1a5 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2558,4 +2558,4 @@ void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value[EntityID] = binaryEntityProperties; } -} +} \ No newline at end of file diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a363fb6d15..b7d594f1dc 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -54,6 +54,8 @@ #include "HeadData.h" #include "PathUtils.h" +#include + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -694,6 +696,9 @@ public: bool getIsReplicated() const { return _isReplicated; } + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + signals: void displayNameChanged(); void sessionDisplayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 49ddf111c3..2f92790d18 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -146,6 +146,9 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity _needsRenderUpdate = true; emit requestRenderUpdate(); }); + _materials = entity->getMaterials(); + connect(entity.get(), &EntityItem::addMaterialToRenderItem, this, &EntityRenderer::addMaterial); + connect(entity.get(), &EntityItem::removeMaterialFromRenderItem, this, &EntityRenderer::removeMaterial); } EntityRenderer::~EntityRenderer() { } @@ -399,4 +402,14 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) { void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { entity->deregisterChangeHandler(_changeHandlerId); QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); +} + +void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); +} + +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index ce5bfb30a4..f58b540aef 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -101,6 +101,10 @@ protected: return result; } +public slots: + virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + signals: void requestRenderUpdate(); @@ -129,6 +133,8 @@ protected: // Only touched on the rendering thread bool _renderUpdateQueued{ false }; + std::unordered_map _materials; + std::mutex _materialsLock; private: // The base class relies on comparing the model transform to the entity transform in order diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 83754c1c16..d541d99c4c 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -15,12 +15,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getMaterial() != _drawMaterial) { return true; } + if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { + return true; + } return false; } void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { withWriteLock([&] { _drawMaterial = entity->getMaterial(); + _parentID = entity->getParentID(); + _clientOnly = entity->getClientOnly(); + _owningAvatarID = entity->getOwningAvatarID(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -30,7 +36,7 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& ItemKey MaterialEntityRenderer::getKey() { ItemKey::Builder builder; - builder.withTypeShape(); + builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1); if (!_visible) { builder.withInvisible(); @@ -215,13 +221,25 @@ void MaterialEntityRenderer::generateMesh() { void MaterialEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_renderTransform); + // Don't render if our parent is set or our material is null + QUuid parentID; + Transform renderTransform; + graphics::MaterialPointer drawMaterial; + withReadLock([&] { + parentID = _clientOnly ? _owningAvatarID : _parentID; + renderTransform = _renderTransform; + drawMaterial = _drawMaterial; + }); + if (!parentID.isNull() || !drawMaterial) { + return; + } + + batch.setModelTransform(renderTransform); // bind the material - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 166ad762cc..af8cef9351 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -31,6 +31,9 @@ private: ItemKey getKey() override; ShapeKey getShapeKey() override; + QUuid _parentID; + bool _clientOnly; + QUuid _owningAvatarID; Transform _renderTransform; std::shared_ptr _drawMaterial; @@ -47,7 +50,7 @@ private: static void addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv); const int SLICES = 15; const int STACKS = 9; - const float M_PI_TIMES_2 = 2.0f * M_PI; + const float M_PI_TIMES_2 = 2.0f * (float)M_PI; }; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 137203f475..739ccd9738 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1380,6 +1380,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce auto entityRenderer = static_cast(&data); entityRenderer->setSubRenderItemIDs(newRenderItemIDs); }); + processMaterials(); } } @@ -1466,3 +1467,28 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr } } +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::addMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->addMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + Parent::removeMaterial(material, shapeID); + if (_model && _model->fetchRenderItemIDs().size() > 0) { + _model->removeMaterial(material, shapeID); + } +} + +void ModelEntityRenderer::processMaterials() { + assert(_model); + std::lock_guard lock(_materialsLock); + for (auto& shapeMaterialPair : _materials) { + auto material = shapeMaterialPair.second; + while (!material.empty()) { + _model->addMaterial(material.top(), shapeMaterialPair.first); + material.pop(); + } + } +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 33fc9910a0..75c6639902 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -138,10 +138,15 @@ namespace render { namespace entities { class ModelEntityRenderer : public TypedEntityRenderer { using Parent = TypedEntityRenderer; friend class EntityRenderer; + Q_OBJECT public: ModelEntityRenderer(const EntityItemPointer& entity); +public slots: + void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; @@ -194,6 +199,8 @@ private: uint64_t _lastAnimated { 0 }; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; + + void processMaterials(); }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index cdee2c5ec9..8163b14608 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -54,8 +54,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin if (_lastUserData != entity->getUserData()) { return true; } - glm::vec4 newColor(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); - if (newColor != _color) { + if (_material != entity->getMaterial()) { return true; } @@ -78,7 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - _color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); + removeMaterial(_material, 0); + _material = entity->getMaterial(); + addMaterial(_material, 0); _shape = entity->getShape(); _position = entity->getWorldPosition(); @@ -112,14 +113,13 @@ bool ShapeEntityRenderer::isTransparent() const { return Parent::isTransparent(); } - - void ShapeEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + std::shared_ptr mat; auto geometryCache = DependencyManager::get(); GeometryCache::Shape geometryShape; bool proceduralRender = false; @@ -127,15 +127,22 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation - outColor = _color; - if (_procedural.isReady()) { - _procedural.prepare(batch, _position, _dimensions, _orientation); - outColor = _procedural.getColor(_color); - outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - proceduralRender = true; + mat = _materials[0].top(); + if (mat) { + outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity()); + if (_procedural.isReady()) { + _procedural.prepare(batch, _position, _dimensions, _orientation); + outColor = _procedural.getColor(outColor); + outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; + proceduralRender = true; + } } }); + if (!mat) { + return; + } + if (proceduralRender) { if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShape(batch, geometryShape, outColor); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 433cb41ad2..c913544255 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -34,7 +34,7 @@ private: QString _lastUserData; Transform _renderTransform; entity::Shape _shape { entity::Sphere }; - glm::vec4 _color; + std::shared_ptr _material; glm::vec3 _position; glm::vec3 _dimensions; glm::quat _orientation; diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index cbd0ad7839..347d40ea49 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -93,7 +93,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) { // and we can stop searching. if (entityTreeElement == details.containingElement) { EntityItemPointer theEntity = details.entity; - bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element + bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element assert(entityDeleted); (void)entityDeleted; // quite warning _tree->clearEntityMapEntry(details.entity->getEntityItemID()); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ed13a46414..43510864ba 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -60,14 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : } EntityItem::~EntityItem() { - // clear out any left-over actions - EntityTreeElementPointer element = _element; // use local copy of _element for logic below - EntityTreePointer entityTree = element ? element->getTree() : nullptr; - EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; - if (simulation) { - clearActions(simulation); - } - // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. assert(!_simulated); @@ -2937,3 +2929,34 @@ void EntityItem::retrieveMarketplacePublicKey() { networkReply->deleteLater(); }); } + +void EntityItem::preDelete() { + // clear out any left-over actions + EntityTreeElementPointer element = _element; // use local copy of _element for logic below + EntityTreePointer entityTree = element ? element->getTree() : nullptr; + EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr; + if (simulation) { + clearActions(simulation); + } +} + +void EntityItem::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].push(material); + emit addMaterialToRenderItem(material, shapeID); +} + +void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + std::lock_guard lock(_materialsLock); + _materials[shapeID].remove(material); + emit removeMaterialFromRenderItem(material, shapeID); +} + +std::unordered_map EntityItem::getMaterials() { + std::unordered_map toReturn; + { + std::lock_guard lock(_materialsLock); + toReturn = _materials; + } + return toReturn; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5f84bcc311..b2804a2e86 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -36,6 +36,8 @@ #include "SimulationFlags.h" #include "EntityDynamicInterface.h" +#include "graphics/Material.h" + class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; @@ -49,7 +51,6 @@ typedef std::shared_ptr EntityTreeElementPointer; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { }; @@ -443,10 +444,10 @@ public: void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; } bool getClientOnly() const { return _clientOnly; } - void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } + virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } // if this entity is client-only, which avatar is it associated with? QUuid getOwningAvatarID() const { return _owningAvatarID; } - void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } + virtual void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; } virtual bool wantsHandControllerPointerEvents() const { return false; } virtual bool wantsKeyboardFocus() const { return false; } @@ -477,8 +478,18 @@ public: void setCauterized(bool value) { _cauterized = value; } bool getCauterized() const { return _cauterized; } + virtual void postAdd() {} + virtual void preDelete(); + virtual void postParentFixup() {} + + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + std::unordered_map getMaterials(); + signals: void requestRenderUpdate(); + void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID); protected: QHash _changeHandlers; @@ -631,6 +642,11 @@ protected: quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera + +private: + std::unordered_map _materials; + std::mutex _materialsLock; + }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 965252abf4..19aa6990db 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -360,7 +360,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BOUNDS, materialBounds); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_POS, materialPos); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_SCALE, materialScale); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_ROT, materialRot); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -664,7 +666,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BOUNDS, materialBounds); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_POS, materialPos); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_SCALE, materialScale); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_ROT, materialRot); } if (!skipDefaults && !strictSemantics) { @@ -801,11 +805,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMode, MaterialMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialBounds, glmVec4, setMaterialBounds); + COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); + COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1163,9 +1169,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); + ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_ROT, MaterialRot, materialRot, float); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -1557,7 +1565,9 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, properties.getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, properties.getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, properties.getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, properties.getMaterialRot()); } APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -1921,9 +1931,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BOUNDS, glmVec4, setMaterialBounds); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_POS, glmVec2, setMaterialPos); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_SCALE, glmVec2, setMaterialScale); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_ROT, float, setMaterialRot); } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -2104,7 +2116,9 @@ void EntityItemProperties::markAllChanged() { _blendFactorChanged = true; _priorityChanged = true; _shapeIDChanged = true; - _materialBoundsChanged = true; + _materialPosChanged = true; + _materialScaleChanged = true; + _materialRotChanged = true; // Certifiable Properties _itemNameChanged = true; @@ -2444,8 +2458,14 @@ QList EntityItemProperties::listChangedProperties() { if (shapeIDChanged()) { out += "shapeID"; } - if (materialBoundsChanged()) { - out += "materialBounds"; + if (materialPosChanged()) { + out += "materialPos"; + } + if (materialScaleChanged()) { + out += "materialScale"; + } + if (materialRotChanged()) { + out += "materialRot"; } // Certifiable Properties diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9bedff41df..a8a79b6303 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -225,9 +225,11 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); - DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t, 0); - DEFINE_PROPERTY_REF(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4, glm::vec4(0, 0, 1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2, glm::vec2(0, 0)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2, glm::vec2(1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_ROT, MaterialRot, materialRot, float, 0); // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 2609fe237d..51a23b6867 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -101,6 +101,7 @@ changedProperties += P; \ } +inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec2& v) { return vec2toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } @@ -183,8 +184,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu properties.setProperty(#P, V); \ } +typedef glm::vec2 glmVec2; typedef glm::vec3 glmVec3; -typedef glm::vec4 glmVec4; typedef glm::quat glmQuat; typedef QVector qVectorVec3; typedef QVector qVectorQuat; @@ -222,6 +223,23 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& return QByteArray::fromBase64(b64.toUtf8()); } +inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = false; /// assume it can't be converted + QScriptValue x = v.property("x"); + QScriptValue y = v.property("y"); + if (x.isValid() && y.isValid()) { + glm::vec4 newValue(0); + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + isValid = !glm::isnan(newValue.x) && + !glm::isnan(newValue.y); + if (isValid) { + return newValue; + } + } + return glm::vec2(0); +} + inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted QScriptValue x = v.property("x"); @@ -242,29 +260,6 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } -inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - isValid = false; /// assume it can't be converted - QScriptValue x = v.property("x"); - QScriptValue y = v.property("y"); - QScriptValue z = v.property("z"); - QScriptValue w = v.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - glm::vec4 newValue(0); - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - newValue.w = w.toVariant().toFloat(); - isValid = !glm::isnan(newValue.x) && - !glm::isnan(newValue.y) && - !glm::isnan(newValue.z) && - !glm::isnan(newValue.w); - if (isValid) { - return newValue; - } - } - return glm::vec4(0); -} - inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; AACube result; diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index bd573423a3..17ebddbe9d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -232,7 +232,9 @@ enum EntityPropertyList { PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_PRIORITY, PROP_PARENT_SHAPE_ID, - PROP_MATERIAL_BOUNDS, + PROP_MATERIAL_POS, + PROP_MATERIAL_SCALE, + PROP_MATERIAL_ROT, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bf29f3bec9..775b3bd2f7 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1732,15 +1732,19 @@ void EntityTree::fixupNeedsParentFixups() { } }); entity->locationChanged(true); - } else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) { - // this is a child of an avatar, which the entity server will never have - // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. - if (!_childrenOfAvatars.contains(entity->getParentID())) { - _childrenOfAvatars[entity->getParentID()] = QSet(); + entity->postParentFixup(); + } else if (_avatarIDs.contains(entity->getParentID())) { + if (getIsServer()) { + // this is a child of an avatar, which the entity server will never have + // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); } - _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; iter.remove(); // and pull it out of the list + entity->postParentFixup(); } if (queryAACubeSuccess && doMove) { @@ -2378,3 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } +std::function EntityTree::_addMaterialToAvatarOperator = nullptr; +std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; +std::function EntityTree::_addMaterialToOverlayOperator = nullptr; +std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; + +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToAvatarOperator) { + return _addMaterialToAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromAvatarOperator) { + return _removeMaterialFromAvatarOperator(avatarID, material, shapeID); + } + return false; +} + +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_addMaterialToOverlayOperator) { + return _addMaterialToOverlayOperator(overlayID, material, shapeID); + } + return false; +} + +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + if (_removeMaterialFromOverlayOperator) { + return _removeMaterialFromOverlayOperator(overlayID, material, shapeID); + } + return false; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8cb89d6493..a02ce900ff 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -280,6 +280,16 @@ public: void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + + static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } + static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + signals: void deletingEntity(const EntityItemID& entityID); void deletingEntityPointer(EntityItem* entityID); @@ -387,6 +397,11 @@ private: void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation); std::shared_ptr _myAvatar{ nullptr }; + + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + static std::function _addMaterialToOverlayOperator; + static std::function _removeMaterialFromOverlayOperator; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c9e1ecc3f1..980ed1c104 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -896,6 +896,7 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI void EntityTreeElement::cleanupEntities() { withWriteLock([&] { foreach(EntityItemPointer entity, _entityItems) { + entity->preDelete(); // NOTE: only EntityTreeElement should ever be changing the value of entity->_element // NOTE: We explicitly don't delete the EntityItem here because since we only // access it by smart pointers, when we remove it from the _entityItems @@ -907,26 +908,10 @@ void EntityTreeElement::cleanupEntities() { bumpChangedContent(); } -bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { - bool foundEntity = false; - withWriteLock([&] { - uint16_t numberOfEntities = _entityItems.size(); - for (uint16_t i = 0; i < numberOfEntities; i++) { - EntityItemPointer& entity = _entityItems[i]; - if (entity->getEntityItemID() == id) { - foundEntity = true; - // NOTE: only EntityTreeElement should ever be changing the value of entity->_element - entity->_element = NULL; - _entityItems.removeAt(i); - bumpChangedContent(); - break; - } - } - }); - return foundEntity; -} - -bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) { +bool EntityTreeElement::removeEntityItem(EntityItemPointer entity, bool deletion) { + if (deletion) { + entity->preDelete(); + } int numEntries = 0; withWriteLock([&] { numEntries = _entityItems.removeAll(entity); @@ -955,6 +940,7 @@ void EntityTreeElement::addEntityItem(EntityItemPointer entity) { }); bumpChangedContent(); entity->_element = getThisPointer(); + entity->postAdd(); } // will average a "common reduced LOD view" from the the child elements... diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index a524904c71..2313bde0c4 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -210,8 +210,7 @@ public: void getEntitiesInside(const AACube& box, QVector& foundEntities); void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities - bool removeEntityWithEntityItemID(const EntityItemID& id); - bool removeEntityItem(EntityItemPointer entity); + bool removeEntityItem(EntityItemPointer entity, bool deletion = false); bool containsEntityBounds(EntityItemPointer entity) const; bool bestFitEntityBounds(EntityItemPointer entity) const; diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index bbcc691879..7026da117c 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -16,6 +16,9 @@ EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); + // When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add + entity->removeMaterial(); + entity->applyMaterial(); return entity; } @@ -31,7 +34,9 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialBounds, getMaterialBounds); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialPos, getMaterialPos); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialScale, getMaterialScale); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRot, getMaterialRot); return properties; } @@ -43,7 +48,9 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialBounds, setMaterialBounds); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialPos, setMaterialPos); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialScale, setMaterialScale); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRot, setMaterialRot); if (somethingChanged) { bool wantDebug = false; @@ -202,9 +209,11 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID); - READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds); + READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); + READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY(PROP_MATERIAL_POS, glm::vec2, setMaterialPos); + READ_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, glm::vec2, setMaterialScale); + READ_ENTITY_PROPERTY(PROP_MATERIAL_ROT, float, setMaterialRot); return bytesRead; } @@ -218,7 +227,9 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_PRIORITY; requestedProperties += PROP_PARENT_SHAPE_ID; - requestedProperties += PROP_MATERIAL_BOUNDS; + requestedProperties += PROP_MATERIAL_POS; + requestedProperties += PROP_MATERIAL_SCALE; + requestedProperties += PROP_MATERIAL_ROT; return requestedProperties; } @@ -234,9 +245,11 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, getMaterialPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, getMaterialScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, getMaterialRot()); } void MaterialEntityItem::debugDump() const { @@ -249,7 +262,9 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " priority:" << _priority; qCDebug(entities) << " parent shape ID:" << _shapeID; - qCDebug(entities) << " material bounds:" << _materialBounds; + qCDebug(entities) << " material pos:" << _materialPos; + qCDebug(entities) << " material scale:" << _materialRot; + qCDebug(entities) << " material rot:" << _materialScale; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); @@ -269,30 +284,38 @@ std::shared_ptr MaterialEntityItem::getMaterial() const { } } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString) { - if (materialURLString.startsWith("userData")) { - QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); - _materials.clear(); - _materialNames.clear(); - if (!materialJSON.isNull()) { - if (materialJSON.isArray()) { - QJsonArray materials = materialJSON.array(); - for (auto& material : materials) { - if (!material.isNull() && material.isObject()) { - parseJSONMaterial(material.toObject()); +void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) { + bool usingUserData = materialURLString.startsWith("userData"); + if (_materialURL != materialURLString || (usingUserData && userDataChanged)) { + removeMaterial(); + _materialURL = materialURLString; + + if (usingUserData) { + QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); + _materials.clear(); + _materialNames.clear(); + if (!materialJSON.isNull()) { + if (materialJSON.isArray()) { + QJsonArray materials = materialJSON.array(); + for (auto material : materials) { + if (!material.isNull() && material.isObject()) { + parseJSONMaterial(material.toObject()); + } } + } else if (materialJSON.isObject()) { + parseJSONMaterial(materialJSON.object()); } - } else if (materialJSON.isObject()) { - parseJSONMaterial(materialJSON.object()); } + } else { + // get material via network request } + + // TODO: if URL ends with ?string, try to set _currentMaterialName = string + + // Since our JSON changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); } - _materialURL = materialURLString; - - // TODO: if URL ends with ?string, set _currentMaterialName = string - - // Since our JSON changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); } void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { @@ -300,14 +323,176 @@ void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialNa if (material != _materials.end()) { _currentMaterialName = currentMaterialName; } else if (_materialNames.size() > 0) { - setCurrentMaterialName(_materialNames[0]); + _currentMaterialName = _materialNames[0]; } } void MaterialEntityItem::setUserData(const QString& userData) { - EntityItem::setUserData(userData); - if (_materialURL.startsWith("userData")) { - // Trigger material update when user data changes - setMaterialURL(_materialURL); + if (_userData != userData) { + EntityItem::setUserData(userData); + if (_materialURL.startsWith("userData")) { + // Trigger material update when user data changes + setMaterialURL(_materialURL, true); + } } +} + +void MaterialEntityItem::setMaterialPos(const glm::vec2& materialPos) { + if (_materialPos != materialPos) { + removeMaterial(); + _materialPos = materialPos; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialScale(const glm::vec2& materialScale) { + if (_materialScale != materialScale) { + removeMaterial(); + _materialScale = materialScale; + applyMaterial(); + } +} + +void MaterialEntityItem::setMaterialRot(const float& materialRot) { + if (_materialRot != materialRot) { + removeMaterial(); + _materialRot = materialRot; + applyMaterial(); + } +} + +void MaterialEntityItem::setBlendFactor(float blendFactor) { + if (_blendFactor != blendFactor) { + removeMaterial(); + _blendFactor = blendFactor; + applyMaterial(); + } +} + +void MaterialEntityItem::setPriority(quint16 priority) { + if (_priority != priority) { + removeMaterial(); + _priority = priority; + applyMaterial(); + } +} + +void MaterialEntityItem::setShapeID(quint16 shapeID) { + if (_shapeID != shapeID) { + removeMaterial(); + _shapeID = shapeID; + applyMaterial(); + } +} + +void MaterialEntityItem::setParentID(const QUuid& parentID) { + if (getParentID() != parentID) { + removeMaterial(); + EntityItem::setParentID(parentID); + applyMaterial(); + } +} + +void MaterialEntityItem::setClientOnly(bool clientOnly) { + if (getClientOnly() != clientOnly) { + removeMaterial(); + EntityItem::setClientOnly(clientOnly); + applyMaterial(); + } +} + +void MaterialEntityItem::setOwningAvatarID(const QUuid& owningAvatarID) { + if (getOwningAvatarID() != owningAvatarID) { + removeMaterial(); + EntityItem::setOwningAvatarID(owningAvatarID); + applyMaterial(); + } +} + +void MaterialEntityItem::removeMaterial() { + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->removeMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::removeMaterialFromAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::removeMaterialFromOverlay(parentID, material, getShapeID())) { + return; + } + + // if a remove fails, our parent is gone, so we don't need to retry +} + +void MaterialEntityItem::applyMaterial() { + _retryApply = false; + graphics::MaterialPointer material = getMaterial(); + QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + if (!material || parentID.isNull()) { + return; + } + Transform textureTransform; + textureTransform.setTranslation(glm::vec3(_materialPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); + textureTransform.setScale(glm::vec3(_materialScale, 1)); + material->setTextureTransforms(textureTransform); + material->setBlendFactor(getBlendFactor()); + material->setPriority(getPriority()); + + // Our parent could be an entity, an avatar, or an overlay + EntityTreePointer tree = getTree(); + if (tree) { + EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); + if (entity) { + entity->addMaterial(material, getShapeID()); + return; + } + } + + if (EntityTree::addMaterialToAvatar(parentID, material, getShapeID())) { + return; + } + + if (EntityTree::addMaterialToOverlay(parentID, material, getShapeID())) { + return; + } + + // if we've reached this point, we couldn't find our parent, so we need to try again later + _retryApply = true; +} + +void MaterialEntityItem::postAdd() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::preDelete() { + EntityItem::preDelete(); + removeMaterial(); +} + +void MaterialEntityItem::postParentFixup() { + removeMaterial(); + applyMaterial(); +} + +void MaterialEntityItem::update(const quint64& now) { + if (_retryApply) { + applyMaterial(); + } + + EntityItem::update(now); } \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 80fe226b68..40137acf22 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -23,6 +23,9 @@ public: ALLOW_INSTANTIATION // This class can be instantiated + void update(const quint64& now) override; + bool needsToCallUpdate() const override { return true; } + // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; @@ -49,7 +52,7 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString); + void setMaterialURL(const QString& materialURLString, bool userDataChanged = false); QString getCurrentMaterialName() const { return _currentMaterialName; } void setCurrentMaterialName(const QString& currentMaterialName); @@ -58,33 +61,51 @@ public: void setMaterialMode(MaterialMode mode) { _materialMode = mode; } float getBlendFactor() const { return _blendFactor; } - void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + void setBlendFactor(float blendFactor); - int getPriority() const { return _priority; } - void setPriority(int priority) { _priority = priority; } + quint16 getPriority() const { return _priority; } + void setPriority(quint16 priority); - int getShapeID() const { return _shapeID; } - void setShapeID(int shapeID) { _shapeID = shapeID; } + quint16 getShapeID() const { return _shapeID; } + void setShapeID(quint16 shapeID); - glm::vec4 getMaterialBounds() const { return _materialBounds; } - void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; } + glm::vec2 getMaterialPos() const { return _materialPos; } + void setMaterialPos(const glm::vec2& materialPos); + glm::vec2 getMaterialScale() const { return _materialScale; } + void setMaterialScale(const glm::vec2& materialScale); + float getMaterialRot() const { return _materialRot; } + void setMaterialRot(const float& materialRot); std::shared_ptr getMaterial() const; void setUserData(const QString& userData) override; + void setParentID(const QUuid& parentID) override; + void setClientOnly(bool clientOnly) override; + void setOwningAvatarID(const QUuid& owningAvatarID) override; + + void applyMaterial(); + void removeMaterial(); + + void postAdd() override; + void preDelete() override; + void postParentFixup() override; private: QString _materialURL; MaterialMode _materialMode { UV }; float _blendFactor { 1.0f }; - int _priority { 0 }; - int _shapeID { 0 }; - glm::vec4 _materialBounds { 0, 0, 1, 1 }; + quint16 _priority { 0 }; + quint16 _shapeID { 0 }; + glm::vec2 _materialPos { 0, 0 }; + glm::vec2 _materialScale { 1, 1 }; + float _materialRot { 0 }; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; + bool _retryApply { false }; + void parseJSONMaterial(const QJsonObject& materialJSON); static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 5d33e4c047..bec7bc1906 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -721,4 +721,4 @@ bool ModelEntityItem::isAnimatingSomething() const { _animationProperties.getRunning() && (_animationProperties.getFPS() != 0.0f); }); -} +} \ No newline at end of file diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index cbcfcaaa1d..2425208a87 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -85,6 +85,7 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Shape; _volumeMultiplier *= PI / 6.0f; + _material = std::make_shared(); } EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { @@ -184,6 +185,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void ShapeEntityItem::setColor(const rgbColor& value) { memcpy(_color, value, sizeof(rgbColor)); + _material->setAlbedo(glm::vec3(_color[0], _color[1], _color[2]) / 255.0f); } xColor ShapeEntityItem::getXColor() const { @@ -204,6 +206,11 @@ void ShapeEntityItem::setColor(const QColor& value) { setAlpha(value.alpha()); } +void ShapeEntityItem::setAlpha(float alpha) { + _alpha = alpha; + _material->setOpacity(alpha); +} + void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 84ce1ce57e..7ad1b3c1c2 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -75,7 +75,7 @@ public: void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } float getAlpha() const { return _alpha; }; - void setAlpha(float alpha) { _alpha = alpha; } + void setAlpha(float alpha); const rgbColor& getColor() const { return _color; } void setColor(const rgbColor& value); @@ -101,6 +101,8 @@ public: virtual void computeShapeInfo(ShapeInfo& info) override; virtual ShapeType getShapeType() const override; + std::shared_ptr getMaterial() { return _material; } + protected: float _alpha { 1 }; @@ -111,6 +113,8 @@ protected: //! prior functionality where new or unsupported shapes are treated as //! ellipsoids. ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID }; + + std::shared_ptr _material; }; #endif // hifi_ShapeEntityItem_h diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 6cc6b8472f..7c66c8ab07 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -12,9 +12,13 @@ #include "TextureMap.h" +#include + using namespace graphics; using namespace gpu; +int materialPointerMetaID = qRegisterMetaType("graphics::MaterialPointer"); + Material::Material() : _key(0), _schemaBuffer(), @@ -221,4 +225,15 @@ bool Material::calculateMaterialInfo() const { _hasCalculatedTextureInfo = allTextures; } return _hasCalculatedTextureInfo; +} + +void Material::setTextureTransforms(const Transform& transform) { + for (auto &textureMapItem : _textureMaps) { + if (textureMapItem.second) { + textureMapItem.second->setTextureTransform(transform); + } + } + for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) { + _texMapArrayBuffer.edit()._texcoordTransforms[i] = transform.getMatrix(); + } } \ No newline at end of file diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index cfbfaa61ea..b9eb881ed8 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -15,11 +15,14 @@ #include #include +#include #include #include +class Transform; + namespace graphics { class TextureMap; @@ -351,6 +354,14 @@ public: size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } + void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } + float getBlendFactor() { return _blendFactor; } + + void setPriority(quint16 priority) { _priority = priority; } + quint16 getPriority() { return _priority; } + + void setTextureTransforms(const Transform& transform); + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; @@ -364,10 +375,35 @@ private: mutable bool _hasCalculatedTextureInfo { false }; bool calculateMaterialInfo() const; + float _blendFactor { 1.0f }; + quint16 _priority { 0 }; }; typedef std::shared_ptr< Material > MaterialPointer; +Q_DECLARE_METATYPE(MaterialPointer) + +class MaterialCompare { +public: + bool operator() (MaterialPointer left, MaterialPointer right) { + return left->getPriority() < right->getPriority(); + } +}; + +class MultiMaterial : public std::priority_queue, MaterialCompare> { +public: + bool remove(const MaterialPointer& value) { + auto it = std::find(c.begin(), c.end(), value); + if (it != c.end()) { + c.erase(it); + std::make_heap(c.begin(), c.end(), comp); + return true; + } else { + return false; + } + } +}; + }; #endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 1fe3648838..32deba3687 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -549,7 +549,6 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, im auto map = std::make_shared(); if (texture) { map->setTextureSource(texture->_textureSource); - emit textureFinished(); } return map; @@ -728,6 +727,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!occlusionName.isEmpty()) { auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); + // FIXME: we need to handle the occlusion map transform here auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); setTextureMap(MapChannel::OCCLUSION_MAP, map); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 575f94f9bf..bbb00d72eb 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -156,8 +156,7 @@ private: virtual ~ModelCache() = default; }; -class NetworkMaterial : public QObject, public graphics::Material { - Q_OBJECT +class NetworkMaterial : public graphics::Material { public: using MapChannel = graphics::Material::MapChannel; @@ -174,9 +173,6 @@ public: void setScatteringMap(const QString& url); void setLightmapMap(const QString& url); -signals: - void textureFinished(); - protected: friend class Geometry; diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index a2aad33058..7108f9a4e4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -381,6 +381,17 @@ bool OctreePacketData::appendValue(float value) { return success; } +bool OctreePacketData::appendValue(const glm::vec2& value) { + const unsigned char* data = (const unsigned char*)&value; + int length = sizeof(value); + bool success = append(data, length); + if (success) { + _bytesOfValues += length; + _totalBytesOfValues += length; + } + return success; +} + bool OctreePacketData::appendValue(const glm::vec3& value) { const unsigned char* data = (const unsigned char*)&value; int length = sizeof(value); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 7f8eb49101..85100ec177 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -164,6 +164,9 @@ public: /// appends a float value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(float value); + /// appends a vec2 to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const glm::vec2& value); + /// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::vec3& value); @@ -250,8 +253,8 @@ public: static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } - static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b80327cf14..d24843c87d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -47,7 +47,7 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material) { updateMeshPart(mesh, partIndex); - updateMaterial(material); + addMaterial(material); } void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { @@ -67,8 +67,12 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor _worldBound.transform(_drawTransform); } -void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { - _drawMaterial = drawMaterial; +void MeshPartPayload::addMaterial(graphics::MaterialPointer material) { + _drawMaterials.push(material); +} + +void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { + _drawMaterials.remove(material); } void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { @@ -85,8 +89,8 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) builder.withLayered(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -105,8 +109,8 @@ Item::Bound MeshPartPayload::getBound() const { ShapeKey MeshPartPayload::getShapeKey() const { graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } ShapeKey::Builder builder; @@ -160,7 +164,7 @@ void MeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! @@ -252,7 +256,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) { auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { - _drawMaterial = networkMaterial; + addMaterial(networkMaterial); } } @@ -298,8 +302,8 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withDeformed(); } - if (_drawMaterial) { - auto matKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + auto matKey = _drawMaterials.top()->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); } @@ -329,8 +333,8 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe } graphics::MaterialKey drawMaterialKey; - if (_drawMaterial) { - drawMaterialKey = _drawMaterial->getKey(); + if (_drawMaterials.top()) { + drawMaterialKey = _drawMaterials.top()->getKey(); } bool isTranslucent = drawMaterialKey.isTranslucent(); @@ -411,7 +415,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing); + args->_shapePipeline->bindMaterial(_drawMaterials.top(), batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index b9ae47fb6a..e6893f1ea7 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -39,8 +39,6 @@ public: virtual void notifyLocationChanged() {} void updateTransform(const Transform& transform, const Transform& offsetTransform); - virtual void updateMaterial(graphics::MaterialPointer drawMaterial); - // Render Item interface virtual render::ItemKey getKey() const; virtual render::Item::Bound getBound() const; @@ -63,13 +61,16 @@ public: mutable graphics::Box _worldBound; std::shared_ptr _drawMesh; - std::shared_ptr _drawMaterial; + graphics::MultiMaterial _drawMaterials; graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } - int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } - bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureSize() : 0; } + int getMaterialTextureCount() { return _drawMaterials.top() ? _drawMaterials.top()->getTextureCount() : 0; } + bool hasTextureInfo() const { return _drawMaterials.top() ? _drawMaterials.top()->hasTextureInfo() : false; } + + void addMaterial(graphics::MaterialPointer material); + void removeMaterial(graphics::MaterialPointer material); protected: render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b9ccc28c01..805995edfb 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1524,6 +1524,50 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } +void Model::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + +void Model::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + render::Transaction transaction; + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.removeMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); + } +} + class CollisionRenderGeometry : public Geometry { public: CollisionRenderGeometry(graphics::MeshPointer mesh) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ca0904f334..80067aff2a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -318,6 +318,9 @@ public: void scaleToFit(); + void addMaterial(graphics::MaterialPointer material, quint16 shapeID); + void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + public slots: void loadURLFinished(bool success); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1763713831..6196a4c5d4 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -342,7 +342,7 @@ var toolBar = (function () { var buttonHandlers = {}; // only used to tablet mode - function addButton(name, image, handler) { + function addButton(name, handler) { buttonHandlers[name] = handler; } @@ -399,7 +399,7 @@ var toolBar = (function () { function handleNewMaterialDialogResult(result) { if (result) { - var json = result.textInput; + var materialURL = result.textInput; var materialMode; switch (result.comboBox) { case MATERIAL_MODE_PROJECTED: @@ -409,11 +409,13 @@ var toolBar = (function () { shapeType = "uv"; } - if (json) { + var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1; + if (materialURL) { createNewEntity({ type: "Material", - materialURL: json, - materialMode: materialMode + materialURL: materialURL, + materialMode: materialMode, + priority: DEFAULT_LAYERED_MATERIAL_PRIORITY }); } } @@ -475,32 +477,22 @@ var toolBar = (function () { that.toggle(); }); - addButton("importEntitiesButton", "assets-01.svg", function() { + addButton("importEntitiesButton", function() { Window.browseChanged.connect(onFileOpenChanged); Window.browseAsync("Select Model to Import", "", "*.json"); }); - addButton("openAssetBrowserButton", "assets-01.svg", function() { + addButton("openAssetBrowserButton", function() { Window.showAssetServer(); }); - addButton("newModelButton", "model-01.svg", function () { - - 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"; - SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box"; - SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere"; - var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; - + addButton("newModelButton", function () { // tablet version of new-model dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml"); }); - addButton("newCubeButton", "cube-01.svg", function () { + addButton("newCubeButton", function () { createNewEntity({ type: "Box", dimensions: DEFAULT_DIMENSIONS, @@ -512,7 +504,7 @@ var toolBar = (function () { }); }); - addButton("newSphereButton", "sphere-01.svg", function () { + addButton("newSphereButton", function () { createNewEntity({ type: "Sphere", dimensions: DEFAULT_DIMENSIONS, @@ -524,7 +516,7 @@ var toolBar = (function () { }); }); - addButton("newLightButton", "light-01.svg", function () { + addButton("newLightButton", function () { createNewEntity({ type: "Light", dimensions: DEFAULT_LIGHT_DIMENSIONS, @@ -543,7 +535,7 @@ var toolBar = (function () { }); }); - addButton("newTextButton", "text-01.svg", function () { + addButton("newTextButton", function () { createNewEntity({ type: "Text", dimensions: { @@ -566,7 +558,7 @@ var toolBar = (function () { }); }); - addButton("newWebButton", "web-01.svg", function () { + addButton("newWebButton", function () { createNewEntity({ type: "Web", dimensions: { @@ -578,7 +570,7 @@ var toolBar = (function () { }); }); - addButton("newZoneButton", "zone-01.svg", function () { + addButton("newZoneButton", function () { createNewEntity({ type: "Zone", dimensions: { @@ -589,7 +581,7 @@ var toolBar = (function () { }); }); - addButton("newParticleButton", "particle-01.svg", function () { + addButton("newParticleButton", function () { createNewEntity({ type: "ParticleEffect", isEmitting: true, @@ -642,15 +634,10 @@ var toolBar = (function () { }); }); - addButton("newMaterialButton", "model-01.svg", function () { - var MATERIAL_MODES = []; - MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material"; - MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material"; - var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV; - + addButton("newMaterialButton", function () { // tablet version of new material dialog var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - tablet.pushOntoStack("NewMaterialDialog.qml"); + tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml"); }); that.setActive(false); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 96084f355f..dd266311ea 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -645,14 +645,14 @@ hr { margin-left: 10px; } -.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label { +.text label, .url label, .number label, .textarea label, .xy label, .wh label, .rgb label, .xyz label,.pyr label, .dropdown label, .gen label { float: left; margin-left: 1px; margin-bottom: 3px; margin-top: -2px; } -.text legend, .url legend, .number legend, .textarea legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { +.text legend, .url legend, .number legend, .textarea legend, .xy legend, .wh legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend { float: left; margin-left: 1px; margin-bottom: 3px; @@ -667,7 +667,7 @@ hr { clear: both; float: left; } -.xyz > div, .pyr > div, .gen > div { +.xy > div, .wh > div, .xyz > div, .pyr > div, .gen > div { clear: both; } @@ -841,6 +841,12 @@ div.refresh input[type="button"] { margin-right: -6px; } +.xy .tuple input { + padding-left: 25px; +} +.wh .tuple input { + padding-left: 45px; +} .rgb .tuple input { padding-left: 65px; } diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 93d22180c9..348d93d589 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -787,7 +787,7 @@
- +
@@ -795,13 +795,26 @@
-
- -
-
-
-
-
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 64f706ce1f..3558a36c04 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -25,7 +25,7 @@ var ICON_FOR_TYPE = { PolyVox: "", Multiple: "", PolyLine: "", - Material: "" + Material: "" }; var EDITOR_TIMEOUT_DURATION = 1500; @@ -167,6 +167,17 @@ function createEmitGroupTextPropertyUpdateFunction(group, propertyName) { }; } +function createEmitVec2PropertyUpdateFunction(property, elX, elY) { + return function () { + var properties = {}; + properties[property] = { + x: elX.value, + y: elY.value + }; + updateProperties(properties); + }; +} + function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) { return function() { var properties = {}; @@ -192,19 +203,6 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el }; } -function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) { - return function () { - var properties = {}; - properties[property] = { - x: elX.value, - y: elY.value, - z: elZ.value, - w: elW.value - }; - updateProperties(properties); - }; -} - function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) { return function() { var properties = {}; @@ -638,10 +636,11 @@ function loaded() { var elBlendFactor = document.getElementById("property-blend-factor"); var elPriority = document.getElementById("property-priority"); var elShapeID = document.getElementById("property-shape-id"); - var elMaterialBoundsX = document.getElementById("property-material-bounds-x"); - var elMaterialBoundsY = document.getElementById("property-material-bounds-y"); - var elMaterialBoundsZ = document.getElementById("property-material-bounds-z"); - var elMaterialBoundsW = document.getElementById("property-material-bounds-w"); + var elMaterialPosX = document.getElementById("property-material-pos-x"); + var elMaterialPosY = document.getElementById("property-material-pos-y"); + var elMaterialScaleX = document.getElementById("property-material-scale-x"); + var elMaterialScaleY = document.getElementById("property-material-scale-y"); + var elMaterialRot = document.getElementById("property-material-rot"); var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -1134,10 +1133,11 @@ function loaded() { elBlendFactor.value = properties.blendFactor.toFixed(2); elPriority.value = properties.priority; elShapeID.value = properties.shapeID; - elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2); - elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2); - elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2); - //elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2); + elMaterialPosX.value = properties.materialPos.x.toFixed(4); + elMaterialPosY.value = properties.materialPos.y.toFixed(4); + elMaterialScaleX.value = properties.materialScale.x.toFixed(4); + elMaterialScaleY.value = properties.materialScale.y.toFixed(4); + elMaterialRot.value = properties.materialRot.toFixed(2); } if (properties.locked) { @@ -1411,15 +1411,16 @@ function loaded() { elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); - elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority')); - elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID')); + elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0)); + elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0)); - var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds', - elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW); - elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction); - elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction); + var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY); + elMaterialPosX.addEventListener('change', materialPosChangeFunction); + elMaterialPosY.addEventListener('change', materialPosChangeFunction); + var materialScaleChangeFunction = createEmitVec2PropertyUpdateFunction('materialScale', elMaterialScaleX, elMaterialScaleY); + elMaterialScaleX.addEventListener('change', materialScaleChangeFunction); + elMaterialScaleY.addEventListener('change', materialScaleChangeFunction); + elMaterialRot.addEventListener('change', createEmitNumberPropertyUpdateFunction('materialRot', 2)); elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera')); diff --git a/tools/jsdoc/package-lock.json b/tools/jsdoc/package-lock.json new file mode 100644 index 0000000000..073bbf60f6 --- /dev/null +++ b/tools/jsdoc/package-lock.json @@ -0,0 +1,138 @@ +{ + "name": "hifiJSDoc", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==" + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", + "requires": { + "underscore-contrib": "0.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "requires": { + "xmlcreate": "1.0.2" + } + }, + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "requires": { + "babylon": "7.0.0-beta.19", + "bluebird": "3.5.1", + "catharsis": "0.8.9", + "escape-string-regexp": "1.0.5", + "js2xmlparser": "3.0.0", + "klaw": "2.0.0", + "marked": "0.3.12", + "mkdirp": "0.5.1", + "requizzle": "0.2.1", + "strip-json-comments": "2.0.1", + "taffydb": "2.6.2", + "underscore": "1.8.3" + } + }, + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "marked": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz", + "integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" + } + } +} From 35bf8f1d01f6b1bb8172eb887cf354e08afa7558 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 16:24:54 -0500 Subject: [PATCH 31/83] [Case 4315] ESLint Pass; Simple errors addressed (details below). Initial ESLint Pass on colpick.js. Issue Count reduced from 185 to 100 via: eslint -c .eslintrc.js scripts/system/html/js/colpick.js --fix Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 149 +++++++++++++++++------------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 99054c6103..b19cbe0bae 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -25,15 +25,15 @@ For usage and examples: colpick.com/plugin submitText: 'OK', height: 156 }, - //Fill the inputs of the plugin - fillRGBFields = function (hsb, cal) { + // Fill the inputs of the plugin + fillRGBFields = function (hsb, cal) { var rgb = hsbToRgb(hsb); $(cal).data('colpick').fields .eq(1).val(rgb.r).end() .eq(2).val(rgb.g).end() .eq(3).val(rgb.b).end(); }, - fillHSBFields = function (hsb, cal) { + fillHSBFields = function (hsb, cal) { $(cal).data('colpick').fields .eq(4).val(Math.round(hsb.h)).end() .eq(5).val(Math.round(hsb.s)).end() @@ -42,7 +42,7 @@ For usage and examples: colpick.com/plugin fillHexFields = function (hsb, cal) { $(cal).data('colpick').fields.eq(0).val(hsbToHex(hsb)); }, - //Set the round selector position + // Set the round selector position setSelector = function (hsb, cal) { $(cal).data('colpick').selector.css('backgroundColor', '#' + hsbToHex({h: hsb.h, s: 100, b: 100})); $(cal).data('colpick').selectorIndic.css({ @@ -50,18 +50,18 @@ For usage and examples: colpick.com/plugin top: parseInt($(cal).data('colpick').height * (100-hsb.b)/100, 10) }); }, - //Set the hue selector position + // Set the hue selector position setHue = function (hsb, cal) { $(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h/360, 10)); }, - //Set current and new colors + // Set current and new colors setCurrentColor = function (hsb, cal) { $(cal).data('colpick').currentColor.css('backgroundColor', '#' + hsbToHex(hsb)); }, setNewColor = function (hsb, cal) { $(cal).data('colpick').newColor.css('backgroundColor', '#' + hsbToHex(hsb)); }, - //Called when the new color is changed + // Called when the new color is changed change = function (ev) { var cal = $(this).parent().parent(), col; if (this.parentNode.className.indexOf('_hex') > 0) { @@ -93,7 +93,7 @@ For usage and examples: colpick.com/plugin setNewColor(col, cal.get(0)); cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); }, - //Change style on blur and on focus of inputs + // Change style on blur and on focus of inputs blur = function (ev) { $(this).parent().removeClass('colpick_focus'); }, @@ -101,7 +101,7 @@ For usage and examples: colpick.com/plugin $(this).parent().parent().data('colpick').fields.parent().removeClass('colpick_focus'); $(this).parent().addClass('colpick_focus'); }, - //Increment/decrement arrows functions + // Increment/decrement arrows functions downIncrement = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var field = $(this).parent().find('input').focus(); @@ -130,7 +130,7 @@ For usage and examples: colpick.com/plugin $(document).off('mousemove', moveIncrement); return false; }, - //Hue slider functions + // Hue slider functions downHue = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var current = { @@ -143,7 +143,7 @@ For usage and examples: colpick.com/plugin var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( current.cal.data('colpick') - .fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10)) + .fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10)) .get(0), [current.cal.data('colpick').livePreview] ); @@ -153,7 +153,7 @@ For usage and examples: colpick.com/plugin var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( ev.data.cal.data('colpick') - .fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10)) + .fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10)) .get(0), [ev.data.preview] ); @@ -166,7 +166,7 @@ For usage and examples: colpick.com/plugin $(document).off('mousemove touchmove',moveHue); return false; }, - //Color selector functions + // Color selector functions downSelector = function (ev) { ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; var current = { @@ -179,7 +179,7 @@ For usage and examples: colpick.com/plugin $(document).on('mousemove touchmove',current,moveSelector); var payeX,pageY; - if(ev.type == 'touchstart') { + if (ev.type == 'touchstart') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; } else { @@ -189,16 +189,16 @@ For usage and examples: colpick.com/plugin change.apply( current.cal.data('colpick').fields - .eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end() - .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) - .get(0), + .eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end() + .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) + .get(0), [current.preview] ); return false; }, moveSelector = function (ev) { var payeX,pageY; - if(ev.type == 'touchmove') { + if (ev.type == 'touchmove') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; } else { @@ -208,9 +208,9 @@ For usage and examples: colpick.com/plugin change.apply( ev.data.cal.data('colpick').fields - .eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end() - .eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10)) - .get(0), + .eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end() + .eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10)) + .get(0), [ev.data.preview] ); return false; @@ -222,7 +222,7 @@ For usage and examples: colpick.com/plugin $(document).off('mousemove touchmove',moveSelector); return false; }, - //Submit button + // Submit button clickSubmit = function (ev) { var cal = $(this).parent(); var col = cal.data('colpick').color; @@ -230,7 +230,7 @@ For usage and examples: colpick.com/plugin setCurrentColor(col, cal.get(0)); cal.data('colpick').onSubmit(col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el); }, - //Show/hide the color picker + // Show/hide the color picker show = function (ev) { // Prevent the trigger of any direct parent ev.stopPropagation(); @@ -248,9 +248,11 @@ For usage and examples: colpick.com/plugin if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) { cal.show(); } - //Hide when user clicks outside + // Hide when user clicks outside $('html').mousedown({cal:cal}, hide); - cal.mousedown(function(ev){ev.stopPropagation();}) + cal.mousedown(function(ev){ + ev.stopPropagation(); + }); }, hide = function (ev) { if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) { @@ -265,7 +267,7 @@ For usage and examples: colpick.com/plugin w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth) }; }, - //Fix the values if the user enters a negative or high value + // Fix the values if the user enters a negative or high value fixHSB = function (hsb) { return { h: Math.min(360, Math.max(0, hsb.h)), @@ -309,8 +311,8 @@ For usage and examples: colpick.com/plugin return { init: function (opt) { opt = $.extend({}, defaults, opt||{}); - //Set color - if (typeof opt.color == 'string') { + // Set color + if (typeof opt.color === 'string') { opt.color = hexToHsb(opt.color); } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) { opt.color = rgbToHsb(opt.color); @@ -320,44 +322,44 @@ For usage and examples: colpick.com/plugin return this; } - //For each selected DOM element + // For each selected DOM element return this.each(function () { - //If the element does not have an ID + // If the element does not have an ID if (!$(this).data('colpickId')) { var options = $.extend({}, opt); options.origColor = opt.color; - //Generate and assign a random ID + // Generate and assign a random ID var id = 'collorpicker_' + parseInt(Math.random() * 1000); $(this).data('colpickId', id); - //Set the tpl's ID and get the HTML + // Set the tpl's ID and get the HTML var cal = $(tpl).attr('id', id); - //Add class according to layout + // Add class according to layout cal.addClass('colpick_'+options.layout+(options.submit?'':' colpick_'+options.layout+'_ns')); - //Add class if the color scheme is not default - if(options.colorScheme != 'light') { + // Add class if the color scheme is not default + if (options.colorScheme != 'light') { cal.addClass('colpick_'+options.colorScheme); } - //Setup submit button + // Setup submit button cal.find('div.colpick_submit').html(options.submitText).click(clickSubmit); - //Setup input fields + // Setup input fields options.fields = cal.find('input').change(change).blur(blur).focus(focus); cal.find('div.colpick_field_arrs').mousedown(downIncrement).end().find('div.colpick_current_color').click(restoreOriginal); - //Setup hue selector + // Setup hue selector options.selector = cal.find('div.colpick_color').on('mousedown touchstart',downSelector); options.selectorIndic = options.selector.find('div.colpick_selector_outer'); - //Store parts of the plugin + // Store parts of the plugin options.el = this; options.hue = cal.find('div.colpick_hue_arrs'); huebar = options.hue.parent(); - //Paint the hue bar + // Paint the hue bar var UA = navigator.userAgent.toLowerCase(); var isIE = navigator.appName === 'Microsoft Internet Explorer'; var IEver = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[\.0-9]{0,})/ )[1] ) : 0; var ngIE = ( isIE && IEver < 10 ); var stops = ['#ff0000','#ff0080','#ff00ff','#8000ff','#0000ff','#0080ff','#00ffff','#00ff80','#00ff00','#80ff00','#ffff00','#ff8000','#ff0000']; - if(ngIE) { + if (ngIE) { var i, div; - for(i=0; i<=11; i++) { + for (i=0; i<=11; i++) { div = $('
').attr('style','height:8.333333%; filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+')";'); huebar.append(div); } @@ -368,7 +370,7 @@ For usage and examples: colpick.com/plugin cal.find('div.colpick_hue').on('mousedown touchstart',downHue); options.newColor = cal.find('div.colpick_new_color'); options.currentColor = cal.find('div.colpick_current_color'); - //Store options and fill with default color + // Store options and fill with default color cal.data('colpick', options); fillRGBFields(options.color, cal.get(0)); fillHSBFields(options.color, cal.get(0)); @@ -377,7 +379,7 @@ For usage and examples: colpick.com/plugin setSelector(options.color, cal.get(0)); setCurrentColor(options.color, cal.get(0)); setNewColor(options.color, cal.get(0)); - //Append to body if flat=false, else show in place + // Append to body if flat=false, else show in place if (options.flat) { cal.appendTo(this).show(); cal.css({ @@ -394,7 +396,7 @@ For usage and examples: colpick.com/plugin } }); }, - //Shows the picker + // Shows the picker showPicker: function() { return this.each( function () { if ($(this).data('colpickId')) { @@ -402,7 +404,7 @@ For usage and examples: colpick.com/plugin } }); }, - //Hides the picker + // Hides the picker hidePicker: function() { return this.each( function () { if ($(this).data('colpickId')) { @@ -410,10 +412,10 @@ For usage and examples: colpick.com/plugin } }); }, - //Sets a color as new and current (default) + // Sets a color as new and current (default) setColor: function(col, setCurrent) { setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent; - if (typeof col == 'string') { + if (typeof col === 'string') { col = hexToHsb(col); } else if (col.r != undefined && col.g != undefined && col.b != undefined) { col = rgbToHsb(col); @@ -435,7 +437,7 @@ For usage and examples: colpick.com/plugin setNewColor(col, cal.get(0)); cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); - if(setCurrent) { + if (setCurrent) { setCurrentColor(col, cal.get(0)); } } @@ -443,7 +445,7 @@ For usage and examples: colpick.com/plugin } }; }(); - //Color space convertions + // Color space convertions var hexToRgb = function (hex) { var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)}; @@ -459,12 +461,20 @@ For usage and examples: colpick.com/plugin hsb.b = max; hsb.s = max != 0 ? 255 * delta / max : 0; if (hsb.s != 0) { - if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta; - else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta; - else hsb.h = 4 + (rgb.r - rgb.g) / delta; - } else hsb.h = -1; + if (rgb.r == max) { + hsb.h = (rgb.g - rgb.b) / delta; + } else if (rgb.g == max) { + hsb.h = 2 + (rgb.b - rgb.r) / delta; + } else { + hsb.h = 4 + (rgb.r - rgb.g) / delta; + } + } else { + hsb.h = -1; + } hsb.h *= 60; - if (hsb.h < 0) hsb.h += 360; + if (hsb.h < 0) { + hsb.h += 360; + } hsb.s *= 100/255; hsb.b *= 100/255; return hsb; @@ -474,20 +484,30 @@ For usage and examples: colpick.com/plugin var h = hsb.h; var s = hsb.s*255/100; var v = hsb.b*255/100; - if(s == 0) { + if (s == 0) { rgb.r = rgb.g = rgb.b = v; } else { var t1 = v; var t2 = (255-s)*v/255; var t3 = (t1-t2)*(h%60)/60; - if(h==360) h = 0; - if(h<60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3} - else if(h<120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3} - else if(h<180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3} - else if(h<240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3} - else if(h<300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3} - else if(h<360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3} - else {rgb.r=0; rgb.g=0; rgb.b=0} + if (h==360) { + h = 0; + } + if (h<60) { + rgb.r=t1; rgb.b=t2; rgb.g=t2+t3; + } else if (h<120) { + rgb.g=t1; rgb.b=t2; rgb.r=t1-t3; + } else if (h<180) { + rgb.g=t1; rgb.r=t2; rgb.b=t2+t3; + } else if (h<240) { + rgb.b=t1; rgb.r=t2; rgb.g=t1-t3; + } else if (h<300) { + rgb.b=t1; rgb.g=t2; rgb.r=t2+t3; + } else if (h<360) { + rgb.r=t1; rgb.g=t2; rgb.b=t1-t3; + } else { + rgb.r=0; rgb.g=0; rgb.b=0; + } } return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)}; }; @@ -524,3 +544,4 @@ For usage and examples: colpick.com/plugin } }); })(jQuery); + From 691aafcf29e20ef2507cf71c3ea1b383fb0f2242 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 16:42:43 -0500 Subject: [PATCH 32/83] [Case 4315] ESLint Pass 2 for colpick.js (details below). Resolves all error Line exceeds the maximum line length of 128 max-len issues. Issue Count reduced from 85 to 70. Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 78 +++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index b19cbe0bae..feb584aa1d 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -1,6 +1,7 @@ /* colpick Color Picker -Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed under the MIT and GPL licenses +Copyright 2013 Jose Vargas. Licensed under GPL license. Based on Stefan Petre's Color Picker www.eyecon.ro, dual licensed +under the MIT and GPL licenses For usage and examples: colpick.com/plugin */ @@ -8,7 +9,31 @@ For usage and examples: colpick.com/plugin (function ($) { var colpick = function () { var - tpl = '
#
R
G
B
H
S
B
', + tpl = '
' + + '
' + + '
' + + '
' + + '
' + + '
#
' + + '
' + + '
R
' + + '
' + + '
' + + '
G
' + + '
' + + '
B
' + + '
' + + '
' + + '
H
' + + '
' + + '
' + + '
S
' + + '
' + + '
' + + '
B
' + + '
' + + '
' + + '
', defaults = { showEvent: 'click', onShow: function () {}, @@ -52,7 +77,8 @@ For usage and examples: colpick.com/plugin }, // Set the hue selector position setHue = function (hsb, cal) { - $(cal).data('colpick').hue.css('top', parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h/360, 10)); + $(cal).data('colpick').hue.css('top', + parseInt($(cal).data('colpick').height - $(cal).data('colpick').height * hsb.h / 360, 10)); }, // Set current and new colors setCurrentColor = function (hsb, cal) { @@ -91,7 +117,8 @@ For usage and examples: colpick.com/plugin setSelector(col, cal.get(0)); setHue(col, cal.get(0)); setNewColor(col, cal.get(0)); - cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); + cal.data('colpick').onChange.apply(cal.parent(), + [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 0]); }, // Change style on blur and on focus of inputs blur = function (ev) { @@ -107,7 +134,8 @@ For usage and examples: colpick.com/plugin var field = $(this).parent().find('input').focus(); var current = { el: $(this).parent().addClass('colpick_slider'), - max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255), + max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : + (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255), y: ev.pageY, field: field, val: parseInt(field.val(), 10), @@ -143,7 +171,8 @@ For usage and examples: colpick.com/plugin var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( current.cal.data('colpick') - .fields.eq(4).val(parseInt(360*(current.cal.data('colpick').height - (pageY - current.y))/current.cal.data('colpick').height, 10)) + .fields.eq(4).val(parseInt(360 * (current.cal.data('colpick').height - + (pageY - current.y)) / current.cal.data('colpick').height, 10)) .get(0), [current.cal.data('colpick').livePreview] ); @@ -153,7 +182,9 @@ For usage and examples: colpick.com/plugin var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( ev.data.cal.data('colpick') - .fields.eq(4).val(parseInt(360*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.y))))/ev.data.cal.data('colpick').height, 10)) + .fields.eq(4).val(parseInt(360 * (ev.data.cal.data('colpick').height - + Math.max(0, Math.min(ev.data.cal.data('colpick').height, (pageY - ev.data.y)))) / + ev.data.cal.data('colpick').height, 10)) .get(0), [ev.data.preview] ); @@ -189,7 +220,8 @@ For usage and examples: colpick.com/plugin change.apply( current.cal.data('colpick').fields - .eq(6).val(parseInt(100*(current.cal.data('colpick').height - (pageY - current.pos.top))/current.cal.data('colpick').height, 10)).end() + .eq(6).val(parseInt(100 * (current.cal.data('colpick').height - (pageY - current.pos.top)) / + current.cal.data('colpick').height, 10)).end() .eq(5).val(parseInt(100*(pageX - current.pos.left)/current.cal.data('colpick').height, 10)) .get(0), [current.preview] @@ -208,8 +240,11 @@ For usage and examples: colpick.com/plugin change.apply( ev.data.cal.data('colpick').fields - .eq(6).val(parseInt(100*(ev.data.cal.data('colpick').height - Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageY - ev.data.pos.top))))/ev.data.cal.data('colpick').height, 10)).end() - .eq(5).val(parseInt(100*(Math.max(0,Math.min(ev.data.cal.data('colpick').height,(pageX - ev.data.pos.left))))/ev.data.cal.data('colpick').height, 10)) + .eq(6).val(parseInt(100 * (ev.data.cal.data('colpick').height - + Math.max(0, Math.min(ev.data.cal.data('colpick').height, (pageY - ev.data.pos.top)))) / + ev.data.cal.data('colpick').height, 10)).end() + .eq(5).val(parseInt(100 * (Math.max(0, Math.min(ev.data.cal.data('colpick').height, + (pageX - ev.data.pos.left)))) / ev.data.cal.data('colpick').height, 10)) .get(0), [ev.data.preview] ); @@ -343,7 +378,8 @@ For usage and examples: colpick.com/plugin cal.find('div.colpick_submit').html(options.submitText).click(clickSubmit); // Setup input fields options.fields = cal.find('input').change(change).blur(blur).focus(focus); - cal.find('div.colpick_field_arrs').mousedown(downIncrement).end().find('div.colpick_current_color').click(restoreOriginal); + cal.find('div.colpick_field_arrs').mousedown(downIncrement); + cal.find('div.colpick_current_color').click(restoreOriginal); // Setup hue selector options.selector = cal.find('div.colpick_color').on('mousedown touchstart',downSelector); options.selectorIndic = options.selector.find('div.colpick_selector_outer'); @@ -356,16 +392,27 @@ For usage and examples: colpick.com/plugin var isIE = navigator.appName === 'Microsoft Internet Explorer'; var IEver = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[\.0-9]{0,})/ )[1] ) : 0; var ngIE = ( isIE && IEver < 10 ); - var stops = ['#ff0000','#ff0080','#ff00ff','#8000ff','#0000ff','#0080ff','#00ffff','#00ff80','#00ff00','#80ff00','#ffff00','#ff8000','#ff0000']; + var stops = ['#ff0000', '#ff0080', '#ff00ff', '#8000ff', '#0000ff', '#0080ff', '#00ffff', '#00ff80', + '#00ff00', '#80ff00', '#ffff00', '#ff8000', '#ff0000']; if (ngIE) { var i, div; for (i=0; i<=11; i++) { - div = $('
').attr('style','height:8.333333%; filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='+stops[i]+', endColorstr='+stops[i+1]+')";'); + div = $('
').attr('style', + 'height:8.333333%; filter:progid:' + + 'DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=' + stops[i] + + ', endColorstr=' + stops[i + 1] + + '); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=' + + stops[i] + ', endColorstr=' + stops[i + 1] + ')";'); huebar.append(div); } } else { stopList = stops.join(','); - huebar.attr('style','background:-webkit-linear-gradient(top,'+stopList+'); background: -o-linear-gradient(top,'+stopList+'); background: -ms-linear-gradient(top,'+stopList+'); background:-moz-linear-gradient(top,'+stopList+'); -webkit-linear-gradient(top,'+stopList+'); background:linear-gradient(to bottom,'+stopList+'); '); + huebar.attr('style', 'background:-webkit-linear-gradient(top,' + stopList + + '); background: -o-linear-gradient(top,' + stopList + + '); background: -ms-linear-gradient(top,' + stopList + + '); background:-moz-linear-gradient(top,' + stopList + + '); -webkit-linear-gradient(top,' + stopList + + '); background:linear-gradient(to bottom,' + stopList + '); '); } cal.find('div.colpick_hue').on('mousedown touchstart',downHue); options.newColor = cal.find('div.colpick_new_color'); @@ -436,7 +483,8 @@ For usage and examples: colpick.com/plugin setSelector(col, cal.get(0)); setNewColor(col, cal.get(0)); - cal.data('colpick').onChange.apply(cal.parent(), [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); + cal.data('colpick').onChange.apply(cal.parent(), + [col, hsbToHex(col), hsbToRgb(col), cal.data('colpick').el, 1]); if (setCurrent) { setCurrentColor(col, cal.get(0)); } From 0a1e05326eeea6fdbb95aaf9176f19792ff6580e Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 16:49:44 -0500 Subject: [PATCH 33/83] [Case 4315] ESLint Pass 3, adds global declarations (details below). This resolves 23 error is not defined no-undef errors related to global objects. Issue Count reduced from 70 to 47. Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index feb584aa1d..0ac6996bde 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -6,6 +6,8 @@ under the MIT and GPL licenses For usage and examples: colpick.com/plugin */ +/* global console, document, Element, EventBridge, jQuery, navigator, window, _ $ */ + (function ($) { var colpick = function () { var From ef1fd19a982a67a5c1653671226d33f43c86f673 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 17:01:52 -0500 Subject: [PATCH 34/83] [Case 4315] ESLint Pass 4 for colpick.js (details below). Resolved payeX vs pageX issues. Resolved stopList & huebar undefined issues. Issue Count reduced from 47 to 29. Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 0ac6996bde..44e887056a 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -211,7 +211,7 @@ For usage and examples: colpick.com/plugin $(document).on('mouseup touchend',current,upSelector); $(document).on('mousemove touchmove',current,moveSelector); - var payeX,pageY; + var pageX,pageY; if (ev.type == 'touchstart') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; @@ -231,7 +231,7 @@ For usage and examples: colpick.com/plugin return false; }, moveSelector = function (ev) { - var payeX,pageY; + var pageX,pageY; if (ev.type == 'touchmove') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; @@ -388,7 +388,7 @@ For usage and examples: colpick.com/plugin // Store parts of the plugin options.el = this; options.hue = cal.find('div.colpick_hue_arrs'); - huebar = options.hue.parent(); + var huebar = options.hue.parent(); // Paint the hue bar var UA = navigator.userAgent.toLowerCase(); var isIE = navigator.appName === 'Microsoft Internet Explorer'; @@ -408,7 +408,7 @@ For usage and examples: colpick.com/plugin huebar.append(div); } } else { - stopList = stops.join(','); + var stopList = stops.join(','); huebar.attr('style', 'background:-webkit-linear-gradient(top,' + stopList + '); background: -o-linear-gradient(top,' + stopList + '); background: -ms-linear-gradient(top,' + stopList + From 83749b16c7811028e0e81aea69f6f34e9d08f8d7 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 17:35:03 -0500 Subject: [PATCH 35/83] [Case 4315] ESLint Pass 5 resolves hex already defined issue (details below). * var hex was declared both the hexToRGB and hexToHsb functions. * hexToRGB was updated to have a more explicit var name * hexToRGB & hexToHSB also had the function param name updated to clarify the expected object type. Also error statements and early returns were added should an unsupported object type be received. * Issue Count is now 28 Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 44e887056a..d748698cde 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -496,12 +496,22 @@ For usage and examples: colpick.com/plugin }; }(); // Color space convertions - var hexToRgb = function (hex) { - var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); - return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)}; + var hexToRgb = function (hexString) { + if (typeof hexString !== "string") { + print("Error - ColPick.js::hexToRgb expects string object."); + return; + } + + var hexNumber = parseInt(((hexString.indexOf('#') > -1) ? hexString.substring(1) : hexString), 16); + return { r: hexNumber >> 16, g: (hexNumber & 0x00FF00) >> 8, b: (hexNumber & 0x0000FF)}; }; - var hexToHsb = function (hex) { - return rgbToHsb(hexToRgb(hex)); + var hexToHsb = function (hexString) { + if (typeof hexString !== "string") { + print("Error - ColPick.js::hexToHsb expects string object."); + return; + } + + return rgbToHsb(hexToRgb(hexString)); }; var rgbToHsb = function (rgb) { var hsb = {h: 0, s: 0, b: 0}; From 59e0b8476aeca4fe7501df96d2488da7175db023 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 17:57:42 -0500 Subject: [PATCH 36/83] [Case 4315] ESLint Pass 6 Pt 1 for colpick.js (details below). First portion of vetted equality check fixes. Issue Count reduced from 28 to 8. Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index d748698cde..7c640633e3 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -170,7 +170,7 @@ For usage and examples: colpick.com/plugin $(document).on('mouseup touchend',current,upHue); $(document).on('mousemove touchmove',current,moveHue); - var pageY = ((ev.type == 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); + var pageY = ((ev.type === 'touchstart') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( current.cal.data('colpick') .fields.eq(4).val(parseInt(360 * (current.cal.data('colpick').height - @@ -181,7 +181,7 @@ For usage and examples: colpick.com/plugin return false; }, moveHue = function (ev) { - var pageY = ((ev.type == 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); + var pageY = ((ev.type === 'touchmove') ? ev.originalEvent.changedTouches[0].pageY : ev.pageY ); change.apply( ev.data.cal.data('colpick') .fields.eq(4).val(parseInt(360 * (ev.data.cal.data('colpick').height - @@ -212,7 +212,7 @@ For usage and examples: colpick.com/plugin $(document).on('mousemove touchmove',current,moveSelector); var pageX,pageY; - if (ev.type == 'touchstart') { + if (ev.type === 'touchstart') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; } else { @@ -232,7 +232,7 @@ For usage and examples: colpick.com/plugin }, moveSelector = function (ev) { var pageX,pageY; - if (ev.type == 'touchmove') { + if (ev.type === 'touchmove') { pageX = ev.originalEvent.changedTouches[0].pageX, pageY = ev.originalEvent.changedTouches[0].pageY; } else { @@ -282,7 +282,7 @@ For usage and examples: colpick.com/plugin left -= calW; } cal.css({left: left + 'px', top: top + 'px'}); - if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) != false) { + if (cal.data('colpick').onShow.apply(this, [cal.get(0)]) !== false) { cal.show(); } // Hide when user clicks outside @@ -292,13 +292,13 @@ For usage and examples: colpick.com/plugin }); }, hide = function (ev) { - if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) != false) { + if (ev.data.cal.data('colpick').onHide.apply(this, [ev.data.cal.get(0)]) !== false) { ev.data.cal.hide(); } $('html').off('mousedown', hide); }, getViewport = function () { - var m = document.compatMode == 'CSS1Compat'; + var m = document.compatMode === 'CSS1Compat'; return { l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft), w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth) @@ -351,9 +351,9 @@ For usage and examples: colpick.com/plugin // Set color if (typeof opt.color === 'string') { opt.color = hexToHsb(opt.color); - } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) { + } else if (opt.color.r !== undefined && opt.color.g !== undefined && opt.color.b !== undefined) { opt.color = rgbToHsb(opt.color); - } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) { + } else if (opt.color.h !== undefined && opt.color.s !== undefined && opt.color.b !== undefined) { opt.color = fixHSB(opt.color); } else { return this; @@ -373,7 +373,7 @@ For usage and examples: colpick.com/plugin // Add class according to layout cal.addClass('colpick_'+options.layout+(options.submit?'':' colpick_'+options.layout+'_ns')); // Add class if the color scheme is not default - if (options.colorScheme != 'light') { + if (options.colorScheme !== 'light') { cal.addClass('colpick_'+options.colorScheme); } // Setup submit button @@ -466,9 +466,9 @@ For usage and examples: colpick.com/plugin setCurrent = (typeof setCurrent === "undefined") ? 1 : setCurrent; if (typeof col === 'string') { col = hexToHsb(col); - } else if (col.r != undefined && col.g != undefined && col.b != undefined) { + } else if (col.r !== undefined && col.g !== undefined && col.b !== undefined) { col = rgbToHsb(col); - } else if (col.h != undefined && col.s != undefined && col.b != undefined) { + } else if (col.h !== undefined && col.s !== undefined && col.b !== undefined) { col = fixHSB(col); } else { return this; From fed85a7a5309200fca79e4dbdb28a3ec4a21effd Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 18:12:57 -0500 Subject: [PATCH 37/83] [Case 4315] ESLint Pass 6 Pt 2 for colpick equality checks (details below). * Suppressing equality checking issues within color conversion helper functions. * These issues are suppressed as opposed to resolved because their resolution causes issues with the color picker's understanding of the color it's being set to along with the respective hue. This is likely due to rounding issues; however, it may also be something related to the equality operator implicit conversions semantics of JavaScript. It's something that can be looked into later if desired. * Bug Steps upon resolving check as opposed to suppressing them: - Select a shape entity for example. - Note the visual color and actual RGB values for that entity's color upon selection. - Click the Color Wheel. - Notice the automatic change of the color for the entity when the picker is shown. - If the issue doesn't show itself right away, alter the color for the entity close the picker, and repeat steps 2-3. * Issue Count reduced from 8 to 1 Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 7c640633e3..94b5d8521c 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -519,11 +519,11 @@ For usage and examples: colpick.com/plugin var max = Math.max(rgb.r, rgb.g, rgb.b); var delta = max - min; hsb.b = max; - hsb.s = max != 0 ? 255 * delta / max : 0; - if (hsb.s != 0) { - if (rgb.r == max) { + hsb.s = max != 0 ? 255 * delta / max : 0; // eslint-disable-line eqeqeq + if (hsb.s != 0) { // eslint-disable-line eqeqeq + if (rgb.r == max) { // eslint-disable-line eqeqeq hsb.h = (rgb.g - rgb.b) / delta; - } else if (rgb.g == max) { + } else if (rgb.g == max) { // eslint-disable-line eqeqeq hsb.h = 2 + (rgb.b - rgb.r) / delta; } else { hsb.h = 4 + (rgb.r - rgb.g) / delta; @@ -544,13 +544,13 @@ For usage and examples: colpick.com/plugin var h = hsb.h; var s = hsb.s*255/100; var v = hsb.b*255/100; - if (s == 0) { + if (s == 0) { // eslint-disable-line eqeqeq rgb.r = rgb.g = rgb.b = v; } else { var t1 = v; var t2 = (255-s)*v/255; var t3 = (t1-t2)*(h%60)/60; - if (h==360) { + if (h==360) { // eslint-disable-line eqeqeq h = 0; } if (h<60) { @@ -578,7 +578,7 @@ For usage and examples: colpick.com/plugin rgb.b.toString(16) ]; $.each(hex, function (nr, val) { - if (val.length == 1) { + if (val.length == 1) { // eslint-disable-line eqeqeq hex[nr] = '0' + val; } }); From b058b346bd2059395f2fdc3e29455413979777f1 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 9 Feb 2018 18:25:50 -0500 Subject: [PATCH 38/83] [Case 4315] ESLint Pass 7 for colpick.js resolves regex error (details below). Issue Count for colpick is now 0. Changes Committed: modified: scripts/system/html/js/colpick.js --- scripts/system/html/js/colpick.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/html/js/colpick.js b/scripts/system/html/js/colpick.js index 94b5d8521c..199c624bc5 100644 --- a/scripts/system/html/js/colpick.js +++ b/scripts/system/html/js/colpick.js @@ -392,7 +392,7 @@ For usage and examples: colpick.com/plugin // Paint the hue bar var UA = navigator.userAgent.toLowerCase(); var isIE = navigator.appName === 'Microsoft Internet Explorer'; - var IEver = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[\.0-9]{0,})/ )[1] ) : 0; + var IEver = isIE ? parseFloat( UA.match( /msie ([0-9]{1,}[.0-9]{0,})/ )[1] ) : 0; var ngIE = ( isIE && IEver < 10 ); var stops = ['#ff0000', '#ff0080', '#ff00ff', '#8000ff', '#0000ff', '#0080ff', '#00ffff', '#00ff80', '#00ff00', '#80ff00', '#ffff00', '#ff8000', '#ff0000']; From abdd50fb455feacb2c27306a6322c5e4387e5b14 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 9 Feb 2018 14:58:48 -0800 Subject: [PATCH 39/83] it's a start --- .gitignore | 5 ++- .../hifi/commerce/common/FirstUseTutorial.qml | 4 +- .../hifi/commerce/purchases/PurchasedItem.qml | 42 ++++++++++-------- .../qml/hifi/commerce/purchases/Purchases.qml | 24 ++++++---- interface/resources/qml/js/Utils.jsc | Bin 6516 -> 6596 bytes scripts/system/commerce/wallet.js | 2 +- scripts/system/marketplaces/marketplaces.js | 5 ++- 7 files changed, 50 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index f45572c388..1ffb93fe80 100644 --- a/.gitignore +++ b/.gitignore @@ -85,4 +85,7 @@ npm-debug.log android/app/src/main/assets # Resource binary file -interface/compiledResources \ No newline at end of file +interface/compiledResources + +# GPUCache +interface/resources/GPUCache/* \ No newline at end of file diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml index bcc641acd5..9944838e03 100644 --- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml +++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml @@ -90,11 +90,11 @@ Rectangle { id: introText2; text: "My Purchases"; // Text size - size: 28; + size: 22; // Anchors anchors.top: introText1.bottom; anchors.left: parent.left; - anchors.leftMargin: 12; + anchors.leftMargin: 24; anchors.right: parent.right; height: paintedHeight; // Style diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 05e280b839..361b9931a4 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -39,7 +39,10 @@ Item { property int itemEdition; property int numberSold; property int limitedRun; - property bool isWearable; + property string itemType; + property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar"]; + property var buttonTextNormal: ["REZ", "WEAR", "SWAP", "INSTALL", "WEAR"]; + property var buttonTextClicked: ["REZZED", "WORN", "SWAPPED", "INSTALLED", "WORN"] property string originalStatusText; property string originalStatusColor; @@ -73,10 +76,10 @@ Item { color: hifi.colors.white; // Size anchors.left: parent.left; - anchors.leftMargin: 8; + anchors.leftMargin: 16; anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.top: parent.top; + anchors.rightMargin: 16; + anchors.verticalCenter: parent.verticalCenter; height: root.height - 10; Image { @@ -311,7 +314,7 @@ Item { id: rezzedNotifContainer; z: 998; visible: false; - color: hifi.colors.blueHighlight; + color: "#1FC6A6"; anchors.fill: buttonContainer; MouseArea { anchors.fill: parent; @@ -321,7 +324,7 @@ Item { RalewayBold { anchors.fill: parent; - text: "REZZED"; + text: (root.buttonTextClicked)[itemTypesArray.indexOf(root.itemType)]; size: 18; color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; @@ -337,25 +340,28 @@ Item { Button { id: buttonContainer; - property int color: hifi.buttons.red; + property int color: hifi.buttons.blue; property int colorScheme: hifi.colorSchemes.light; anchors.top: parent.top; + anchors.topMargin: 4; anchors.bottom: parent.bottom; + anchors.bottomMargin: 4; anchors.right: parent.right; + anchors.rightMargin: 4; width: height; - enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated"; + enabled: (root.canRezCertifiedItems || root.itemType === "wearable") && root.purchaseStatus !== "invalidated"; onClicked: { - sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable}); + sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.isWearable ? "rez" : "wear"); + UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.itemType === "wearable" ? "rez" : "wear"); } style: ButtonStyle { - background: Rectangle { + radius: 4; gradient: Gradient { GradientStop { position: 0.2 @@ -413,10 +419,10 @@ Item { font.capitalization: Font.AllUppercase color: enabled ? hifi.buttons.textColor[control.color] : hifi.buttons.disabledTextColor[control.colorScheme] - size: 16; + size: 15; verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter - text: root.isWearable ? "Wear It" : "Rez It" + text: (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)] } } } @@ -425,11 +431,11 @@ Item { DropShadow { anchors.fill: mainContainer; - horizontalOffset: 3; - verticalOffset: 3; - radius: 8.0; - samples: 17; - color: "#80000000"; + horizontalOffset: 0; + verticalOffset: 4; + radius: 4.0; + samples: 9 + color: Qt.rgba(0, 0, 0, 0.25); source: mainContainer; } diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 2743677683..922ba54822 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -308,11 +308,11 @@ Rectangle { anchors.bottom: parent.bottom; anchors.bottomMargin: 10; anchors.left: parent.left; - anchors.leftMargin: 4; + anchors.leftMargin: 16; width: paintedWidth; text: isShowingMyItems ? "My Items" : "My Purchases"; color: hifi.colors.baseGray; - size: 28; + size: 22; } HifiControlsUit.TextField { @@ -323,8 +323,8 @@ Rectangle { hasRoundedBorder: true; anchors.left: myText.right; anchors.leftMargin: 16; - anchors.top: parent.top; - anchors.bottom: parent.bottom; + height: 39; + anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; placeholderText: "filter items"; @@ -454,16 +454,24 @@ Rectangle { numberSold: model.number_sold; limitedRun: model.limited_run; displayedItemCount: model.displayedItemCount; - isWearable: model.categories.indexOf("Wearables") > -1; - anchors.topMargin: 12; - anchors.bottomMargin: 12; + itemType: { + if (model.download_url.indexOf(".fst") > -1) { + "avatar"; + } else if (model.categories.indexOf("Wearables") > -1) { + "wearable"; + } else { + "entity"; + } + } + anchors.topMargin: 10; + anchors.bottomMargin: 10; Connections { onSendToPurchases: { if (msg.method === 'purchases_itemInfoClicked') { sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId}); } else if (msg.method === "purchases_rezClicked") { - sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, isWearable: isWearable}); + sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, itemType: itemType}); } else if (msg.method === 'purchases_itemCertificateClicked') { inspectionCertificate.visible = true; inspectionCertificate.isLightbox = true; diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc index 8da68e4e192018ee2b4f3d835ec91f36f0161eca..ab20e996b9469915ac6a89901da175143e6b5024 100644 GIT binary patch delta 604 zcmexjbi`Pvu*@VmC9xz?kb!}Lfs>VC&A*2iV;C72bXXY}mb_f{tI)LMb*EnX9J{G= zWjE?fVPxWFpL~eXjmbb{GZ&K)lcEI!149}^CPNNGDuWe+J{UTKSV!qu$P@xQv&;%5r0+3J# zickeer~z51p@D&c!LzePrQ-kp|4@m^A9y8vAm%nqfJ$c|q`_`zm;seYK$lnmm56{y zI39Phm>j})kdv7eWRZ)?jLG}?J(xDJOx`D`JXuG8Z}JL$VaC6c_wai&DZm7I_&)Iq z-167~3SS0>5B8H41jOnE9)IGGd+4!a)=UuiXrJc6pLZgSU+*D*n>GUj15EV<2e8B^ z{2Kn8s9?FPGD3MA9~ zMq$_Fat`Uu69ftv87(F=3MGm|!vW+*kU5~R2l;h#rBDLn4g!mi%G zd85u0My4%nlMgYvF+C98%*ABHq-@E+z>vm}$&ka4%3#Hy4~8yaRtiHBLn1>mL-yoY zme9>xSavcq8f?zvxX;LFu-T8xhB-~cvzy7I+abZT(?w;5Z?~9lcMw!410*y7MW_HI z)PW*Y0TOCJ7HViFnI&N2cysApZo@sr}K+4E}OiT- Date: Fri, 9 Feb 2018 15:24:07 -0800 Subject: [PATCH 40/83] warnings, load material from URL, shapeID -> parentMaterialID --- assignment-client/src/assets/AssetServer.h | 7 +- interface/src/Application.cpp | 16 +- interface/src/ui/overlays/ModelOverlay.cpp | 12 +- interface/src/ui/overlays/ModelOverlay.h | 4 +- interface/src/ui/overlays/Overlay.cpp | 8 +- interface/src/ui/overlays/Overlay.h | 6 +- .../src/avatars-renderer/Avatar.cpp | 12 +- .../src/avatars-renderer/Avatar.h | 6 +- libraries/avatars/src/AvatarData.h | 4 +- .../src/RenderableEntityItem.cpp | 8 +- .../src/RenderableEntityItem.h | 6 +- .../src/RenderableMaterialEntityItem.cpp | 8 +- .../src/RenderableModelEntityItem.cpp | 12 +- .../src/RenderableModelEntityItem.h | 4 +- .../src/RenderableShapeEntityItem.cpp | 6 +- libraries/entities/src/EntityItem.cpp | 16 +- libraries/entities/src/EntityItem.h | 12 +- .../entities/src/EntityItemProperties.cpp | 28 +-- libraries/entities/src/EntityItemProperties.h | 3 +- libraries/entities/src/EntityPropertyFlags.h | 3 +- libraries/entities/src/EntityTree.cpp | 24 +- libraries/entities/src/EntityTree.h | 24 +- libraries/entities/src/MaterialEntityItem.cpp | 215 ++++-------------- libraries/entities/src/MaterialEntityItem.h | 15 +- libraries/graphics/src/graphics/Material.h | 4 - .../src/model-networking/MaterialCache.cpp | 175 ++++++++++++++ .../src/model-networking/MaterialCache.h | 46 ++++ .../src/model-networking/ModelCache.cpp | 2 +- libraries/networking/src/ResourceRequest.cpp | 2 +- libraries/render-utils/src/Model.cpp | 92 ++++---- libraries/render-utils/src/Model.h | 6 +- libraries/shared/src/RegisteredMetaTypes.h | 7 + scripts/system/html/entityProperties.html | 11 +- scripts/system/html/js/entityProperties.js | 9 +- 34 files changed, 447 insertions(+), 366 deletions(-) create mode 100644 libraries/model-networking/src/model-networking/MaterialCache.cpp create mode 100644 libraries/model-networking/src/model-networking/MaterialCache.h diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5e7a3c1700..1470249bf3 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -21,12 +21,7 @@ #include "AssetUtils.h" #include "ReceivedMessage.h" -namespace std { - template <> - struct hash { - size_t operator()(const QString& v) const { return qHash(v); } - }; -} +#include "RegisteredMetaTypes.h" struct AssetMeta { AssetMeta() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f8fa8f9b17..ce4027945d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1587,37 +1587,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->addMaterial(material, shapeID); + avatar->addMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->removeMaterial(material, shapeID); + avatar->removeMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->addMaterial(material, shapeID); + overlay->addMaterial(material, parentMaterialID); return true; } return false; }); - EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->removeMaterial(material, shapeID); + overlay->removeMaterial(material, parentMaterialID); return true; } return false; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index bf95494d19..ab7f55d6e7 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -633,17 +633,17 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { return 0; } -void ModelOverlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Overlay::addMaterial(material, shapeID); +void ModelOverlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Overlay::addMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, shapeID); + _model->addMaterial(material, parentMaterialID); } } -void ModelOverlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Overlay::removeMaterial(material, shapeID); +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Overlay::removeMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, shapeID); + _model->removeMaterial(material, parentMaterialID); } } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 827f7f2d5b..6761b1508c 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -59,8 +59,8 @@ public: void setDrawInFront(bool drawInFront) override; void setDrawHUDLayer(bool drawHUDLayer) override; - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; protected: Transform evalRenderTransform() override; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 368ed04062..04d6c2fe4d 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -236,12 +236,12 @@ QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { return newVector; } -void Overlay::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Overlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); } -void Overlay::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Overlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); } \ No newline at end of file diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 4cb3f7c84d..bd9f7942fd 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -91,8 +91,8 @@ public: unsigned int getStackOrder() const { return _stackOrder; } void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; } - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); protected: float updatePulse(); @@ -120,7 +120,7 @@ protected: static const xColor DEFAULT_OVERLAY_COLOR; static const float DEFAULT_ALPHA; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; private: diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 4cd9bbedd7..3276a8fe89 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1763,19 +1763,19 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { } } -void Avatar::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Avatar::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->addMaterial(material, shapeID); + _skeletonModel->addMaterial(material, parentMaterialID); } } -void Avatar::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void Avatar::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->removeMaterial(material, shapeID); + _skeletonModel->removeMaterial(material, parentMaterialID); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 9c355159d8..49aa664a9f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -272,8 +272,8 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; public slots: @@ -401,7 +401,7 @@ protected: ThreadSafeValueCache _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT }; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; void processMaterials(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index fbd586f153..832585a483 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -696,8 +696,8 @@ public: bool getIsReplicated() const { return _isReplicated; } - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID) {} - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) {} + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) {} + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) {} signals: void displayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 2f92790d18..81d7dceb0d 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -404,12 +404,12 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) { QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr); } -void EntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); + _materials[parentMaterialID].push(material); } -void EntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); + _materials[parentMaterialID].remove(material); } \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index f58b540aef..6247a97c21 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -102,8 +102,8 @@ protected: } public slots: - virtual void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - virtual void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); signals: void requestRenderUpdate(); @@ -133,7 +133,7 @@ protected: // Only touched on the rendering thread bool _renderUpdateQueued{ false }; - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; private: diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index d541d99c4c..ad17202d8e 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -102,10 +102,10 @@ void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::ve void MaterialEntityRenderer::addTriangleFan(std::vector& buffer, int stack, int step) { float v1 = ((float)stack) / STACKS; - float theta1 = v1 * M_PI; + float theta1 = v1 * (float)M_PI; glm::vec3 tip = getVertexPos(0, theta1); float v2 = ((float)(stack + step)) / STACKS; - float theta2 = v2 * M_PI; + float theta2 = v2 * (float)M_PI; for (int i = 0; i < SLICES; i++) { float u1 = ((float)i) / SLICES; float u2 = ((float)(i + step)) / SLICES; @@ -169,8 +169,8 @@ void MaterialEntityRenderer::generateMesh() { for (int j = 1; j < STACKS - 1; j++) { float v1 = ((float)j) / STACKS; float v2 = ((float)(j + 1)) / STACKS; - float theta1 = v1 * M_PI; - float theta2 = v2 * M_PI; + float theta1 = v1 * (float)M_PI; + float theta2 = v2 * (float)M_PI; for (int i = 0; i < SLICES; i++) { float u1 = ((float)i) / SLICES; float u2 = ((float)(i + 1)) / SLICES; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 739ccd9738..e28ba797d5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1467,17 +1467,17 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr } } -void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Parent::addMaterial(material, shapeID); +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Parent::addMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, shapeID); + _model->addMaterial(material, parentMaterialID); } } -void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - Parent::removeMaterial(material, shapeID); +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + Parent::removeMaterial(material, parentMaterialID); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, shapeID); + _model->removeMaterial(material, parentMaterialID); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 75c6639902..3951deaa2d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -144,8 +144,8 @@ public: ModelEntityRenderer(const EntityItemPointer& entity); public slots: - void addMaterial(graphics::MaterialPointer material, quint16 shapeID) override; - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 8bed9c70ee..5c5df38350 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -77,9 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); } - removeMaterial(_material, 0); + removeMaterial(_material, "0"); _material = entity->getMaterial(); - addMaterial(_material, 0); + addMaterial(_material, "0"); _shape = entity->getShape(); _position = entity->getWorldPosition(); @@ -127,7 +127,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation - mat = _materials[0].top(); + mat = _materials["0"].top(); if (mat) { outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity()); if (_procedural.isReady()) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 43510864ba..3ea81e5a36 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2940,20 +2940,20 @@ void EntityItem::preDelete() { } } -void EntityItem::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityItem::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].push(material); - emit addMaterialToRenderItem(material, shapeID); + _materials[parentMaterialID].push(material); + emit addMaterialToRenderItem(material, parentMaterialID); } -void EntityItem::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { +void EntityItem::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { std::lock_guard lock(_materialsLock); - _materials[shapeID].remove(material); - emit removeMaterialFromRenderItem(material, shapeID); + _materials[parentMaterialID].remove(material); + emit removeMaterialFromRenderItem(material, parentMaterialID); } -std::unordered_map EntityItem::getMaterials() { - std::unordered_map toReturn; +std::unordered_map EntityItem::getMaterials() { + std::unordered_map toReturn; { std::lock_guard lock(_materialsLock); toReturn = _materials; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index b2804a2e86..97d2f32a04 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -482,14 +482,14 @@ public: virtual void preDelete(); virtual void postParentFixup() {} - void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); - std::unordered_map getMaterials(); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + std::unordered_map getMaterials(); signals: void requestRenderUpdate(); - void addMaterialToRenderItem(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterialFromRenderItem(graphics::MaterialPointer material, quint16 shapeID); + void addMaterialToRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); protected: QHash _changeHandlers; @@ -644,7 +644,7 @@ protected: bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera private: - std::unordered_map _materials; + std::unordered_map _materials; std::mutex _materialsLock; }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 19aa6990db..450d0727f9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -357,9 +357,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); - CHECK_PROPERTY_CHANGE(PROP_PARENT_SHAPE_ID, shapeID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_MATERIAL_ID, parentMaterialID); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_POS, materialPos); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_SCALE, materialScale); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_ROT, materialRot); @@ -663,9 +662,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (_type == EntityTypes::Material) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_TYPE, materialMode, getMaterialModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_ID, parentMaterialID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_POS, materialPos); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_SCALE, materialScale); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_ROT, materialRot); @@ -806,9 +804,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMode, MaterialMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, quint16, setShapeID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialID, QString, setParentMaterialID); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialPos, glmVec2, setMaterialPos); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialScale, glmVec2, setMaterialScale); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRot, float, setMaterialRot); @@ -1168,9 +1165,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); - ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16); + ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_ID, ParentMaterialID, parentMaterialID, QString); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_ROT, MaterialRot, materialRot, float); @@ -1562,9 +1558,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy if (properties.getType() == EntityTypes::Material) { APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)properties.getMaterialMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, properties.getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, properties.getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, properties.getParentMaterialID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, properties.getMaterialPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, properties.getMaterialScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, properties.getMaterialRot()); @@ -1930,9 +1925,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int if (properties.getType() == EntityTypes::Material) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_ID, QString, setParentMaterialID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_POS, glmVec2, setMaterialPos); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_SCALE, glmVec2, setMaterialScale); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_ROT, float, setMaterialRot); @@ -2113,9 +2107,8 @@ void EntityItemProperties::markAllChanged() { _materialURLChanged = true; _materialModeChanged = true; - _blendFactorChanged = true; _priorityChanged = true; - _shapeIDChanged = true; + _parentMaterialIDChanged = true; _materialPosChanged = true; _materialScaleChanged = true; _materialRotChanged = true; @@ -2449,14 +2442,11 @@ QList EntityItemProperties::listChangedProperties() { if (materialModeChanged()) { out += "materialMode"; } - if (blendFactorChanged()) { - out += "blendFactor"; - } if (priorityChanged()) { out += "priority"; } - if (shapeIDChanged()) { - out += "shapeID"; + if (parentMaterialIDChanged()) { + out += "parentMaterialID"; } if (materialPosChanged()) { out += "materialPos"; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a8a79b6303..daa2272e36 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -224,9 +224,8 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode, UV); - DEFINE_PROPERTY_REF(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float, 1.0f); DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, quint16, 0); + DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_ID, ParentMaterialID, parentMaterialID, QString, "0"); DEFINE_PROPERTY_REF(PROP_MATERIAL_POS, MaterialPos, materialPos, glmVec2, glm::vec2(0, 0)); DEFINE_PROPERTY_REF(PROP_MATERIAL_SCALE, MaterialScale, materialScale, glmVec2, glm::vec2(1, 1)); DEFINE_PROPERTY_REF(PROP_MATERIAL_ROT, MaterialRot, materialRot, float, 0); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 17ebddbe9d..6ed2186760 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -229,9 +229,8 @@ enum EntityPropertyList { PROP_MATERIAL_URL, PROP_MATERIAL_TYPE, - PROP_MATERIAL_BLEND_FACTOR, PROP_MATERIAL_PRIORITY, - PROP_PARENT_SHAPE_ID, + PROP_PARENT_MATERIAL_ID, PROP_MATERIAL_POS, PROP_MATERIAL_SCALE, PROP_MATERIAL_ROT, diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 775b3bd2f7..9935718568 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2382,35 +2382,35 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const { return entity->getJointNames(); } -std::function EntityTree::_addMaterialToAvatarOperator = nullptr; -std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; -std::function EntityTree::_addMaterialToOverlayOperator = nullptr; -std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; +std::function EntityTree::_addMaterialToAvatarOperator = nullptr; +std::function EntityTree::_removeMaterialFromAvatarOperator = nullptr; +std::function EntityTree::_addMaterialToOverlayOperator = nullptr; +std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; -bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_addMaterialToAvatarOperator) { - return _addMaterialToAvatarOperator(avatarID, material, shapeID); + return _addMaterialToAvatarOperator(avatarID, material, parentMaterialID); } return false; } -bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_removeMaterialFromAvatarOperator) { - return _removeMaterialFromAvatarOperator(avatarID, material, shapeID); + return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialID); } return false; } -bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_addMaterialToOverlayOperator) { - return _addMaterialToOverlayOperator(overlayID, material, shapeID); + return _addMaterialToOverlayOperator(overlayID, material, parentMaterialID); } return false; } -bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID) { +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { if (_removeMaterialFromOverlayOperator) { - return _removeMaterialFromOverlayOperator(overlayID, material, shapeID); + return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialID); } return false; } \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index a02ce900ff..a532f64fc9 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -280,15 +280,15 @@ public: void setMyAvatar(std::shared_ptr myAvatar) { _myAvatar = myAvatar; } - static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } - static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } - static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); - static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, quint16 shapeID); + static void setAddMaterialToAvatarOperator(std::function addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; } + static void setRemoveMaterialFromAvatarOperator(std::function removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; } + static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID); - static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } - static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } - static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); - static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, quint16 shapeID); + static void setAddMaterialToOverlayOperator(std::function addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; } + static void setRemoveMaterialFromOverlayOperator(std::function removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; } + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID); signals: void deletingEntity(const EntityItemID& entityID); @@ -398,10 +398,10 @@ private: std::shared_ptr _myAvatar{ nullptr }; - static std::function _addMaterialToAvatarOperator; - static std::function _removeMaterialFromAvatarOperator; - static std::function _addMaterialToOverlayOperator; - static std::function _removeMaterialFromOverlayOperator; + static std::function _addMaterialToAvatarOperator; + static std::function _removeMaterialFromAvatarOperator; + static std::function _addMaterialToOverlayOperator; + static std::function _removeMaterialFromOverlayOperator; }; #endif // hifi_EntityTree_h diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 7026da117c..1ebaa4f21a 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -31,9 +31,8 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMode, getMaterialMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendFactor, getBlendFactor); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeID, getShapeID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentMaterialID, getParentMaterialID); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialPos, getMaterialPos); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialScale, getMaterialScale); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRot, getMaterialRot); @@ -45,9 +44,8 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeID, setShapeID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentMaterialID, setParentMaterialID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialPos, setMaterialPos); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialScale, setMaterialScale); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRot, setMaterialRot); @@ -65,139 +63,6 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } -bool MaterialEntityItem::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { - if (array.isArray()) { - QJsonArray colorArray = array.toArray(); - if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { - isSRGB = true; - if (colorArray.size() >= 4) { - if (colorArray[3].isBool()) { - isSRGB = colorArray[3].toBool(); - } - } - color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); - return true; - } - } - return false; -} - -void MaterialEntityItem::parseJSONMaterial(const QJsonObject& materialJSON) { - QString name = ""; - std::shared_ptr material = std::make_shared(); - for (auto& key : materialJSON.keys()) { - if (key == "name") { - auto nameJSON = materialJSON.value(key); - if (nameJSON.isString()) { - name = nameJSON.toString(); - } - } else if (key == "emissive") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setEmissive(color, isSRGB); - } - } else if (key == "opacity") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setOpacity(value.toDouble()); - } - } else if (key == "albedo") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setAlbedo(color, isSRGB); - } - } else if (key == "roughness") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setRoughness(value.toDouble()); - } - } else if (key == "fresnel") { - glm::vec3 color; - bool isSRGB; - bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); - if (valid) { - material->setFresnel(color, isSRGB); - } - } else if (key == "metallic") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setMetallic(value.toDouble()); - } - } else if (key == "scattering") { - auto value = materialJSON.value(key); - if (value.isDouble()) { - material->setScattering(value.toDouble()); - } - } else if (key == "emissiveMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setEmissiveMap(value.toString()); - } - } else if (key == "albedoMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - bool useAlphaChannel = false; - auto opacityMap = materialJSON.find("opacityMap"); - if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { - useAlphaChannel = true; - } - material->setAlbedoMap(value.toString(), useAlphaChannel); - } - } else if (key == "roughnessMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setRoughnessMap(value.toString(), false); - } - } else if (key == "glossMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setRoughnessMap(value.toString(), true); - } - } else if (key == "metallicMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setMetallicMap(value.toString(), false); - } - } else if (key == "specularMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setMetallicMap(value.toString(), true); - } - } else if (key == "normalMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setNormalMap(value.toString(), false); - } - } else if (key == "bumpMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setNormalMap(value.toString(), true); - } - } else if (key == "occlusionMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setOcclusionMap(value.toString()); - } - } else if (key == "scatteringMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setScatteringMap(value.toString()); - } - } else if (key == "lightMap") { - auto value = materialJSON.value(key); - if (value.isString()) { - material->setLightmapMap(value.toString()); - } - } - } - _materials[name] = material; - _materialNames.push_back(name); -} - int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -208,9 +73,8 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL); READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode); - READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor); READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, quint16, setShapeID); + READ_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, QString, setParentMaterialID); READ_ENTITY_PROPERTY(PROP_MATERIAL_POS, glm::vec2, setMaterialPos); READ_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, glm::vec2, setMaterialScale); READ_ENTITY_PROPERTY(PROP_MATERIAL_ROT, float, setMaterialRot); @@ -224,9 +88,8 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MATERIAL_URL; requestedProperties += PROP_MATERIAL_TYPE; - requestedProperties += PROP_MATERIAL_BLEND_FACTOR; requestedProperties += PROP_MATERIAL_PRIORITY; - requestedProperties += PROP_PARENT_SHAPE_ID; + requestedProperties += PROP_PARENT_MATERIAL_ID; requestedProperties += PROP_MATERIAL_POS; requestedProperties += PROP_MATERIAL_SCALE; requestedProperties += PROP_MATERIAL_ROT; @@ -244,9 +107,8 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode bool successPropertyFits = true; APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_ID, getParentMaterialID()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_POS, getMaterialPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_SCALE, getMaterialScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_ROT, getMaterialRot()); @@ -259,9 +121,8 @@ void MaterialEntityItem::debugDump() const { qCDebug(entities) << " material json:" << _materialURL; qCDebug(entities) << " current material name:" << _currentMaterialName; qCDebug(entities) << " material type:" << _materialMode; - qCDebug(entities) << " blend factor:" << _blendFactor; qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent shape ID:" << _shapeID; + qCDebug(entities) << " parent material ID:" << _parentMaterialID; qCDebug(entities) << " material pos:" << _materialPos; qCDebug(entities) << " material scale:" << _materialRot; qCDebug(entities) << " material rot:" << _materialScale; @@ -290,6 +151,8 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u removeMaterial(); _materialURL = materialURLString; + // TODO: if URL ends with ?string, try to set _currentMaterialName = string + if (usingUserData) { QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8()); _materials.clear(); @@ -299,22 +162,39 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u QJsonArray materials = materialJSON.array(); for (auto material : materials) { if (!material.isNull() && material.isObject()) { - parseJSONMaterial(material.toObject()); + auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(material.toObject()); + _materials[networkMaterial.first] = networkMaterial.second; + _materialNames.push_back(networkMaterial.first); } } } else if (materialJSON.isObject()) { - parseJSONMaterial(materialJSON.object()); + auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(materialJSON.object()); + _materials[networkMaterial.first] = networkMaterial.second; + _materialNames.push_back(networkMaterial.first); } } + // Since our material changed, the current name might not be valid anymore, so we need to update + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); } else { - // get material via network request + _networkMaterial = MaterialCache::instance().getMaterial(materialURLString); + auto onMaterialRequestFinished = [&](bool success) { + if (success) { + _materials[_networkMaterial->name] = _networkMaterial->networkMaterial; + _materialNames.push_back(_networkMaterial->name); + + setCurrentMaterialName(_currentMaterialName); + applyMaterial(); + } + }; + if (_networkMaterial) { + if (_networkMaterial->isLoaded()) { + onMaterialRequestFinished(!_networkMaterial->isFailed()); + } else { + connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished); + } + } } - - // TODO: if URL ends with ?string, try to set _currentMaterialName = string - - // Since our JSON changed, the current name might not be valid anymore, so we need to update - setCurrentMaterialName(_currentMaterialName); - applyMaterial(); } } @@ -361,14 +241,6 @@ void MaterialEntityItem::setMaterialRot(const float& materialRot) { } } -void MaterialEntityItem::setBlendFactor(float blendFactor) { - if (_blendFactor != blendFactor) { - removeMaterial(); - _blendFactor = blendFactor; - applyMaterial(); - } -} - void MaterialEntityItem::setPriority(quint16 priority) { if (_priority != priority) { removeMaterial(); @@ -377,10 +249,10 @@ void MaterialEntityItem::setPriority(quint16 priority) { } } -void MaterialEntityItem::setShapeID(quint16 shapeID) { - if (_shapeID != shapeID) { +void MaterialEntityItem::setParentMaterialID(const QString& parentMaterialID) { + if (_parentMaterialID != parentMaterialID) { removeMaterial(); - _shapeID = shapeID; + _parentMaterialID = parentMaterialID; applyMaterial(); } } @@ -421,16 +293,16 @@ void MaterialEntityItem::removeMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->removeMaterial(material, getShapeID()); + entity->removeMaterial(material, getParentMaterialID()); return; } } - if (EntityTree::removeMaterialFromAvatar(parentID, material, getShapeID())) { + if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialID())) { return; } - if (EntityTree::removeMaterialFromOverlay(parentID, material, getShapeID())) { + if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialID())) { return; } @@ -449,7 +321,6 @@ void MaterialEntityItem::applyMaterial() { textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); textureTransform.setScale(glm::vec3(_materialScale, 1)); material->setTextureTransforms(textureTransform); - material->setBlendFactor(getBlendFactor()); material->setPriority(getPriority()); // Our parent could be an entity, an avatar, or an overlay @@ -457,16 +328,16 @@ void MaterialEntityItem::applyMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->addMaterial(material, getShapeID()); + entity->addMaterial(material, getParentMaterialID()); return; } } - if (EntityTree::addMaterialToAvatar(parentID, material, getShapeID())) { + if (EntityTree::addMaterialToAvatar(parentID, material, getParentMaterialID())) { return; } - if (EntityTree::addMaterialToOverlay(parentID, material, getShapeID())) { + if (EntityTree::addMaterialToOverlay(parentID, material, getParentMaterialID())) { return; } diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index 40137acf22..dde9b60da9 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -13,6 +13,7 @@ #include "MaterialMode.h" #include +#include class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; @@ -60,14 +61,11 @@ public: MaterialMode getMaterialMode() const { return _materialMode; } void setMaterialMode(MaterialMode mode) { _materialMode = mode; } - float getBlendFactor() const { return _blendFactor; } - void setBlendFactor(float blendFactor); - quint16 getPriority() const { return _priority; } void setPriority(quint16 priority); - quint16 getShapeID() const { return _shapeID; } - void setShapeID(quint16 shapeID); + QString getParentMaterialID() const { return _parentMaterialID; } + void setParentMaterialID(const QString& parentMaterialID); glm::vec2 getMaterialPos() const { return _materialPos; } void setMaterialPos(const glm::vec2& materialPos); @@ -93,22 +91,19 @@ public: private: QString _materialURL; MaterialMode _materialMode { UV }; - float _blendFactor { 1.0f }; quint16 _priority { 0 }; - quint16 _shapeID { 0 }; + QString _parentMaterialID { "0" }; glm::vec2 _materialPos { 0, 0 }; glm::vec2 _materialScale { 1, 1 }; float _materialRot { 0 }; + NetworkMaterialResourcePointer _networkMaterial; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; bool _retryApply { false }; - void parseJSONMaterial(const QJsonObject& materialJSON); - static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); - }; #endif // hifi_MaterialEntityItem_h diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 6731d544b8..5b3396dfc5 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -354,9 +354,6 @@ public: size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } - void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; } - float getBlendFactor() { return _blendFactor; } - void setPriority(quint16 priority) { _priority = priority; } quint16 getPriority() { return _priority; } @@ -375,7 +372,6 @@ private: mutable bool _hasCalculatedTextureInfo { false }; bool calculateMaterialInfo() const; - float _blendFactor { 1.0f }; quint16 _priority { 0 }; }; diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp new file mode 100644 index 0000000000..723448f65a --- /dev/null +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -0,0 +1,175 @@ +// +// Created by Sam Gondelman on 2/9/2018 +// Copyright 2018 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 "MaterialCache.h" + +#include "QJsonObject" +#include "QJsonDocument" +#include "QJsonArray" + +NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) : + Resource(url) {} + +void NetworkMaterialResource::downloadFinished(const QByteArray& data) { + if (_url.toString().endsWith(".json")) { + QJsonDocument materialJSON = QJsonDocument::fromJson(data); + if (!materialJSON.isNull() && materialJSON.isObject()) { + auto parsedMaterial = parseJSONMaterial(materialJSON.object()); + name = parsedMaterial.first; + networkMaterial = parsedMaterial.second; + } + } + + // TODO: parse other material types + + finishedLoading(true); +} + +bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) { + if (array.isArray()) { + QJsonArray colorArray = array.toArray(); + if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) { + isSRGB = true; + if (colorArray.size() >= 4) { + if (colorArray[3].isBool()) { + isSRGB = colorArray[3].toBool(); + } + } + color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble()); + return true; + } + } + return false; +} + +std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { + QString name = ""; + std::shared_ptr material = std::make_shared(); + for (auto& key : materialJSON.keys()) { + if (key == "name") { + auto nameJSON = materialJSON.value(key); + if (nameJSON.isString()) { + name = nameJSON.toString(); + } + } else if (key == "emissive") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setEmissive(color, isSRGB); + } + } else if (key == "opacity") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setOpacity(value.toDouble()); + } + } else if (key == "albedo") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setAlbedo(color, isSRGB); + } + } else if (key == "roughness") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setRoughness(value.toDouble()); + } + } else if (key == "fresnel") { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB); + if (valid) { + material->setFresnel(color, isSRGB); + } + } else if (key == "metallic") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setMetallic(value.toDouble()); + } + } else if (key == "scattering") { + auto value = materialJSON.value(key); + if (value.isDouble()) { + material->setScattering(value.toDouble()); + } + } else if (key == "emissiveMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setEmissiveMap(value.toString()); + } + } else if (key == "albedoMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + bool useAlphaChannel = false; + auto opacityMap = materialJSON.find("opacityMap"); + if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) { + useAlphaChannel = true; + } + material->setAlbedoMap(value.toString(), useAlphaChannel); + } + } else if (key == "roughnessMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), false); + } + } else if (key == "glossMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setRoughnessMap(value.toString(), true); + } + } else if (key == "metallicMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), false); + } + } else if (key == "specularMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setMetallicMap(value.toString(), true); + } + } else if (key == "normalMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), false); + } + } else if (key == "bumpMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setNormalMap(value.toString(), true); + } + } else if (key == "occlusionMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setOcclusionMap(value.toString()); + } + } else if (key == "scatteringMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setScatteringMap(value.toString()); + } + } else if (key == "lightMap") { + auto value = materialJSON.value(key); + if (value.isString()) { + material->setLightmapMap(value.toString()); + } + } + } + return std::pair>(name, material); +} + +MaterialCache& MaterialCache::instance() { + static MaterialCache _instance; + return _instance; +} + +NetworkMaterialResourcePointer MaterialCache::getMaterial(const QUrl& url) { + return ResourceCache::getResource(url, QUrl(), nullptr).staticCast(); +} + +QSharedPointer MaterialCache::createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) { + return QSharedPointer(new NetworkMaterialResource(url), &Resource::deleter); +} \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/MaterialCache.h b/libraries/model-networking/src/model-networking/MaterialCache.h new file mode 100644 index 0000000000..1b0f1c577c --- /dev/null +++ b/libraries/model-networking/src/model-networking/MaterialCache.h @@ -0,0 +1,46 @@ +// +// Created by Sam Gondelman on 2/9/2018 +// Copyright 2018 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_MaterialCache_h +#define hifi_MaterialCache_h + +#include + +#include "glm/glm.hpp" + +#include "ModelCache.h" + +class NetworkMaterialResource : public Resource { +public: + NetworkMaterialResource(const QUrl& url); + + QString getType() const override { return "NetworkMaterial"; } + + virtual void downloadFinished(const QByteArray& data) override; + + QString name { "" }; + std::shared_ptr networkMaterial { nullptr }; + + static std::pair> parseJSONMaterial(const QJsonObject& materialJSON); + +private: + static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB); +}; + +using NetworkMaterialResourcePointer = QSharedPointer; + +class MaterialCache : public ResourceCache { +public: + static MaterialCache& instance(); + + NetworkMaterialResourcePointer getMaterial(const QUrl& url); + +protected: + virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; +}; + +#endif diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 32deba3687..739f401ee7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -495,8 +495,8 @@ NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) : Material(m), _textures(m._textures), _albedoTransform(m._albedoTransform), - _lightmapParams(m._lightmapParams), _lightmapTransform(m._lightmapTransform), + _lightmapParams(m._lightmapParams), _isOriginal(m._isOriginal) {} diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index 5d39583c9e..115e665b77 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -23,7 +23,7 @@ void ResourceRequest::send() { QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); return; } - + Q_ASSERT(_state == NotStarted); _state = InProgress; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 805995edfb..3a9ea45d77 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1524,48 +1524,62 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -void Model::addMaterial(graphics::MaterialPointer material, quint16 shapeID) { - if (shapeID < _modelMeshRenderItemIDs.size()) { - render::Transaction transaction; - auto itemID = _modelMeshRenderItemIDs[shapeID]; - bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool wireframe = isWireframe(); - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; - bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, - invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { - data.addMaterial(material); - // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); - data.setShapeKey(invalidatePayloadShapeKey, wireframe); - }); - AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); - } +std::vector Model::getMeshIDsFromMaterialID(const QString& parentMaterialID) { + std::vector toReturn; + // TODO: first, try to find all meshes with materials that match parentMaterialID as a string + // if none, return parentMaterialID as a uint + toReturn.push_back(parentMaterialID.toUInt()); + return toReturn; } -void Model::removeMaterial(graphics::MaterialPointer material, quint16 shapeID) { - if (shapeID < _modelMeshRenderItemIDs.size()) { - render::Transaction transaction; - auto itemID = _modelMeshRenderItemIDs[shapeID]; - bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool wireframe = isWireframe(); - auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; - bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, - invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { - data.removeMaterial(material); - // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); - data.setShapeKey(invalidatePayloadShapeKey, wireframe); - }); - AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +void Model::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); + render::Transaction transaction; + for (auto shapeID : shapeIDs) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.addMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + } } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +} + +void Model::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); + render::Transaction transaction; + for (auto shapeID : shapeIDs) { + if (shapeID < _modelMeshRenderItemIDs.size()) { + auto itemID = _modelMeshRenderItemIDs[shapeID]; + bool visible = isVisible(); + uint8_t viewTagBits = getViewTagBits(); + bool layeredInFront = isLayeredInFront(); + bool layeredInHUD = isLayeredInHUD(); + bool wireframe = isWireframe(); + auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; + bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); + transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, + invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) { + data.removeMaterial(material); + // if the material changed, we might need to update our item key or shape key + data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits); + data.setShapeKey(invalidatePayloadShapeKey, wireframe); + }); + } + } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } class CollisionRenderGeometry : public Geometry { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 80067aff2a..b4152324bc 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -318,8 +318,8 @@ public: void scaleToFit(); - void addMaterial(graphics::MaterialPointer material, quint16 shapeID); - void removeMaterial(graphics::MaterialPointer material, quint16 shapeID); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); public slots: void loadURLFinished(bool success); @@ -471,6 +471,8 @@ private: float _loadingPriority { 0.0f }; void calculateTextureInfo(); + + std::vector getMeshIDsFromMaterialID(const QString& parentMaterialID); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 25b2cec331..4dbbd190ff 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -256,6 +256,13 @@ namespace std { return result; } }; + + template <> + struct hash { + size_t operator()(const QString& a) const { + return qHash(a); + } + }; } enum ContactEventType { diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 348d93d589..5eedd1c7e4 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -780,19 +780,14 @@ -
- - -
-
-
- - +
+ +
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 3558a36c04..01ec4ae283 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -633,9 +633,8 @@ function loaded() { var elMaterialURL = document.getElementById("property-material-url"); var elMaterialMode = document.getElementById("property-material-mode"); - var elBlendFactor = document.getElementById("property-blend-factor"); var elPriority = document.getElementById("property-priority"); - var elShapeID = document.getElementById("property-shape-id"); + var elParentMaterialID = document.getElementById("property-parent-material-id"); var elMaterialPosX = document.getElementById("property-material-pos-x"); var elMaterialPosY = document.getElementById("property-material-pos-y"); var elMaterialScaleX = document.getElementById("property-material-scale-x"); @@ -1130,9 +1129,8 @@ function loaded() { elMaterialURL.value = properties.materialURL; elMaterialMode.value = properties.materialMode; setDropdownText(elMaterialMode); - elBlendFactor.value = properties.blendFactor.toFixed(2); elPriority.value = properties.priority; - elShapeID.value = properties.shapeID; + elParentMaterialID.value = properties.parentMaterialID; elMaterialPosX.value = properties.materialPos.x.toFixed(4); elMaterialPosY.value = properties.materialPos.y.toFixed(4); elMaterialScaleX.value = properties.materialScale.x.toFixed(4); @@ -1410,9 +1408,8 @@ function loaded() { elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL')); elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode')); - elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2)); elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0)); - elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID', 0)); + elParentMaterialID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentMaterialID')); var materialPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialPos', elMaterialPosX, elMaterialPosY); elMaterialPosX.addEventListener('change', materialPosChangeFunction); From 2ff78493dbf68bd3d988aebfef44614e4e5a6b36 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 13 Feb 2018 10:11:18 +1300 Subject: [PATCH 41/83] A further guard --- scripts/system/controllers/controllerDispatcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index b2455b3f5a..345ab33c0d 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -479,7 +479,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; } function mouseReleaseOnOverlay(overlayID, event) { - if (overlayID === HMD.homeButtonID && event.button === "Primary") { + if (HMD.homeButtonID && overlayID === HMD.homeButtonID && event.button === "Primary") { Messages.sendLocalMessage("home", overlayID); } } From ad409618640071ca84824765c656b7467a53ac19 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 12 Feb 2018 13:46:27 -0800 Subject: [PATCH 42/83] fix tangents (I think), update material rendering when transform changes --- .../src/RenderableMaterialEntityItem.cpp | 13 ++++++++++++- .../src/RenderableMaterialEntityItem.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index ad17202d8e..529aa03124 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -18,6 +18,9 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { return true; } + if (entity->getMaterialPos() != _materialPos || entity->getMaterialScale() != _materialScale || entity->getMaterialRot() != _materialRot) { + return true; + } return false; } @@ -27,6 +30,9 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& _parentID = entity->getParentID(); _clientOnly = entity->getClientOnly(); _owningAvatarID = entity->getOwningAvatarID(); + _materialPos = entity->getMaterialPos(); + _materialScale = entity->getMaterialScale(); + _materialRot = entity->getMaterialRot(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -91,7 +97,7 @@ glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) { } glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) { - return glm::vec3(-glm::cos(theta) * glm::cos(phi), 0, -glm::cos(theta) * glm::sin(phi)); + return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi)); } void MaterialEntityRenderer::addVertex(std::vector& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) { @@ -227,16 +233,21 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { QUuid parentID; Transform renderTransform; graphics::MaterialPointer drawMaterial; + Transform textureTransform; withReadLock([&] { parentID = _clientOnly ? _owningAvatarID : _parentID; renderTransform = _renderTransform; drawMaterial = _drawMaterial; + textureTransform.setTranslation(glm::vec3(_materialPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); + textureTransform.setScale(glm::vec3(_materialScale, 1)); }); if (!parentID.isNull() || !drawMaterial) { return; } batch.setModelTransform(renderTransform); + drawMaterial->setTextureTransforms(textureTransform); // bind the material args->_shapePipeline->bindMaterial(drawMaterial, batch, args->_enableTexturing); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index af8cef9351..4af21d84f6 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -34,6 +34,9 @@ private: QUuid _parentID; bool _clientOnly; QUuid _owningAvatarID; + glm::vec2 _materialPos; + glm::vec2 _materialScale; + float _materialRot; Transform _renderTransform; std::shared_ptr _drawMaterial; From 95e9eb8e4abebbbaa919224a8f638a78fc91482a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 12 Feb 2018 17:06:57 -0800 Subject: [PATCH 43/83] Lots of progress --- interface/resources/fonts/hifi-glyphs.ttf | Bin 31232 -> 32536 bytes .../qml/hifi/commerce/checkout/Checkout.qml | 69 +++++++++++++----- .../hifi/commerce/purchases/PurchasedItem.qml | 57 +++++++++++---- .../qml/hifi/commerce/purchases/Purchases.qml | 16 +++- .../qml/styles-uit/HifiConstants.qml | 4 + interface/src/Application.cpp | 34 +++++---- interface/src/Application.h | 2 + interface/src/commerce/QmlCommerce.cpp | 13 ++++ interface/src/commerce/QmlCommerce.h | 4 + .../entities/src/EntityScriptingInterface.cpp | 5 ++ .../entities/src/EntityScriptingInterface.h | 6 ++ scripts/system/marketplaces/marketplaces.js | 17 +++-- 12 files changed, 174 insertions(+), 53 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 4cc5a0fe4f098a287c1df067c8bff37695f96d34..8db0377f88864810e7f893132449ad8e258e68cd 100644 GIT binary patch delta 1778 zcmX|BYit}>6+Y+AoqK2QJl2nSB>S*;W_D-2b{(&GXJ_2H>o!qq1dW}@Z9){4lvT5h zqu7p>-KGvdyya2)h89Z*g%o}O?VnUUtN=f%mWR~PN+2OYkx)Sq5&Ym!Bm`1H$U(EI zxYE7fxku-Gy65UU=jngqH}7dS0U-a02OeC6w}Am{ ze+U4@BM;BikGyrb2Y@F4;P~U~?ahl1e$WOW9|Dk#Gwtr??b{#$Z2t}blrw9Wp0Lk- z?+O6h1lW9TwbMRrK2iK70Hl2J>T0LorZv0)fEEChR@Zx5#n0{g5&-@H04LYZKi+=l zzCWD;kPic3X}!I*3AgYR0M4Zk+GwwL{yul@IKah^0C0Ene79$>Tz&{(>nZ@77!-#9 z<3CKEc`S49zd$39t`EL*>*gIKw{Ct7TlnhE0)7T(cCTO)kG0@#ScG|49K=chgPk9c z0j`2Hu<}6ha9SlOaEEpK#?0;8gBJt$^ znvmp2b9C;3-4pEExjusyJc7T#t6)GGns5-7;5Yy_>bAqJ!1J5KQ3G2Tg@Na@0*RA& z9GzqUa@}co^(3x@m5?*eDhrr|l`t^TwGxK~EUZLvQg=e1*_K<6Bg89Z#LC`#l`0;h z#@=uBzN{(xM>AZvI$0~X_cy8%oG>J&S1V%3xyDQ}sVTa|T^*mr{OD+IaFj<3TNrq? z{N-oE3FOtif1AHCsI0%KQ&}I$2qqeal{<}0(JNJr>nEuzTZ{{dkGS~8Xby8$$|UJ( z-zK`1>hW$!@H)N=8sx!;DVT*A=HY($BpiWba1u5Ez-N}zaGML*jCe~9D{$s_9_tW&CAU7uQ@i9 z%?_9DEe)>)_Q(RF@H4i%-x2t3@AV!c_EsJ~AtNH8L0%S8c!sU#R&MhlsSyhF4MDS(ChHj+vx|Y|pyrw&rWeM?l zbwU;4@6~<^B_a!Xh;e2rjC1MR5>p7HgfWG4E~`|buMwt5hC+oRs~JU32gE#lAK%9> z!W7KFJpkpj0|Va| zMi2?-dZ8eX>=)2VCq~@DD76F6f3$^(eMb&XqkbPQVC4X2 zuo?NE&DthbO*^aZ{Xu=r(-c*UWr;~KMJj2un7wH%o3?E(8^*G#F8}nKIaO%9CP_6( zqZDcGvazdQ&~bPcYA_A;!LGq9%{Kk4`qt~TRwKq=Fr#kHm{Om@z*IrxOdFxUE RU)lNNrJVNvNq_6+{{ZQFEu#Pc delta 506 zcmX|-Pe>GT6vsbrW?a_PN=#T{p%p?1S=w31NpL;s+9A-lJ#L?N1OHfx?@7&K_$jRKEZ}fzEtBH)|UysezmWF6K*xFSHt&=rbf$Ti>;Q8YrX zncAgVM-V91wi+jx!~?YvL%)~ zq-iG8DbuR-xJ$C&e|BTy|Mj+vesu*20yIT_8i=W3*y}t;FhB|8So(HmEqr(Ac;|op E2i!<=3IG5A diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 809f48361d..c141b48d32 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -37,11 +37,14 @@ Rectangle { property double balanceAfterPurchase; property bool alreadyOwned: false; property int itemPrice: -1; - property bool itemIsJson: true; + property bool isCertified; + property string itemType; + property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar"]; + property var buttonTextNormal: ["REZ IT", "WEAR IT", "SWAP CONTENT SET", "INSTALL IT", "WEAR IT"]; + property var buttonTextClicked: ["REZZED", "WORN", "SWAPPED", "INSTALLED", "WORN"] property bool shouldBuyWithControlledFailure: false; property bool debugCheckoutSuccess: false; property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); - property bool isWearable; property string referrer; // Style color: hifi.colors.white; @@ -85,7 +88,9 @@ Rectangle { UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { root.itemHref = result.data.download_url; - root.isWearable = result.data.categories.indexOf("Wearables") > -1; + if (result.data.categories.indexOf("Wearables") > -1) { + root.itemType = "wearable"; + } root.activeView = "checkoutSuccess"; UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned); } @@ -122,7 +127,25 @@ Rectangle { } onItemHrefChanged: { - itemIsJson = root.itemHref.endsWith('.json'); + if (root.itemHref.indexOf(".fst") > -1) { + root.itemType = "avatar"; + } else if (root.itemHref.endsWith('.json.gz')) { + root.itemType = "contentSet"; + } else if (root.itemHref.endsWith('.json')) { + root.itemType = "entity"; // "wearable" type handled later + } else if (root.itemHref.endsWith('.js')) { + root.itemType = "app"; + } else { + root.itemType = "entity"; + } + } + + onItemTypeChanged: { + if (root.itemType === "entity" || root.itemType === "wearable" || root.itemType === "contentSet") { + root.isCertified = true; + } else { + root.isCertified = false; + } } onItemPriceChanged: { @@ -464,7 +487,7 @@ Rectangle { // "Buy" button HifiControlsUit.Button { id: buyButton; - enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson; + enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || (!root.isCertified); color: hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; anchors.top: checkoutActionButtonsContainer.top; @@ -472,9 +495,9 @@ Rectangle { height: 40; anchors.left: parent.left; anchors.right: parent.right; - text: (itemIsJson ? ((purchasesReceived && balanceReceived) ? "Confirm Purchase" : "--") : "Get Item"); + text: ((root.isCertified) ? ((purchasesReceived && balanceReceived) ? "Confirm Purchase" : "--") : "Get Item"); onClicked: { - if (itemIsJson) { + if (root.isCertified) { buyButton.enabled = false; if (!root.shouldBuyWithControlledFailure) { Commerce.buy(itemId, itemPrice); @@ -576,7 +599,7 @@ Rectangle { RalewayBold { anchors.fill: parent; - text: "REZZED"; + text: (root.buttonTextClicked)[itemTypesArray.indexOf(root.itemType)]; size: 18; color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; @@ -592,7 +615,7 @@ Rectangle { // "Rez" button HifiControlsUit.Button { id: rezNowButton; - enabled: root.canRezCertifiedItems || root.isWearable; + enabled: root.canRezCertifiedItems || root.itemType === "wearable"; buttonGlyph: hifi.glyphs.lightning; color: hifi.buttons.red; colorScheme: hifi.colorSchemes.light; @@ -601,17 +624,27 @@ Rectangle { height: 50; anchors.left: parent.left; anchors.right: parent.right; - text: root.isWearable ? "Wear It" : "Rez It" + text: (root.buttonTextNormal)[itemTypesArray.indexOf(root.itemType)]; onClicked: { - sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable}); - rezzedNotifContainer.visible = true; - rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, "checkout", root.isWearable ? "rez" : "wear"); + if (root.itemType === "contentSet") { + lightboxPopup.titleText = "Replace Content"; + lightboxPopup.bodyText = "Rezzing this content set will replace the existing environment and all of the items in this domain."; + lightboxPopup.button1text = "CANCEL"; + lightboxPopup.button1method = "root.visible = false;" + lightboxPopup.button2text = "CONFIRM"; + lightboxPopup.button2method = "sendToScript({method: 'checkout_rezClicked', itemHref: " + root.itemHref + ", itemType: " + root.itemType + "});"; + lightboxPopup.visible = true; + } else { + sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); + rezzedNotifContainer.visible = true; + rezzedNotifContainerTimer.start(); + UserActivityLogger.commerceEntityRezzed(root.itemId, "checkout", root.itemType); + } } } RalewaySemiBold { id: noPermissionText; - visible: !root.canRezCertifiedItems && !root.isWearable; + visible: !root.canRezCertifiedItems && root.itemType !== "wearable"; text: 'You do not have Certified Rez permissions in this domain.' // Text size size: 16; @@ -640,7 +673,7 @@ Rectangle { } RalewaySemiBold { id: explainRezText; - visible: !root.isWearable; + visible: root.itemType === "entity"; text: 'What does "Rez" mean?' // Text size size: 16; @@ -851,7 +884,7 @@ Rectangle { buyButton.color = hifi.buttons.red; root.shouldBuyWithControlledFailure = true; } else { - buyButton.text = (itemIsJson ? ((purchasesReceived && balanceReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item"); + buyButton.text = (root.isCertified ? ((purchasesReceived && balanceReceived) ? (root.alreadyOwned ? "Buy Another" : "Buy"): "--") : "Get Item"); buyButton.color = hifi.buttons.blue; root.shouldBuyWithControlledFailure = false; } @@ -901,7 +934,7 @@ Rectangle { } function setBuyText() { - if (root.itemIsJson) { + if (root.isCertified) { if (root.purchasesReceived && root.balanceReceived) { if (root.balanceAfterPurchase < 0) { if (root.alreadyOwned) { diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 361b9931a4..41f2d919cd 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -41,8 +41,11 @@ Item { property int limitedRun; property string itemType; property var itemTypesArray: ["entity", "wearable", "contentSet", "app", "avatar"]; - property var buttonTextNormal: ["REZ", "WEAR", "SWAP", "INSTALL", "WEAR"]; - property var buttonTextClicked: ["REZZED", "WORN", "SWAPPED", "INSTALLED", "WORN"] + property var buttonTextNormal: ["REZ", "WEAR", "REPLACE", "INSTALL", "WEAR"]; + property var buttonTextClicked: ["REZZED", "WORN", "REPLACED", "INSTALLED", "WORN"] + property var buttonGlyph: [hifi.glyphs.wand, hifi.glyphs.hat, hifi.glyphs.globe, hifi.glyphs.install, hifi.glyphs.avatar]; + property bool showConfirmation: false; + property bool hasPermissionToRezThis; property string originalStatusText; property string originalStatusColor; @@ -50,6 +53,23 @@ Item { height: 110; width: parent.width; + Connections { + target: Commerce; + + onContentSetChanged: { + if (contentSetMarketplaceID === root.itemId) { + showConfirmation = true; + } + } + } + + onItemTypeChanged: { + if ((itemType === "entity" && (!Entities.canRezCertified() && !Entities.canRezTmpCertified())) || + (itemType === "contentSet" && !Entities.canReplaceContent())) { + root.hasPermissionToRezThis = false; + } + } + onPurchaseStatusChangedChanged: { if (root.purchaseStatusChanged === true && root.purchaseStatus === "confirmed") { root.originalStatusText = statusText.text; @@ -60,6 +80,15 @@ Item { } } + onShowConfirmationChanged: { + if (root.showConfirmation) { + rezzedNotifContainer.visible = true; + rezzedNotifContainerTimer.start(); + UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.itemType); + root.showConfirmation = false; + } + } + Timer { id: confirmedTimer; interval: 3000; @@ -325,7 +354,7 @@ Item { RalewayBold { anchors.fill: parent; text: (root.buttonTextClicked)[itemTypesArray.indexOf(root.itemType)]; - size: 18; + size: 15; color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter; @@ -353,10 +382,12 @@ Item { enabled: (root.canRezCertifiedItems || root.itemType === "wearable") && root.purchaseStatus !== "invalidated"; onClicked: { - sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); - rezzedNotifContainer.visible = true; - rezzedNotifContainerTimer.start(); - UserActivityLogger.commerceEntityRezzed(root.itemId, "purchases", root.itemType === "wearable" ? "rez" : "wear"); + if (root.itemType === "contentSet") { + sendToPurchases({method: 'showReplaceContentLightbox', itemId: root.itemId, itemHref: root.itemHref}); + } else { + sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); + root.showConfirmation = true; + } } style: ButtonStyle { @@ -396,13 +427,13 @@ Item { label: Item { HiFiGlyphs { - id: lightningIcon; - text: hifi.glyphs.lightning; + id: rezIcon; + text: (root.buttonGlyph)[itemTypesArray.indexOf(root.itemType)]; // Size - size: 32; + size: 60; // Anchors anchors.top: parent.top; - anchors.topMargin: 12; + anchors.topMargin: 0; anchors.left: parent.left; anchors.right: parent.right; horizontalAlignment: Text.AlignHCenter; @@ -411,8 +442,8 @@ Item { : hifi.buttons.disabledTextColor[control.colorScheme] } RalewayBold { - anchors.top: lightningIcon.bottom; - anchors.topMargin: -20; + anchors.top: rezIcon.bottom; + anchors.topMargin: -4; anchors.right: parent.right; anchors.left: parent.left; anchors.bottom: parent.bottom; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 922ba54822..956bfa7c26 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -455,10 +455,16 @@ Rectangle { limitedRun: model.limited_run; displayedItemCount: model.displayedItemCount; itemType: { - if (model.download_url.indexOf(".fst") > -1) { + if (model.root_file_url.indexOf(".fst") > -1) { "avatar"; } else if (model.categories.indexOf("Wearables") > -1) { "wearable"; + } else if (model.root_file_url.endsWith('.json.gz')) { + "contentSet"; + } else if (model.root_file_url.endsWith('.json')) { + "entity"; + } else if (model.root_file_url.endsWith('.js')) { + "app"; } else { "entity"; } @@ -490,6 +496,14 @@ Rectangle { lightboxPopup.button1text = "CLOSE"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.visible = true; + } else if (msg.method === "showReplaceContentLightbox") { + lightboxPopup.titleText = "Replace Content"; + lightboxPopup.bodyText = "Rezzing this content set will replace the existing environment and all of the items in this domain."; + lightboxPopup.button1text = "CANCEL"; + lightboxPopup.button1method = "root.visible = false;" + lightboxPopup.button2text = "CONFIRM"; + lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemId + "', '" + msg.itemHref + "'); root.visible = false;"; + lightboxPopup.visible = true; } else if (msg.method === "setFilterText") { filterBar.text = msg.filterText; } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 5da587ea57..16b74f6b54 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -354,5 +354,9 @@ Item { readonly property string wallet: "\ue027" readonly property string paperPlane: "\ue028" readonly property string passphrase: "\ue029" + readonly property string globe: "\ue02c" + readonly property string wand: "\ue02d" + readonly property string hat: "\ue02e" + readonly property string install: "\ue02f" } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index be2a54b8e9..576d080947 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6176,6 +6176,24 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { return true; } +void Application::replaceDomainContent(const QString& url) { + qCDebug(interfaceapp) << "Attempting to replace domain content: " << url; + QByteArray urlData(url.toUtf8()); + auto limitedNodeList = DependencyManager::get(); + limitedNodeList->eachMatchingNode([](const SharedNodePointer& node) { + return node->getType() == NodeType::EntityServer && node->getActiveSocket(); + }, [&urlData, limitedNodeList](const SharedNodePointer& octreeNode) { + auto octreeFilePacket = NLPacket::create(PacketType::OctreeFileReplacementFromUrl, urlData.size(), true); + octreeFilePacket->write(urlData); + limitedNodeList->sendPacket(std::move(octreeFilePacket), *octreeNode); + }); + auto addressManager = DependencyManager::get(); + addressManager->handleLookupString(DOMAIN_SPAWNING_POINT); + QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT; + qCDebug(interfaceapp) << "Setting new home bookmark to: " << newHomeAddress; + DependencyManager::get()->setHomeLocationToAddress(newHomeAddress); +} + bool Application::askToReplaceDomainContent(const QString& url) { QString methodDetails; const int MAX_CHARACTERS_PER_LINE = 90; @@ -6195,21 +6213,7 @@ bool Application::askToReplaceDomainContent(const QString& url) { QString details; if (static_cast(answer.toInt()) == QMessageBox::Yes) { // Given confirmation, send request to domain server to replace content - qCDebug(interfaceapp) << "Attempting to replace domain content: " << url; - QByteArray urlData(url.toUtf8()); - auto limitedNodeList = DependencyManager::get(); - limitedNodeList->eachMatchingNode([](const SharedNodePointer& node) { - return node->getType() == NodeType::EntityServer && node->getActiveSocket(); - }, [&urlData, limitedNodeList](const SharedNodePointer& octreeNode) { - auto octreeFilePacket = NLPacket::create(PacketType::OctreeFileReplacementFromUrl, urlData.size(), true); - octreeFilePacket->write(urlData); - limitedNodeList->sendPacket(std::move(octreeFilePacket), *octreeNode); - }); - auto addressManager = DependencyManager::get(); - addressManager->handleLookupString(DOMAIN_SPAWNING_POINT); - QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT; - qCDebug(interfaceapp) << "Setting new home bookmark to: " << newHomeAddress; - DependencyManager::get()->setHomeLocationToAddress(newHomeAddress); + replaceDomainContent(url); details = "SuccessfulRequestToReplaceContent"; } else { details = "UserDeclinedToReplaceContent"; diff --git a/interface/src/Application.h b/interface/src/Application.h index ddb8ce11e5..2dd83f39eb 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -284,6 +284,8 @@ public: bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } void saveNextPhysicsStats(QString filename); + void replaceDomainContent(const QString& url); + signals: void svoImportRequested(const QString& url); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index c9caa393ce..ba52edba4f 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -15,6 +15,8 @@ #include "Ledger.h" #include "Wallet.h" #include +#include +#include QmlCommerce::QmlCommerce() { auto ledger = DependencyManager::get(); @@ -163,3 +165,14 @@ void QmlCommerce::transferHfcToUsername(const QString& username, const int& amou QString key = keys[0]; ledger->transferHfcToUsername(key, username, amount, optionalMessage); } + +void QmlCommerce::replaceContentSet(const QString& id, const QString& url) { + qApp->replaceDomainContent(url); + QJsonObject messageProperties = { + { "status", "SuccessfulRequestToReplaceContent" }, + { "content_set_url", url } + }; + UserActivityLogger::getInstance().logAction("replace_domain_content", messageProperties); + + emit contentSetChanged(id); +} diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index b261ee6de6..aa939a439d 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -48,6 +48,8 @@ signals: void transferHfcToNodeResult(QJsonObject result); void transferHfcToUsernameResult(QJsonObject result); + void contentSetChanged(const QString& contentSetMarketplaceID); + protected: Q_INVOKABLE void getWalletStatus(); @@ -71,6 +73,8 @@ protected: Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage); + + Q_INVOKABLE void replaceContentSet(const QString& id, const QString& url); }; #endif // hifi_QmlCommerce_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4342f0e683..f9449cca34 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -101,6 +101,11 @@ bool EntityScriptingInterface::canWriteAssets() { return nodeList->getThisNodeCanWriteAssets(); } +bool EntityScriptingInterface::canReplaceContent() { + auto nodeList = DependencyManager::get(); + return nodeList->getThisNodeCanReplaceContent(); +} + void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { if (_entityTree) { disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d1b321dbca..30e1e6ce1c 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -144,6 +144,12 @@ public slots: */ Q_INVOKABLE bool canWriteAssets(); + /**jsdoc + * @function Entities.canReplaceContent + * @return {bool} `true` if the DomainServer will allow this Node/Avatar to replace the domain's content set + */ + Q_INVOKABLE bool canReplaceContent(); + /**jsdoc * Add a new entity with the specified properties. If `clientOnly` is true, the entity will * not be sent to the server and will only be visible/accessible on the local client. diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index b43fe545fa..95d9294063 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -65,7 +65,7 @@ var selectionDisplay = null; // for gridTool.js to ignore var onMarketplaceScreen = false; var onCommerceScreen = false; - var debugCheckout = false; + var debugCheckout = true; var debugError = false; function showMarketplace() { if (!debugCheckout) { @@ -75,11 +75,11 @@ var selectionDisplay = null; // for gridTool.js to ignore tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH); tablet.sendToQml({ method: 'updateCheckoutQML', params: { - itemId: '0d90d21c-ce7a-4990-ad18-e9d2cf991027', - itemName: 'Test Flaregun', - itemPrice: (debugError ? 10 : 17), - itemHref: 'http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json', - categories: ["Wearables", "Miscellaneous"] + itemId: 'e197e3d7-eafc-4aa5-9341-acee57174fe9', + itemName: 'Oasis', + itemPrice: (debugError ? 10 : 11), + itemHref: 'http://mpassets-staging.highfidelity.com/e197e3d7-eafc-4aa5-9341-acee57174fe9-v1/oasis_Aug15.json.gz', + categories: ["Miscellaneous"] } }); } @@ -240,6 +240,11 @@ var selectionDisplay = null; // for gridTool.js to ignore var wearableLocalDimensions = null; var wearableDimensions = null; + if (itemType === "contentSet") { + console.log("Item is a content set; codepath shouldn't go here.") + return; + } + if (isWearable) { var wearableTransforms = Settings.getValue("io.highfidelity.avatarStore.checkOut.transforms"); if (!wearableTransforms) { From 0809210dc3cb92948f0173828e244d405681b743 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 13 Feb 2018 11:16:48 -0800 Subject: [PATCH 44/83] No permission card --- .../hifi/commerce/purchases/PurchasedItem.qml | 100 +++++++++++++++++- .../qml/hifi/commerce/purchases/Purchases.qml | 84 +++------------ .../AccountServicesScriptingInterface.h | 2 +- 3 files changed, 113 insertions(+), 73 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 41f2d919cd..9db847eada 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -29,7 +29,6 @@ Item { id: root; property string purchaseStatus; property bool purchaseStatusChanged; - property bool canRezCertifiedItems: false; property string itemName; property string itemId; property string itemPreviewImageUrl; @@ -67,6 +66,8 @@ Item { if ((itemType === "entity" && (!Entities.canRezCertified() && !Entities.canRezTmpCertified())) || (itemType === "contentSet" && !Entities.canReplaceContent())) { root.hasPermissionToRezThis = false; + } else { + root.hasPermissionToRezThis = true; } } @@ -128,15 +129,19 @@ Item { } } - + TextMetrics { + id: itemNameTextMetrics; + font: itemName.font; + text: itemName.text; + } RalewaySemiBold { id: itemName; anchors.top: itemPreviewImage.top; anchors.topMargin: 4; anchors.left: itemPreviewImage.right; anchors.leftMargin: 8; - anchors.right: buttonContainer.left; - anchors.rightMargin: 8; + width: root.hasPermissionToRezThis ? (buttonContainer.x - itemPreviewImage.x - itemPreviewImage.width) : + Math.min(itemNameTextMetrics.tightBoundingRect.width + 2, buttonContainer.x - itemPreviewImage.x - itemPreviewImage.width - noPermissionGlyph.width + 2); height: paintedHeight; // Text size size: 24; @@ -162,6 +167,91 @@ Item { } } } + HiFiGlyphs { + id: noPermissionGlyph; + visible: !root.hasPermissionToRezThis; + anchors.verticalCenter: itemName.verticalCenter; + anchors.left: itemName.right; + anchors.leftMargin: itemName.truncated ? -14 : -2; + text: hifi.glyphs.info; + // Size + size: 40; + width: 32; + // Style + color: hifi.colors.redAccent; + + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + + onEntered: { + noPermissionGlyph.color = hifi.colors.redHighlight; + } + onExited: { + noPermissionGlyph.color = hifi.colors.redAccent; + } + onClicked: { + permissionExplanationCard.visible = true; + } + } + } + Rectangle { + id: permissionExplanationCard; + z: 995; + visible: false; + anchors.fill: parent; + color: hifi.colors.white; + + RalewayRegular { + id: permissionExplanationText; + text: { + if (root.itemType === "contentSet") { + "You do not have 'Replace Content' permissions in this domain. Learn more"; + } else if (root.itemType === "entity") { + "You do not have 'Rez Certified' permissions in this domain. Learn more"; + } + } + size: 16; + anchors.left: parent.left; + anchors.leftMargin: 30; + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.right: permissionExplanationGlyph.left; + color: hifi.colors.baseGray; + wrapMode: Text.WordWrap; + verticalAlignment: Text.AlignVCenter; + + onLinkActivated: { + sendToPurchases({method: 'showPermissionsExplanation', itemType: root.itemType}); + } + } + // "Close" button + HiFiGlyphs { + id: permissionExplanationGlyph; + text: hifi.glyphs.close; + color: hifi.colors.baseGray; + size: 26; + anchors.top: parent.top; + anchors.bottom: parent.bottom; + anchors.right: parent.right; + width: 77; + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + onEntered: { + parent.text = hifi.glyphs.closeInverted; + } + onExited: { + parent.text = hifi.glyphs.close; + } + onClicked: { + permissionExplanationCard.visible = false; + } + } + } + } Item { id: certificateContainer; @@ -379,7 +469,7 @@ Item { anchors.right: parent.right; anchors.rightMargin: 4; width: height; - enabled: (root.canRezCertifiedItems || root.itemType === "wearable") && root.purchaseStatus !== "invalidated"; + enabled: root.hasPermissionToRezThis && root.purchaseStatus !== "invalidated"; onClicked: { if (root.itemType === "contentSet") { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 956bfa7c26..daa23d29c8 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -32,7 +32,6 @@ Rectangle { property bool securityImageResultReceived: false; property bool purchasesReceived: false; property bool punctuationMode: false; - property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); property bool pendingInventoryReply: true; property bool isShowingMyItems: false; property bool isDebuggingFirstUseTutorial: false; @@ -365,69 +364,6 @@ Rectangle { id: filteredPurchasesModel; } - Rectangle { - id: cantRezCertified; - visible: !root.canRezCertifiedItems; - color: "#FFC3CD"; - radius: 4; - border.color: hifi.colors.redAccent; - border.width: 1; - anchors.top: separator.bottom; - anchors.topMargin: 12; - anchors.left: parent.left; - anchors.leftMargin: 16; - anchors.right: parent.right; - anchors.rightMargin: 16; - height: 80; - - HiFiGlyphs { - id: lightningIcon; - text: hifi.glyphs.lightning; - // Size - size: 36; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 18; - anchors.left: parent.left; - anchors.leftMargin: 12; - horizontalAlignment: Text.AlignHCenter; - // Style - color: hifi.colors.lightGray; - } - - RalewayRegular { - text: "You don't have permission to rez certified items in this domain. " + - 'Learn More'; - // Text size - size: 18; - // Anchors - anchors.top: parent.top; - anchors.topMargin: 4; - anchors.left: lightningIcon.right; - anchors.leftMargin: 8; - anchors.right: parent.right; - anchors.rightMargin: 8; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 4; - // Style - color: hifi.colors.baseGray; - wrapMode: Text.WordWrap; - // Alignment - verticalAlignment: Text.AlignVCenter; - - onLinkActivated: { - lightboxPopup.titleText = "Rez Permission Required"; - lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.

" + - "Use the GOTO app to visit another domain or go to your own sandbox."; - lightboxPopup.button1text = "CLOSE"; - lightboxPopup.button1method = "root.visible = false;" - lightboxPopup.button2text = "OPEN GOTO"; - lightboxPopup.button2method = "sendToParent({method: 'purchases_openGoTo'});"; - lightboxPopup.visible = true; - } - } - } - ListView { id: purchasesContentsList; visible: (root.isShowingMyItems && filteredPurchasesModel.count !== 0) || (!root.isShowingMyItems && filteredPurchasesModel.count !== 0); @@ -436,13 +372,12 @@ Rectangle { snapMode: ListView.SnapToItem; highlightRangeMode: ListView.StrictlyEnforceRange; // Anchors - anchors.top: root.canRezCertifiedItems ? separator.bottom : cantRezCertified.bottom; + anchors.top: separator.bottom; anchors.topMargin: 12; anchors.left: parent.left; anchors.bottom: parent.bottom; width: parent.width; delegate: PurchasedItem { - canRezCertifiedItems: root.canRezCertifiedItems; itemName: title; itemId: id; itemPreviewImageUrl: preview; @@ -466,7 +401,7 @@ Rectangle { } else if (model.root_file_url.endsWith('.js')) { "app"; } else { - "entity"; + "unknown"; } } anchors.topMargin: 10; @@ -504,6 +439,21 @@ Rectangle { lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemId + "', '" + msg.itemHref + "'); root.visible = false;"; lightboxPopup.visible = true; + } else if (msg.method === "showPermissionsExplanation") { + if (msg.itemType === "entity") { + lightboxPopup.titleText = "Rez Certified Permission"; + lightboxPopup.bodyText = "You don't have permission to rez certified items in this domain.

" + + "Use the GOTO app to visit another domain or go to your own sandbox."; + lightboxPopup.button2text = "OPEN GOTO"; + lightboxPopup.button2method = "sendToParent({method: 'purchases_openGoTo'});"; + } else if (msg.itemType === "contentSet") { + lightboxPopup.titleText = "Replace Content Permission"; + lightboxPopup.bodyText = "You do not have the permission 'Replace Content' in this domain's server settings. The domain owner " + + "must enable it for you before you can replace content sets in this domain."; + } + lightboxPopup.button1text = "CLOSE"; + lightboxPopup.button1method = "root.visible = false;" + lightboxPopup.visible = true; } else if (msg.method === "setFilterText") { filterBar.text = msg.filterText; } diff --git a/interface/src/scripting/AccountServicesScriptingInterface.h b/interface/src/scripting/AccountServicesScriptingInterface.h index 012c37305d..cfa51697af 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.h +++ b/interface/src/scripting/AccountServicesScriptingInterface.h @@ -38,7 +38,7 @@ class AccountServicesScriptingInterface : public QObject { Q_PROPERTY(QString username READ getUsername NOTIFY myUsernameChanged) Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged) Q_PROPERTY(QString findableBy READ getFindableBy WRITE setFindableBy NOTIFY findableByChanged) - Q_PROPERTY(QUrl metaverseServerURL READ getMetaverseServerURL) + Q_PROPERTY(QUrl metaverseServerURL READ getMetaverseServerURL CONSTANT) public: static AccountServicesScriptingInterface* getInstance(); From 38290064c1c6510f2d3dd6b2333c03ef7dd2b6a8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 13 Feb 2018 13:24:08 -0800 Subject: [PATCH 45/83] replace materials by name, hide material mode for now --- libraries/entities/src/MaterialEntityItem.cpp | 8 ++- libraries/entities/src/MaterialEntityItem.h | 29 +++++++++-- libraries/graphics/src/graphics/Material.cpp | 3 ++ libraries/graphics/src/graphics/Material.h | 5 ++ .../src/model-networking/ModelCache.cpp | 1 + libraries/render-utils/src/Model.cpp | 24 +++++++-- libraries/render-utils/src/Model.h | 3 +- scripts/system/html/entityProperties.html | 34 ++++++++----- scripts/system/html/js/entityProperties.js | 49 ++++++++++++++++--- 9 files changed, 126 insertions(+), 30 deletions(-) diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 1ebaa4f21a..fcca2d9803 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -346,8 +346,12 @@ void MaterialEntityItem::applyMaterial() { } void MaterialEntityItem::postAdd() { - removeMaterial(); - applyMaterial(); + // postAdd is called every time we are added to a new octree cell, but we only need to update the material the first time + if (!_hasBeenAddedToOctree) { + removeMaterial(); + applyMaterial(); + _hasBeenAddedToOctree = true; + } } void MaterialEntityItem::preDelete() { diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index dde9b60da9..d015bae681 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -19,7 +19,7 @@ class MaterialEntityItem : public EntityItem { using Pointer = std::shared_ptr; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - + MaterialEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated @@ -44,9 +44,9 @@ public: virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; void debugDump() const override; @@ -89,20 +89,39 @@ public: void postParentFixup() override; private: + // URL for this material. Currently, only JSON format is supported. Set to "userData" to use the user data to live edit a material. + // The following fields are supported in the JSON: + // strings: + // name (NOT YET USED) + // floats: + // opacity, roughness, metallic, scattering + // colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB): + // emissive, albedo, fresnel + // urls to textures: + // emissiveMap, albedoMap, metallicMap, roughnessMap, normalMap, occlusionMap, lightmapMap, scatteringMap QString _materialURL; + // Type of material. "uv" or "projected". NOT YET IMPLEMENTED, only UV is used MaterialMode _materialMode { UV }; + // Priority for this material when applying it to its parent. Only the highest priority material will be used. Materials with the same priority are (essentially) randomly sorted. + // Base materials that come with models always have priority 0. quint16 _priority { 0 }; + // An identifier for choosing a submesh or submeshes within a parent. If in the format "mat::", all submeshes with material name "" will be replaced. Otherwise, + // parentMaterialID will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify. QString _parentMaterialID { "0" }; + // Offset position in UV-space of top left of material, (0, 0) to (1, 1) glm::vec2 _materialPos { 0, 0 }; + // How much to scale this material within its parent's UV-space glm::vec2 _materialScale { 1, 1 }; + // How much to rotate this material within its parent's UV-space (degrees) float _materialRot { 0 }; - + NetworkMaterialResourcePointer _networkMaterial; QHash> _materials; std::vector _materialNames; QString _currentMaterialName; bool _retryApply { false }; + bool _hasBeenAddedToOctree { false }; }; diff --git a/libraries/graphics/src/graphics/Material.cpp b/libraries/graphics/src/graphics/Material.cpp index 7c66c8ab07..2bf58bc6fb 100755 --- a/libraries/graphics/src/graphics/Material.cpp +++ b/libraries/graphics/src/graphics/Material.cpp @@ -34,6 +34,7 @@ Material::Material() : } Material::Material(const Material& material) : + _name(material._name), _key(material._key), _textureMaps(material._textureMaps) { @@ -50,6 +51,8 @@ Material::Material(const Material& material) : Material& Material::operator= (const Material& material) { QMutexLocker locker(&_textureMapsMutex); + _name = material._name; + _key = (material._key); _textureMaps = (material._textureMaps); _hasCalculatedTextureInfo = false; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 5b3396dfc5..5abc090be3 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -359,6 +359,11 @@ public: void setTextureTransforms(const Transform& transform); + const QString& getName() { return _name; } + +protected: + QString _name { "" }; + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 739f401ee7..19ee05d1e2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -619,6 +619,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur graphics::Material(*material._material), _textures(MapChannel::NUM_MAP_CHANNELS) { + _name = material.name; if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP); _albedoTransform = material.albedoTexture.transform; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3a9ea45d77..84687a46d0 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -828,6 +828,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _modelMeshRenderItemIDs.clear(); _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); foreach(auto item, _collisionRenderItemsMap.keys()) { @@ -1456,6 +1457,7 @@ void Model::createVisibleRenderItemSet() { Q_ASSERT(_modelMeshRenderItems.isEmpty()); _modelMeshRenderItems.clear(); + _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); Transform transform; @@ -1479,6 +1481,7 @@ void Model::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); + _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } @@ -1524,11 +1527,24 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -std::vector Model::getMeshIDsFromMaterialID(const QString& parentMaterialID) { - std::vector toReturn; - // TODO: first, try to find all meshes with materials that match parentMaterialID as a string +std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialID) { + // try to find all meshes with materials that match parentMaterialID as a string // if none, return parentMaterialID as a uint - toReturn.push_back(parentMaterialID.toUInt()); + std::vector toReturn; + const QString MATERIAL_NAME_PREFIX = "mat::"; + if (parentMaterialID.startsWith(MATERIAL_NAME_PREFIX)) { + parentMaterialID.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); + for (int i = 0; i < _modelMeshMaterialNames.size(); i++) { + if (_modelMeshMaterialNames[i] == parentMaterialID) { + toReturn.push_back(i); + } + } + } + + if (toReturn.empty()) { + toReturn.push_back(parentMaterialID.toUInt()); + } + return toReturn; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b4152324bc..67bc646473 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -438,6 +438,7 @@ protected: render::ItemIDs _modelMeshRenderItemIDs; using ShapeInfo = struct { int meshIndex; }; std::vector _modelMeshRenderItemShapes; + std::vector _modelMeshMaterialNames; bool _addedToScene { false }; // has been added to scene bool _needsFixupInScene { true }; // needs to be removed/re-added to scene @@ -472,7 +473,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(const QString& parentMaterialID); + std::vector getMeshIDsFromMaterialID(QString parentMaterialID); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 5eedd1c7e4..a70e42a7e1 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -772,12 +772,19 @@
-