From 5a843b13427e3d884f6779abb3af55efd67fc3c7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 14 Dec 2017 11:03:59 -0800 Subject: [PATCH 001/272] 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 002/272] 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 003/272] 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 c3801fee7e5093405a460be2b5df19f9625baa4b Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 27 Dec 2017 11:58:00 -0800 Subject: [PATCH 004/272] ka --- libraries/fbx/src/OBJReader.cpp | 20 +++++++++++++------- libraries/fbx/src/OBJReader.h | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 315c6a86d2..bd4158bcad 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -256,7 +256,13 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { default: materials[matName] = currentMaterial; #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Last material shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << " diffuse color:" << currentMaterial.diffuseColor << " specular color:" << currentMaterial.specularColor << " diffuse texture:" << currentMaterial.diffuseTextureFilename << " specular texture:" << currentMaterial.specularTextureFilename; + qCDebug(modelformat) << "OBJ Reader Last material shininess:" << currentMaterial.shininess << " opacity:" << + currentMaterial.opacity << " diffuse color:" << currentMaterial.diffuseColor << + " specular color:" << currentMaterial.specularColor << " emissive color:" << + currentMaterial.emissiveColor << " diffuse texture:" << + currentMaterial.diffuseTextureFilename << " specular texture:" << + currentMaterial.specularTextureFilename << " emissive texture:" << + currentMaterial.emissiveTextureFilename; #endif return; } @@ -277,14 +283,12 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if ((token == "d") || (token == "Tr")) { currentMaterial.opacity = tokenizer.getFloat(); } else if (token == "Ka") { - #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3(); - #endif + currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Kd") { currentMaterial.diffuseColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); - } else if ((token == "map_Kd") || (token == "map_Ks")) { + } else if ((token == "map_Ka") || (token == "map_Kd") || (token == "map_Ks")) { QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8(); if (filename.endsWith(".tga")) { #ifdef WANT_DEBUG @@ -292,7 +296,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { #endif break; } - if (token == "map_Kd") { + if (token == "map_Ka") { + currentMaterial.emissiveTextureFilename = filename; + } else if (token == "map_Kd") { currentMaterial.diffuseTextureFilename = filename; } else if( token == "map_Ks" ) { currentMaterial.specularTextureFilename = filename; @@ -725,7 +731,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, } geometry.materials[materialID] = FBXMaterial(objMaterial.diffuseColor, objMaterial.specularColor, - glm::vec3(0.0f), + objMaterial.emissiveColor, objMaterial.shininess, objMaterial.opacity); FBXMaterial& fbxMaterial = geometry.materials[materialID]; diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 45e3f79480..e25cd7c5e9 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -56,11 +56,13 @@ public: float opacity; glm::vec3 diffuseColor; glm::vec3 specularColor; + glm::vec3 emissiveColor; QByteArray diffuseTextureFilename; QByteArray specularTextureFilename; + QByteArray emissiveTextureFilename; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.9f) {} }; class OBJReader: public QObject { // QObject so we can make network requests. From 5e45ee456c610733a5b598780aab45573dd7cf73 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 27 Dec 2017 16:55:45 -0800 Subject: [PATCH 005/272] more ka --- interface/resources/qml/js/Utils.jsc | Bin 6596 -> 6516 bytes libraries/fbx/src/OBJReader.cpp | 5 +++++ 2 files changed, 5 insertions(+) diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc index ab20e996b9469915ac6a89901da175143e6b5024..8da68e4e192018ee2b4f3d835ec91f36f0161eca 100644 GIT binary patch delta 522 zcmX?N{KZJ8u*@VmC9xz?kb!}Lk&~5STcM<00wV*14l4u0rhn_zD^;ej?k>4g!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-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#rBDLnsetEmissive(fbxMaterial.emissiveColor); modelMaterial->setAlbedo(fbxMaterial.diffuseColor); From 38d2266d28bef0d418525acf251d6d76e201708c Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 27 Dec 2017 17:14:45 -0800 Subject: [PATCH 006/272] Tr --- libraries/fbx/src/OBJReader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 0395173c68..de60efbc1d 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -282,8 +282,10 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { //currentMaterial.specularTextureFilename = ""; } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); - } else if ((token == "d") || (token == "Tr")) { + } else if (token == "d") { currentMaterial.opacity = tokenizer.getFloat(); + } else if (token == "Tr") { + currentMaterial.opacity = 1.0f - tokenizer.getFloat(); } else if (token == "Ka") { currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Kd") { From 188e476f2f203bc5e832fb18afd9192a759ef260 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 28 Dec 2017 13:57:12 -0800 Subject: [PATCH 007/272] temp obj import fixes --- libraries/fbx/src/OBJReader.cpp | 24 ++++++++++++++++++++++-- libraries/render-utils/src/Model.cpp | 2 +- libraries/shared/src/Transform.cpp | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index de60efbc1d..51e7c3cafb 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -467,14 +467,34 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi // vertex-index/texture-index // vertex-index/texture-index/surface-normal-index QByteArray token = tokenizer.getDatum(); - if (!isdigit(token[0])) { // Tokenizer treats line endings as whitespace. Non-digit indicates done; + auto firstChar = token[0]; + // Tokenizer treats line endings as whitespace. Non-digit and non-negative sign indicates done; + if (!isdigit(firstChar) && firstChar != '-') { tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } QList parts = token.split('/'); assert(parts.count() >= 1); assert(parts.count() <= 3); - const QByteArray noData {}; + // If indices are negative relative indices then adjust them to absolute indices based on current vector sizes + // Also add 1 to each index as 1 will be subtracted later on from each index in OBJFace::add + int part0 = parts[0].toInt(); + if (part0 < 0) { + parts[0].setNum(vertices.size() - abs(part0) + 1); + } + if (parts.count() > 1) { + int part1 = parts[1].toInt(); + if (part1 < 0) { + parts[1].setNum(textureUVs.size() - abs(part1) + 1); + } + if (parts.count() > 2) { + int part2 = parts[2].toInt(); + if (part2 < 0) { + parts[2].setNum(normals.size() - abs(part2) + 1); + } + } + } + const QByteArray noData{}; face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData, vertices, vertexColors); face.groupName = currentGroup; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7717ceda6f..fd9f753a75 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -163,7 +163,7 @@ void Model::setScale(const glm::vec3& scale) { _scaledToFit = false; } -const float SCALE_CHANGE_EPSILON = 0.001f; +const float SCALE_CHANGE_EPSILON = 0.0000001f; void Model::setScaleInternal(const glm::vec3& scale) { if (glm::distance(_scale, scale) > SCALE_CHANGE_EPSILON) { diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index 3e29c38add..eeb726ba72 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -19,7 +19,7 @@ #include "shared/JSONHelpers.h" void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix) { - const float ACCURACY_THREASHOLD = 0.00001f; + const float ACCURACY_THREASHOLD = 0.000001f; // Following technique taken from: // http://callumhay.blogspot.com/2010/10/decomposing-affine-transforms.html From dee06e72f6c627da15e97dc1c67ac8873b5cab94 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 28 Dec 2017 16:08:53 -0800 Subject: [PATCH 008/272] ke is the new ka --- libraries/fbx/src/OBJReader.cpp | 18 +++++++++++------- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 51e7c3cafb..07d445fb3e 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -277,9 +277,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader Starting new material definition " << matName; #endif - //currentMaterial.emissiveTextureFilename = ""; currentMaterial.diffuseTextureFilename = ""; - //currentMaterial.specularTextureFilename = ""; + currentMaterial.emissiveTextureFilename = ""; + currentMaterial.specularTextureFilename = ""; } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); } else if (token == "d") { @@ -287,12 +287,16 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "Tr") { currentMaterial.opacity = 1.0f - tokenizer.getFloat(); } else if (token == "Ka") { - currentMaterial.emissiveColor = tokenizer.getVec3(); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3(); + #endif } else if (token == "Kd") { currentMaterial.diffuseColor = tokenizer.getVec3(); + } else if (token == "Ke") { + currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); - } else if ((token == "map_Ka") || (token == "map_Kd") || (token == "map_Ks")) { + } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks")) { QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8(); if (filename.endsWith(".tga")) { #ifdef WANT_DEBUG @@ -300,10 +304,10 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { #endif break; } - if (token == "map_Ka") { - currentMaterial.emissiveTextureFilename = filename; - } else if (token == "map_Kd") { + if (token == "map_Kd") { currentMaterial.diffuseTextureFilename = filename; + } else if (token == "map_Ke") { + currentMaterial.emissiveTextureFilename = filename; } else if( token == "map_Ks" ) { currentMaterial.specularTextureFilename = filename; } diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index e25cd7c5e9..f0852c9c22 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -62,7 +62,7 @@ public: QByteArray emissiveTextureFilename; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.9f) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f) {} }; class OBJReader: public QObject { // QObject so we can make network requests. From a855916eb89c1ef3b8d744e2ef9b7f477715f29d Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 28 Dec 2017 16:39:02 -0800 Subject: [PATCH 009/272] fix relative paths --- libraries/fbx/src/OBJReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 07d445fb3e..3b4eed6746 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -297,7 +297,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks")) { - QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8(); + QByteArray filename = QString(tokenizer.getLineAsDatum()).toUtf8(); if (filename.endsWith(".tga")) { #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << _url; From cee6bd270079125729dd9748665e4714efb0f32f Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 28 Dec 2017 17:20:16 -0800 Subject: [PATCH 010/272] ignore Ni --- libraries/fbx/src/OBJReader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 3b4eed6746..d6955a6945 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -282,6 +282,10 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.specularTextureFilename = ""; } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); + } else if (token == "Ni") { + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << tokenizer.getFloat(); + #endif } else if (token == "d") { currentMaterial.opacity = tokenizer.getFloat(); } else if (token == "Tr") { From 7531a2ef3b9e134e2000ed79c507bed7b1acafca Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Dec 2017 18:00:07 -0800 Subject: [PATCH 011/272] map_bump wip --- interface/resources/qml/js/Utils.jsc | Bin 6516 -> 6548 bytes libraries/fbx/src/OBJReader.cpp | 15 ++++++++++++--- libraries/fbx/src/OBJReader.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc index 8da68e4e192018ee2b4f3d835ec91f36f0161eca..0e4b04d46e53fb0fdea77cfc8b85627fa9276aad 100644 GIT binary patch delta 180 zcmW;8JqrPG9KiAK@A_XIoALs@0CnO@Nl`9F7A%U(LtQK$x|L+t^_Lf5mJ%uN!D2Uf z0Y)2x(r5X+)0<3k95~&cH}hhEL`*t~bR|LRQXGhvF2i${P@ W51R@;Gu>8oK_AsT%v-0F>BfHt$1Yz0 delta 155 zcmbPY{KZJ8u*@VmC9xz?kb!}Lk&~5STcM<00wV*14l4u0rhn_zD^;ej?k>4g!mi%G zd7@4Wqrt?D;Y<(MCv!1|F&>zl$QaJ3FnK4VKhp!@$y`j^1h=p-FdSiFV7S7setEmissive(fbxMaterial.emissiveColor); modelMaterial->setAlbedo(fbxMaterial.diffuseColor); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index f0852c9c22..d0bbd539e9 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -60,6 +60,7 @@ public: QByteArray diffuseTextureFilename; QByteArray specularTextureFilename; QByteArray emissiveTextureFilename; + QByteArray bumpTextureFilename; bool used { false }; bool userSpecifiesUV { false }; OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f) {} From a44e00142dfb867e960596397689e7c3f617210c Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 2 Jan 2018 15:41:14 -0800 Subject: [PATCH 012/272] texture line parse wip --- libraries/fbx/src/OBJReader.cpp | 31 ++++++++++++++++++++++++++++--- libraries/fbx/src/OBJReader.h | 7 +++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 73c0f07fa6..d5eeec51d0 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -303,8 +303,10 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump")) { - QByteArray textureLine = QString(tokenizer.getLineAsDatum()).toUtf8(); - QByteArray filename = textureLine; // TODO: parse texture options and filename from line + const QByteArray textureLine = tokenizer.getLineAsDatum(); + QByteArray filename; + OBJMaterialTextureOptions textureOptions; + parseTextureLine(textureLine, filename, textureOptions); if (filename.endsWith(".tga")) { #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << _url; @@ -315,13 +317,36 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.diffuseTextureFilename = filename; } else if (token == "map_Ke") { currentMaterial.emissiveTextureFilename = filename; - } else if( token == "map_Ks" ) { + } else if (token == "map_Ks" ) { currentMaterial.specularTextureFilename = filename; } else if (token == "map_bump") { currentMaterial.bumpTextureFilename = filename; } } } +} + +void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { + QString parser = textureLine; + while (parser.length() > 0) { + if (parser.startsWith("-bm")) { + parser.remove(0, 4); + int multiplierEnd = parser.indexOf(' '); + if (multiplierEnd < 0) { + multiplierEnd = parser.length(); + } + QString multiplier = parser.left(multiplierEnd); + textureOptions.bumpMultiplier = std::stof(multiplier.toStdString()); + parser.remove(0, multiplier.length() + 1); + } else { + int fileEnd = parser.indexOf(' '); + if (fileEnd < 0) { + fileEnd = parser.length(); + } + filename = parser.left(fileEnd).toUtf8(); + parser.remove(0, filename.length() + 1); + } + } } std::tuple requestData(QUrl& url) { diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index d0bbd539e9..2c1db7ccf7 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -66,6 +66,12 @@ public: OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f) {} }; +class OBJMaterialTextureOptions { +public: + float bumpMultiplier; + OBJMaterialTextureOptions() : bumpMultiplier(1.0f) {} +}; + class OBJReader: public QObject { // QObject so we can make network requests. Q_OBJECT public: @@ -87,6 +93,7 @@ private: bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, bool combineParts); void parseMaterialLibrary(QIODevice* device); + void parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions); bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format. int _partCounter { 0 }; From 88b034aa78ddb3be7c95190bf6bf38742609b616 Mon Sep 17 00:00:00 2001 From: David Back Date: Tue, 2 Jan 2018 16:35:43 -0800 Subject: [PATCH 013/272] bump multiplier --- libraries/fbx/src/FBX.h | 2 ++ libraries/fbx/src/OBJReader.cpp | 8 ++++++-- libraries/fbx/src/OBJReader.h | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 7d3328a2dd..70344512ca 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -178,6 +178,8 @@ public: float emissiveIntensity{ 1.0f }; float ambientFactor{ 1.0f }; + float bumpMultiplier{ 1.0f }; + QString materialID; QString name; QString shadingModel; diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index d5eeec51d0..6127b454b8 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -302,7 +302,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); - } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump")) { + } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump")) { const QByteArray textureLine = tokenizer.getLineAsDatum(); QByteArray filename; OBJMaterialTextureOptions textureOptions; @@ -319,8 +319,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveTextureFilename = filename; } else if (token == "map_Ks" ) { currentMaterial.specularTextureFilename = filename; - } else if (token == "map_bump") { + } else if ((token == "map_bump") || (token == "bump")) { currentMaterial.bumpTextureFilename = filename; + currentMaterial.bumpMultiplier = textureOptions.bumpMultiplier; } } } @@ -338,6 +339,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file QString multiplier = parser.left(multiplierEnd); textureOptions.bumpMultiplier = std::stof(multiplier.toStdString()); parser.remove(0, multiplier.length() + 1); + } else if (parser[0] == '-') { + // TO DO } else { int fileEnd = parser.indexOf(' '); if (fileEnd < 0) { @@ -813,6 +816,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, if (!objMaterial.bumpTextureFilename.isEmpty()) { fbxMaterial.normalTexture.filename = objMaterial.bumpTextureFilename; fbxMaterial.normalTexture.isBumpmap = true; + fbxMaterial.bumpMultiplier = objMaterial.bumpMultiplier; } modelMaterial->setEmissive(fbxMaterial.emissiveColor); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 2c1db7ccf7..ab2fd2fd78 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -61,9 +61,10 @@ public: QByteArray specularTextureFilename; QByteArray emissiveTextureFilename; QByteArray bumpTextureFilename; + float bumpMultiplier; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), bumpMultiplier(1.0f) {} }; class OBJMaterialTextureOptions { From dfb9d9ce6b3d82bc404f4683c6638dd11023477b Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 3 Jan 2018 13:58:27 -0800 Subject: [PATCH 014/272] illum model wip --- libraries/fbx/src/OBJReader.cpp | 53 ++++++++++++++++++++++++++++----- libraries/fbx/src/OBJReader.h | 1 + 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 6127b454b8..1e31371178 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -256,12 +256,12 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { default: materials[matName] = currentMaterial; #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Last material shininess:" << currentMaterial.shininess << " opacity:" << - currentMaterial.opacity << " diffuse color:" << currentMaterial.diffuseColor << - " specular color:" << currentMaterial.specularColor << " emissive color:" << - currentMaterial.emissiveColor << " diffuse texture:" << - currentMaterial.diffuseTextureFilename << " specular texture:" << - currentMaterial.specularTextureFilename << " emissive texture:" << + qCDebug(modelformat) << "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << + " shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << + " diffuse color:" << currentMaterial.diffuseColor << " specular color:" << + currentMaterial.specularColor << " emissive color:" << currentMaterial.emissiveColor << + " diffuse texture:" << currentMaterial.diffuseTextureFilename << " specular texture:" << + currentMaterial.specularTextureFilename << " emissive texture:" << currentMaterial.emissiveTextureFilename << " bump texture:" << currentMaterial.bumpTextureFilename; #endif @@ -302,6 +302,8 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); + } else if (token == "illum") { + currentMaterial.illuminationModel = tokenizer.getFloat(); } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump")) { const QByteArray textureLine = tokenizer.getLineAsDatum(); QByteArray filename; @@ -824,8 +826,45 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor)); modelMaterial->setRoughness(model::Material::shininessToRoughness(fbxMaterial.shininess)); + // Illumination model reference http://paulbourke.net/dataformats/mtl/ + switch (objMaterial.illuminationModel) { + case 0: // Color on and Ambient off + fbxMaterial.ambientFactor = 0.0f; + break; + case 1: // Color on and Ambient on + fbxMaterial.ambientFactor = 1.0f; + break; + case 2: // Highlight on + fbxMaterial.specularFactor = 1.0f; + break; + case 3: // Reflection on and Ray trace on + break; + case 4: // Transparency: Glass on and Reflection: Ray trace on + fbxMaterial.opacity = 0.0f; + break; + case 5: // Reflection: Fresnel on and Ray trace on + modelMaterial->setFresnel(glm::vec3(1.0f)); + break; + case 6: // Transparency: Refraction on and Reflection: Fresnel off and Ray trace on + fbxMaterial.opacity = 0.0f; + modelMaterial->setFresnel(glm::vec3(0.0f)); + break; + case 7: // Transparency: Refraction on and Reflection: Fresnel on and Ray trace on + fbxMaterial.opacity = 0.0f; + modelMaterial->setFresnel(glm::vec3(1.0f)); + break; + case 8: // Reflection on and Ray trace off + break; + case 9: // Transparency: Glass on and Reflection: Ray trace off + fbxMaterial.opacity = 0.0f; + break; + case 10: // Casts shadows onto invisible surfaces + // Do nothing? + break; + } + if (fbxMaterial.opacity <= 0.0f) { - modelMaterial->setOpacity(1.0f); + modelMaterial->setOpacity(0.0f); // previous was 1.0f? } else { modelMaterial->setOpacity(fbxMaterial.opacity); } diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index ab2fd2fd78..eb7376c64f 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -62,6 +62,7 @@ public: QByteArray emissiveTextureFilename; QByteArray bumpTextureFilename; float bumpMultiplier; + int illuminationModel; bool used { false }; bool userSpecifiesUV { false }; OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), bumpMultiplier(1.0f) {} From cbaba8688171d3530859f659038a4131afd604d1 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 3 Jan 2018 15:50:24 -0800 Subject: [PATCH 015/272] more texture options --- interface/resources/qml/js/Utils.jsc | Bin 6548 -> 6516 bytes libraries/fbx/src/OBJReader.cpp | 131 +++++++++++++++++++++++---- libraries/fbx/src/OBJReader.h | 18 ++-- 3 files changed, 121 insertions(+), 28 deletions(-) diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc index 0e4b04d46e53fb0fdea77cfc8b85627fa9276aad..8da68e4e192018ee2b4f3d835ec91f36f0161eca 100644 GIT binary patch delta 155 zcmbPY{KZJ8u*@VmC9xz?kb!}Lk&~5STcM<00wV*14l4u0rhn_zD^;ej?k>4g!mi%G zd7@4Wqrt?D;Y<(MCv!1|F&>zl$QaJ3FnK4VKhp!@$y`j^1h=p-FdSiFV7S7R|LRQXGhvF2i${P@ W51R@;Gu>8oK_AsT%v-0F>BfHt$1Yz0 diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 1e31371178..2e4fff700c 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -323,33 +323,124 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.specularTextureFilename = filename; } else if ((token == "map_bump") || (token == "bump")) { currentMaterial.bumpTextureFilename = filename; - currentMaterial.bumpMultiplier = textureOptions.bumpMultiplier; + currentMaterial.bumpTextureOptions = textureOptions; } } } } +bool OBJReader::parseTextureLineFloat(QString& parser, float& result) { + if (parser.length() == 0) { + return false; + } + auto firstChar = parser[0]; + if ((firstChar < '0' || firstChar > '9') && firstChar != '-') { + return false; + } + int floatEnd = parser.indexOf(' '); + if (floatEnd < 0) { + floatEnd = parser.length(); + } + QString floatStr = parser.left(floatEnd); + try + { + result = std::stof(floatStr.toStdString()); + parser.remove(0, floatStr.length() + 1); + return true; + } + catch (const std::exception& /*e*/) + { + return false; + } +} + +bool OBJReader::parseTextureLineString(QString& parser, QByteArray& result) { + if (parser.length() == 0) { + return false; + } + int stringEnd = parser.indexOf(' '); + if (stringEnd < 0) { + stringEnd = parser.length(); + } + result = parser.left(stringEnd).toUtf8(); + parser.remove(0, result.length() + 1); + return true; +} + void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { + // Texture options reference http://paulbourke.net/dataformats/mtl/ + // and https://wikivisually.com/wiki/Material_Template_Library QString parser = textureLine; while (parser.length() > 0) { - if (parser.startsWith("-bm")) { - parser.remove(0, 4); - int multiplierEnd = parser.indexOf(' '); - if (multiplierEnd < 0) { - multiplierEnd = parser.length(); - } - QString multiplier = parser.left(multiplierEnd); - textureOptions.bumpMultiplier = std::stof(multiplier.toStdString()); - parser.remove(0, multiplier.length() + 1); - } else if (parser[0] == '-') { - // TO DO - } else { - int fileEnd = parser.indexOf(' '); - if (fileEnd < 0) { - fileEnd = parser.length(); - } - filename = parser.left(fileEnd).toUtf8(); - parser.remove(0, filename.length() + 1); + if (parser.startsWith("-blendu") || parser.startsWith("-blendv")) { + parser.remove(0, 11); // remove through "-blendu on " or "-blendu off" + if (parser[0] == ' ') // extra character for space after off + parser.remove(0, 1); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -blendu/-blendv"; + #endif + } else if (parser.startsWith("-bm")) { + parser.remove(0, 4); // remove through "-bm " + parseTextureLineFloat(parser, textureOptions.bumpMultiplier); + } else if (parser.startsWith("-boost")) { + parser.remove(0, 7); // remove through "-boost " + float ignore; + parseTextureLineFloat(parser, ignore); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -boost"; + #endif + } else if (parser.startsWith("-cc")) { + parser.remove(0, 7); // remove through "-cc on " or "-cc off" + if (parser[0] == ' ') // extra character for space after off + parser.remove(0, 1); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -cc"; + #endif + } else if (parser.startsWith("-clamp")) { + parser.remove(0, 10); // remove through "-clamp on " or "-clamp off" + if (parser[0] == ' ') // extra character for space after off + parser.remove(0, 1); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -clamp"; + #endif + } else if (parser.startsWith("-imfchan")) { + parser.remove(0, 11); // remove through "-imfchan X " + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -imfchan"; + #endif + } else if (parser.startsWith("-mm")) { + parser.remove(0, 4); // remove through "-mm " + float ignore; + parseTextureLineFloat(parser, ignore); + parseTextureLineFloat(parser, ignore); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -mm"; + #endif + } else if (parser.startsWith("-o") || parser.startsWith("-s") || parser.startsWith("-t")) { + parser.remove(0, 3); // remove through "-o " + float ignore; + parseTextureLineFloat(parser, ignore); + parseTextureLineFloat(parser, ignore); + parseTextureLineFloat(parser, ignore); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -o/-s/-t"; + #endif + } else if (parser.startsWith("-texres")) { + parser.remove(0, 8); // remove through "-texres " + float ignore; + parseTextureLineFloat(parser, ignore); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -texres"; + #endif + } else if (parser.startsWith("-type")) { + parser.remove(0, 6); // remove through "-type " + QByteArray ignore; + parseTextureLineString(parser, ignore); + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -type"; + #endif + } else { // assume filename + parseTextureLineString(parser, filename); } } } @@ -818,7 +909,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, if (!objMaterial.bumpTextureFilename.isEmpty()) { fbxMaterial.normalTexture.filename = objMaterial.bumpTextureFilename; fbxMaterial.normalTexture.isBumpmap = true; - fbxMaterial.bumpMultiplier = objMaterial.bumpMultiplier; + fbxMaterial.bumpMultiplier = objMaterial.bumpTextureOptions.bumpMultiplier; } modelMaterial->setEmissive(fbxMaterial.emissiveColor); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index eb7376c64f..a4582d6ef4 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -48,6 +48,12 @@ private: void addFrom(const OBJFace* face, int index); }; +class OBJMaterialTextureOptions { +public: + float bumpMultiplier; + OBJMaterialTextureOptions() : bumpMultiplier(1.0f) {} +} +; // Materials and references to material names can come in any order, and different mesh parts can refer to the same material. // Therefore it would get pretty hacky to try to use FBXMeshPart to store these as we traverse the files. class OBJMaterial { @@ -61,17 +67,11 @@ public: QByteArray specularTextureFilename; QByteArray emissiveTextureFilename; QByteArray bumpTextureFilename; - float bumpMultiplier; + OBJMaterialTextureOptions bumpTextureOptions; int illuminationModel; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), bumpMultiplier(1.0f) {} -}; - -class OBJMaterialTextureOptions { -public: - float bumpMultiplier; - OBJMaterialTextureOptions() : bumpMultiplier(1.0f) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), illuminationModel(0) {} }; class OBJReader: public QObject { // QObject so we can make network requests. @@ -95,6 +95,8 @@ private: bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, bool combineParts); void parseMaterialLibrary(QIODevice* device); + bool parseTextureLineFloat(QString& parser, float& result); + bool parseTextureLineString(QString& parser, QByteArray& result); void parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions); bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format. From e9f30549f487604fb8f5384770f7da7269de19b8 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 3 Jan 2018 18:20:07 -0800 Subject: [PATCH 016/272] ignore Tf, disable illum test --- libraries/fbx/src/OBJReader.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 2e4fff700c..ca69ccb64d 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -292,6 +292,12 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.opacity = tokenizer.getFloat(); } else if (token == "Tr") { currentMaterial.opacity = 1.0f - tokenizer.getFloat(); + } else if (token == "illum") { + currentMaterial.illuminationModel = tokenizer.getFloat(); + } else if (token == "Tf") { + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << tokenizer.getVec3(); + #endif } else if (token == "Ka") { #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3(); @@ -302,8 +308,6 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.emissiveColor = tokenizer.getVec3(); } else if (token == "Ks") { currentMaterial.specularColor = tokenizer.getVec3(); - } else if (token == "illum") { - currentMaterial.illuminationModel = tokenizer.getFloat(); } else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump")) { const QByteArray textureLine = tokenizer.getLineAsDatum(); QByteArray filename; @@ -917,6 +921,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor)); modelMaterial->setRoughness(model::Material::shininessToRoughness(fbxMaterial.shininess)); + /* // Illumination model reference http://paulbourke.net/dataformats/mtl/ switch (objMaterial.illuminationModel) { case 0: // Color on and Ambient off @@ -953,12 +958,9 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Do nothing? break; } + */ - if (fbxMaterial.opacity <= 0.0f) { - modelMaterial->setOpacity(0.0f); // previous was 1.0f? - } else { - modelMaterial->setOpacity(fbxMaterial.opacity); - } + modelMaterial->setOpacity(fbxMaterial.opacity); } return geometryPtr; From 2c5a433ea1f695cf6a3cb46d1f46e7cc55565b31 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 4 Jan 2018 12:56:57 -0800 Subject: [PATCH 017/272] fix datum reset with comment token --- libraries/fbx/src/OBJReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index ca69ccb64d..d4cb5de497 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -70,6 +70,7 @@ int OBJTokenizer::nextToken(bool allowSpaceChar /*= false*/) { } switch (ch) { case '#': { + _datum = ""; _comment = _device->readLine(); // stash comment for a future call to getComment return COMMENT_TOKEN; } From fcac489efb92c9da28742e6ed80a465a530cb1a1 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 4 Jan 2018 16:39:44 -0800 Subject: [PATCH 018/272] illum mode adjustments, small tweaks --- libraries/fbx/src/FBX.h | 2 +- libraries/fbx/src/OBJReader.cpp | 72 +++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 70344512ca..c1842dbee4 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -178,7 +178,7 @@ public: float emissiveIntensity{ 1.0f }; float ambientFactor{ 1.0f }; - float bumpMultiplier{ 1.0f }; + float bumpMultiplier{ 1.0f }; // TODO: to be implemented QString materialID; QString name; diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index d4cb5de497..8fc683b0d5 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -286,8 +286,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); } else if (token == "Ni") { + float ignore = tokenizer.getFloat(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << tokenizer.getFloat(); + qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << ignore; #endif } else if (token == "d") { currentMaterial.opacity = tokenizer.getFloat(); @@ -296,12 +297,14 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "illum") { currentMaterial.illuminationModel = tokenizer.getFloat(); } else if (token == "Tf") { + glm::vec3 ignore = tokenizer.getVec3(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << tokenizer.getVec3(); + qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << ignore; #endif } else if (token == "Ka") { + glm::vec3 ignore = tokenizer.getVec3(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3(); + qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << ignore; #endif } else if (token == "Kd") { currentMaterial.diffuseColor = tokenizer.getVec3(); @@ -379,8 +382,9 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file while (parser.length() > 0) { if (parser.startsWith("-blendu") || parser.startsWith("-blendv")) { parser.remove(0, 11); // remove through "-blendu on " or "-blendu off" - if (parser[0] == ' ') // extra character for space after off + if (parser[0] == ' ') { // extra character for space after off parser.remove(0, 1); + } #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -blendu/-blendv"; #endif @@ -396,15 +400,17 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file #endif } else if (parser.startsWith("-cc")) { parser.remove(0, 7); // remove through "-cc on " or "-cc off" - if (parser[0] == ' ') // extra character for space after off + if (parser[0] == ' ') { // extra character for space after off parser.remove(0, 1); + } #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -cc"; #endif } else if (parser.startsWith("-clamp")) { parser.remove(0, 10); // remove through "-clamp on " or "-clamp off" - if (parser[0] == ' ') // extra character for space after off + if (parser[0] == ' ') { // extra character for space after off parser.remove(0, 1); + } #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -clamp"; #endif @@ -922,44 +928,76 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor)); modelMaterial->setRoughness(model::Material::shininessToRoughness(fbxMaterial.shininess)); - /* + bool applyTransparency = false; + bool applyShininess = false; + bool applyRoughness = false; + bool applyNonMetallic = false; + bool fresnelOn = false; + bool fresnelOff = false; + // Illumination model reference http://paulbourke.net/dataformats/mtl/ switch (objMaterial.illuminationModel) { case 0: // Color on and Ambient off - fbxMaterial.ambientFactor = 0.0f; + // We don't support ambient - do nothing? break; case 1: // Color on and Ambient on - fbxMaterial.ambientFactor = 1.0f; + // We don't support ambient - do nothing? break; case 2: // Highlight on fbxMaterial.specularFactor = 1.0f; break; case 3: // Reflection on and Ray trace on + applyShininess = true; break; case 4: // Transparency: Glass on and Reflection: Ray trace on - fbxMaterial.opacity = 0.0f; + applyTransparency = true; + applyShininess = true; break; case 5: // Reflection: Fresnel on and Ray trace on - modelMaterial->setFresnel(glm::vec3(1.0f)); + applyShininess = true; + fresnelOn = true; break; case 6: // Transparency: Refraction on and Reflection: Fresnel off and Ray trace on - fbxMaterial.opacity = 0.0f; - modelMaterial->setFresnel(glm::vec3(0.0f)); + applyTransparency = true; + applyNonMetallic = true; + applyShininess = true; + fresnelOff = true; break; case 7: // Transparency: Refraction on and Reflection: Fresnel on and Ray trace on - fbxMaterial.opacity = 0.0f; - modelMaterial->setFresnel(glm::vec3(1.0f)); + applyTransparency = true; + applyNonMetallic = true; + applyShininess = true; + fresnelOn = true; break; case 8: // Reflection on and Ray trace off + applyShininess = true; break; case 9: // Transparency: Glass on and Reflection: Ray trace off - fbxMaterial.opacity = 0.0f; + applyTransparency = true; + applyNonMetallic = true; + applyRoughness = true; break; case 10: // Casts shadows onto invisible surfaces // Do nothing? break; + } + + if (applyTransparency && fbxMaterial.opacity <= 0.1f) { + fbxMaterial.opacity = 0.1f; + } + if (applyShininess) { + modelMaterial->setRoughness(0.25f); + } else if (applyRoughness) { + modelMaterial->setRoughness(1.0f); + } + if (applyNonMetallic) { + modelMaterial->setMetallic(0.0f); + } + if (fresnelOn) { + modelMaterial->setFresnel(glm::vec3(1.0f)); + } else if (fresnelOff) { + modelMaterial->setFresnel(glm::vec3(0.0f)); } - */ modelMaterial->setOpacity(fbxMaterial.opacity); } From 7c99c85ecae4eb7066c7bb7a679cc542afc4c9d9 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 5 Jan 2018 13:54:16 -0800 Subject: [PATCH 019/272] Revert "temp obj import fixes" This reverts commit 188e476f2f203bc5e832fb18afd9192a759ef260. --- libraries/fbx/src/OBJReader.cpp | 24 ++---------------------- libraries/render-utils/src/Model.cpp | 2 +- libraries/shared/src/Transform.cpp | 2 +- 3 files changed, 4 insertions(+), 24 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 8fc683b0d5..2c09b2021d 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -612,34 +612,14 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi // vertex-index/texture-index // vertex-index/texture-index/surface-normal-index QByteArray token = tokenizer.getDatum(); - auto firstChar = token[0]; - // Tokenizer treats line endings as whitespace. Non-digit and non-negative sign indicates done; - if (!isdigit(firstChar) && firstChar != '-') { + if (!isdigit(token[0])) { // Tokenizer treats line endings as whitespace. Non-digit indicates done; tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN); break; } QList parts = token.split('/'); assert(parts.count() >= 1); assert(parts.count() <= 3); - // If indices are negative relative indices then adjust them to absolute indices based on current vector sizes - // Also add 1 to each index as 1 will be subtracted later on from each index in OBJFace::add - int part0 = parts[0].toInt(); - if (part0 < 0) { - parts[0].setNum(vertices.size() - abs(part0) + 1); - } - if (parts.count() > 1) { - int part1 = parts[1].toInt(); - if (part1 < 0) { - parts[1].setNum(textureUVs.size() - abs(part1) + 1); - } - if (parts.count() > 2) { - int part2 = parts[2].toInt(); - if (part2 < 0) { - parts[2].setNum(normals.size() - abs(part2) + 1); - } - } - } - const QByteArray noData{}; + const QByteArray noData {}; face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData, vertices, vertexColors); face.groupName = currentGroup; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 536e76e44e..b91f4dd405 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -163,7 +163,7 @@ void Model::setScale(const glm::vec3& scale) { _scaledToFit = false; } -const float SCALE_CHANGE_EPSILON = 0.0000001f; +const float SCALE_CHANGE_EPSILON = 0.001f; void Model::setScaleInternal(const glm::vec3& scale) { if (glm::distance(_scale, scale) > SCALE_CHANGE_EPSILON) { diff --git a/libraries/shared/src/Transform.cpp b/libraries/shared/src/Transform.cpp index eeb726ba72..3e29c38add 100644 --- a/libraries/shared/src/Transform.cpp +++ b/libraries/shared/src/Transform.cpp @@ -19,7 +19,7 @@ #include "shared/JSONHelpers.h" void Transform::evalRotationScale(Quat& rotation, Vec3& scale, const Mat3& rotationScaleMatrix) { - const float ACCURACY_THREASHOLD = 0.000001f; + const float ACCURACY_THREASHOLD = 0.00001f; // Following technique taken from: // http://callumhay.blogspot.com/2010/10/decomposing-affine-transforms.html From eaee9b387273e1fef7185551d57a8c315e4ac795 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 8 Jan 2018 16:41:51 -0800 Subject: [PATCH 020/272] constants, pre-PR tweaks --- libraries/fbx/src/OBJReader.cpp | 33 +++++++++++++++++++-------------- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index a248f6fb68..e5d4fb7bd4 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -35,6 +35,11 @@ QHash COMMENT_SCALE_HINTS = {{"This file uses centimeters as uni const QString SMART_DEFAULT_MATERIAL_NAME = "High Fidelity smart default material name"; +const float ILLUMINATION_MODEL_MIN_OPACITY = 0.1f; +const float ILLUMINATION_MODEL_APPLY_SHININESS = 0.25f; +const float ILLUMINATION_MODEL_APPLY_ROUGHNESS = 1.0f; +const float ILLUMINATION_MODEL_APPLY_NON_METALLIC = 0.0f; + namespace { template T& checked_at(QVector& vector, int i) { @@ -380,7 +385,7 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file // and https://wikivisually.com/wiki/Material_Template_Library QString parser = textureLine; while (parser.length() > 0) { - if (parser.startsWith("-blendu") || parser.startsWith("-blendv")) { + if (parser.startsWith("-blend")) { // -blendu/-blendv parser.remove(0, 11); // remove through "-blendu on " or "-blendu off" if (parser[0] == ' ') { // extra character for space after off parser.remove(0, 1); @@ -421,18 +426,18 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file #endif } else if (parser.startsWith("-mm")) { parser.remove(0, 4); // remove through "-mm " - float ignore; - parseTextureLineFloat(parser, ignore); + float ignore, ignore2; parseTextureLineFloat(parser, ignore); + parseTextureLineFloat(parser, ignore2); #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -mm"; #endif - } else if (parser.startsWith("-o") || parser.startsWith("-s") || parser.startsWith("-t")) { - parser.remove(0, 3); // remove through "-o " - float ignore; - parseTextureLineFloat(parser, ignore); - parseTextureLineFloat(parser, ignore); + } else if (parser.startsWith("-o ") || parser.startsWith("-s ") || parser.startsWith("-t ")) { + parser.remove(0, 3); // remove through "-o/-s/-t " + float ignore, ignore2, ignore3; parseTextureLineFloat(parser, ignore); + bool hasValue2 = parseTextureLineFloat(parser, ignore2); + bool hasValue3 = parseTextureLineFloat(parser, ignore3); #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -o/-s/-t"; #endif @@ -944,7 +949,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // We don't support ambient - do nothing? break; case 2: // Highlight on - fbxMaterial.specularFactor = 1.0f; + // Change specular intensity? break; case 3: // Reflection on and Ray trace on applyShininess = true; @@ -982,16 +987,16 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, break; } - if (applyTransparency && fbxMaterial.opacity <= 0.1f) { - fbxMaterial.opacity = 0.1f; + if (applyTransparency && fbxMaterial.opacity <= ILLUMINATION_MODEL_MIN_OPACITY) { + fbxMaterial.opacity = ILLUMINATION_MODEL_MIN_OPACITY; } if (applyShininess) { - modelMaterial->setRoughness(0.25f); + modelMaterial->setRoughness(ILLUMINATION_MODEL_APPLY_SHININESS); } else if (applyRoughness) { - modelMaterial->setRoughness(1.0f); + modelMaterial->setRoughness(ILLUMINATION_MODEL_APPLY_ROUGHNESS); } if (applyNonMetallic) { - modelMaterial->setMetallic(0.0f); + modelMaterial->setMetallic(ILLUMINATION_MODEL_APPLY_NON_METALLIC); } if (fresnelOn) { modelMaterial->setFresnel(glm::vec3(1.0f)); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index a4582d6ef4..44382e3603 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -71,7 +71,7 @@ public: int illuminationModel; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), illuminationModel(0) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f), emissiveColor(0.0f), illuminationModel(-1) {} }; class OBJReader: public QObject { // QObject so we can make network requests. From 8aa0525f4536b965a6b3bd1586291ca38df164a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Jan 2018 10:32:28 -0800 Subject: [PATCH 021/272] 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 022/272] 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 0145b770da39868ab0209a7cbed7aabbbf0d5ec3 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 11 Jan 2018 17:16:22 -0800 Subject: [PATCH 023/272] fix warnings --- libraries/fbx/src/OBJReader.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index e5d4fb7bd4..008b51b0be 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -291,9 +291,10 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "Ns") { currentMaterial.shininess = tokenizer.getFloat(); } else if (token == "Ni") { - float ignore = tokenizer.getFloat(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << ignore; + qCDebug(modelformat) << "OBJ Reader Ignoring material Ni " << tokenizer.getFloat(); + #else + tokenizer.getFloat(); #endif } else if (token == "d") { currentMaterial.opacity = tokenizer.getFloat(); @@ -302,14 +303,16 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if (token == "illum") { currentMaterial.illuminationModel = tokenizer.getFloat(); } else if (token == "Tf") { - glm::vec3 ignore = tokenizer.getVec3(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << ignore; + qCDebug(modelformat) << "OBJ Reader Ignoring material Tf " << tokenizer.getVec3(); + #else + tokenizer.getVec3(); #endif } else if (token == "Ka") { - glm::vec3 ignore = tokenizer.getVec3(); #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << ignore; + qCDebug(modelformat) << "OBJ Reader Ignoring material Ka " << tokenizer.getVec3();; + #else + tokenizer.getVec3(); #endif } else if (token == "Kd") { currentMaterial.diffuseColor = tokenizer.getVec3(); @@ -436,8 +439,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file parser.remove(0, 3); // remove through "-o/-s/-t " float ignore, ignore2, ignore3; parseTextureLineFloat(parser, ignore); - bool hasValue2 = parseTextureLineFloat(parser, ignore2); - bool hasValue3 = parseTextureLineFloat(parser, ignore3); + parseTextureLineFloat(parser, ignore2); + parseTextureLineFloat(parser, ignore3); #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -o/-s/-t"; #endif From 814de4ab81f335d550d09ee42b6d84b0b1dff196 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 12 Jan 2018 11:59:19 +0100 Subject: [PATCH 024/272] Scribe now outputs shaders as cpp files. --- cmake/macros/AutoScribeShader.cmake | 8 +- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 4 +- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../src/RenderablePolyLineEntityItem.cpp | 8 +- .../src/RenderablePolyVoxEntityItem.cpp | 18 +-- .../src/RenderableShapeEntityItem.cpp | 4 +- libraries/gpu/src/gpu/Shader.h | 2 + libraries/gpu/src/gpu/StandardShaderLib.cpp | 24 ++-- libraries/model/src/model/Skybox.cpp | 4 +- .../procedural/src/procedural/Procedural.cpp | 2 +- .../src/procedural/ProceduralSkybox.cpp | 4 +- .../src/AmbientOcclusionEffect.cpp | 10 +- libraries/render-utils/src/AnimDebugDraw.cpp | 5 +- .../render-utils/src/AntialiasingEffect.cpp | 6 +- libraries/render-utils/src/BloomEffect.cpp | 4 +- .../render-utils/src/DebugDeferredBuffer.cpp | 4 +- .../src/DeferredLightingEffect.cpp | 18 +-- libraries/render-utils/src/DrawHaze.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 26 ++-- .../render-utils/src/HighlightEffect.cpp | 20 +-- libraries/render-utils/src/LightClusters.cpp | 12 +- .../render-utils/src/RenderForwardTask.cpp | 2 +- .../render-utils/src/RenderPipelines.cpp | 132 +++++++++--------- .../render-utils/src/StencilMaskPass.cpp | 2 +- .../render-utils/src/SubsurfaceScattering.cpp | 8 +- .../render-utils/src/SurfaceGeometryPass.cpp | 6 +- libraries/render-utils/src/TextRenderer3D.cpp | 4 +- .../render-utils/src/ToneMappingEffect.cpp | 2 +- libraries/render-utils/src/ZoneRenderer.cpp | 6 +- libraries/render-utils/src/text/Font.cpp | 6 +- libraries/render/src/render/BlurTask.cpp | 8 +- .../render/src/render/DrawSceneOctree.cpp | 10 +- libraries/render/src/render/DrawStatus.cpp | 8 +- libraries/render/src/render/DrawTask.cpp | 4 +- .../render/src/render/drawItemBounds.slf | 1 - tests/shaders/src/main.cpp | 94 ++++++------- tools/scribe/src/main.cpp | 8 +- 37 files changed, 245 insertions(+), 245 deletions(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 1919ecf00a..d25e0e553f 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -39,11 +39,11 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE) get_filename_component(SHADER_EXT ${SHADER_FILE} EXT) if(SHADER_EXT STREQUAL .slv) - set(SHADER_TARGET ${SHADER_TARGET}_vert.h) + set(SHADER_TARGET ${SHADER_TARGET}_vert.cpp) elseif(${SHADER_EXT} STREQUAL .slf) - set(SHADER_TARGET ${SHADER_TARGET}_frag.h) + set(SHADER_TARGET ${SHADER_TARGET}_frag.cpp) elseif(${SHADER_EXT} STREQUAL .slg) - set(SHADER_TARGET ${SHADER_TARGET}_geom.h) + set(SHADER_TARGET ${SHADER_TARGET}_geom.cpp) endif() set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}") @@ -134,6 +134,6 @@ macro(AUTOSCRIBE_SHADER_LIB) list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC}) # Link library shaders, if they exist - include_directories("${SHADERS_DIR}") + #include_directories("${SHADERS_DIR}") endmacro() diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 1d7fee38eb..4f50b5ecd9 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -33,8 +33,8 @@ #include "../Logging.h" #include "../CompositorHelper.h" -#include "render-utils/hmd_ui_vert.h" -#include "render-utils/hmd_ui_frag.h" +INCLUDE_SHADER(hmd_ui_vert) +INCLUDE_SHADER(hmd_ui_frag) static const QString MONO_PREVIEW = "Mono Preview"; static const QString DISABLE_PREVIEW = "Disable Preview"; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a3e6cd4341..b8f979b7fd 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -14,8 +14,8 @@ #include -#include "textured_particle_vert.h" -#include "textured_particle_frag.h" +INCLUDE_SHADER(textured_particle_vert) +INCLUDE_SHADER(textured_particle_frag) using namespace render; using namespace render::entities; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index b362721cde..b85771f5b6 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -23,11 +23,11 @@ # include #endif -#include "paintStroke_vert.h" -#include "paintStroke_frag.h" +INCLUDE_SHADER(paintStroke_vert) +INCLUDE_SHADER(paintStroke_frag) -#include "paintStroke_fade_vert.h" -#include "paintStroke_fade_frag.h" +INCLUDE_SHADER(paintStroke_fade_vert) +INCLUDE_SHADER(paintStroke_fade_frag) using namespace render; using namespace render::entities; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index ad0202457e..b245ed7cda 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -27,10 +27,11 @@ #include #include "EntityTreeRenderer.h" -#include "polyvox_vert.h" -#include "polyvox_frag.h" -#include "polyvox_fade_vert.h" -#include "polyvox_fade_frag.h" + +INCLUDE_SHADER(polyvox_vert) +INCLUDE_SHADER(polyvox_frag) +INCLUDE_SHADER(polyvox_fade_vert) +INCLUDE_SHADER(polyvox_fade_frag) #ifdef POLYVOX_ENTITY_USE_FADE_EFFECT # include @@ -70,10 +71,11 @@ #include "StencilMaskPass.h" #include "EntityTreeRenderer.h" -#include "polyvox_vert.h" -#include "polyvox_frag.h" -#include "polyvox_fade_vert.h" -#include "polyvox_fade_frag.h" + +INCLUDE_SHADER(polyvox_vert) +INCLUDE_SHADER(polyvox_frag) +INCLUDE_SHADER(polyvox_fade_vert) +INCLUDE_SHADER(polyvox_fade_frag) #include "RenderablePolyVoxEntityItem.h" #include "EntityEditPacketSender.h" diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index cdee2c5ec9..cd02186440 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -16,8 +16,8 @@ #include #include -#include -#include +INCLUDE_SHADER(simple_vert) +INCLUDE_SHADER(simple_frag) //#define SHAPE_ENTITY_USE_FADE_EFFECT #ifdef SHAPE_ENTITY_USE_FADE_EFFECT diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 181c9b5e78..5cfdbc8bf4 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -17,6 +17,8 @@ #include #include + +#define INCLUDE_SHADER(source) extern const char source[]; namespace gpu { diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 0d8d131e0b..93c2228de6 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -12,21 +12,21 @@ // #include "StandardShaderLib.h" -#include "DrawUnitQuadTexcoord_vert.h" -#include "DrawTransformUnitQuad_vert.h" -#include "DrawTexcoordRectTransformUnitQuad_vert.h" -#include "DrawViewportQuadTransformTexcoord_vert.h" -#include "DrawVertexPosition_vert.h" -#include "DrawTransformVertexPosition_vert.h" +INCLUDE_SHADER(DrawUnitQuadTexcoord_vert) +INCLUDE_SHADER(DrawTransformUnitQuad_vert) +INCLUDE_SHADER(DrawTexcoordRectTransformUnitQuad_vert) +INCLUDE_SHADER(DrawViewportQuadTransformTexcoord_vert) +INCLUDE_SHADER(DrawVertexPosition_vert) +INCLUDE_SHADER(DrawTransformVertexPosition_vert) const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple... -#include "DrawWhite_frag.h" -#include "DrawColor_frag.h" -#include "DrawTexture_frag.h" -#include "DrawTextureMirroredX_frag.h" -#include "DrawTextureOpaque_frag.h" -#include "DrawColoredTexture_frag.h" +INCLUDE_SHADER(DrawWhite_frag) +INCLUDE_SHADER(DrawColor_frag) +INCLUDE_SHADER(DrawTexture_frag) +INCLUDE_SHADER(DrawTextureMirroredX_frag) +INCLUDE_SHADER(DrawTextureOpaque_frag) +INCLUDE_SHADER(DrawColoredTexture_frag) using namespace gpu; diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index fd3061afa5..7e03890c85 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -15,8 +15,8 @@ #include #include -#include "skybox_vert.h" -#include "skybox_frag.h" +INCLUDE_SHADER(skybox_vert) +INCLUDE_SHADER(skybox_frag) using namespace model; diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 7b718515a8..c0ebdbb186 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -20,7 +20,7 @@ #include #include -#include "ProceduralCommon_frag.h" +INCLUDE_SHADER(ProceduralCommon_frag) #include "Logging.h" diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 9544759037..452d3f639a 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -15,8 +15,8 @@ #include #include -#include -#include +INCLUDE_SHADER(skybox_vert) +INCLUDE_SHADER(skybox_frag) ProceduralSkybox::ProceduralSkybox() : model::Skybox() { _procedural._vertexSource = skybox_vert; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 83753131c8..f5b4f0f6bb 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -28,11 +28,11 @@ #include "DependencyManager.h" #include "ViewFrustum.h" -#include "ssao_makePyramid_frag.h" -#include "ssao_makeOcclusion_frag.h" -#include "ssao_debugOcclusion_frag.h" -#include "ssao_makeHorizontalBlur_frag.h" -#include "ssao_makeVerticalBlur_frag.h" +INCLUDE_SHADER(ssao_makePyramid_frag) +INCLUDE_SHADER(ssao_makeOcclusion_frag) +INCLUDE_SHADER(ssao_debugOcclusion_frag) +INCLUDE_SHADER(ssao_makeHorizontalBlur_frag) +INCLUDE_SHADER(ssao_makeVerticalBlur_frag) AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index c22e99cbbc..53ed3ea9a0 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -9,8 +9,6 @@ #include -#include "animdebugdraw_vert.h" -#include "animdebugdraw_frag.h" #include #include "AbstractViewStateInterface.h" #include "RenderUtilsLogging.h" @@ -19,6 +17,9 @@ #include "AnimDebugDraw.h" +INCLUDE_SHADER(animdebugdraw_vert) +INCLUDE_SHADER(animdebugdraw_frag) + class AnimDebugDrawData { public: diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 70c2e3b5ce..078e906fad 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -23,9 +23,9 @@ #include "ViewFrustum.h" #include "GeometryCache.h" -#include "fxaa_vert.h" -#include "fxaa_frag.h" -#include "fxaa_blend_frag.h" +INCLUDE_SHADER(fxaa_vert) +INCLUDE_SHADER(fxaa_frag) +INCLUDE_SHADER(fxaa_blend_frag) Antialiasing::Antialiasing() { diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 9d9367a6d5..ace347f99e 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -16,8 +16,8 @@ #include #include -#include "BloomThreshold_frag.h" -#include "BloomApply_frag.h" +INCLUDE_SHADER(BloomThreshold_frag) +INCLUDE_SHADER(BloomApply_frag) #define BLOOM_BLUR_LEVEL_COUNT 3 diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index fe03ead4e1..05cd6a6f0e 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -23,8 +23,8 @@ #include "TextureCache.h" #include "DeferredLightingEffect.h" -#include "debug_deferred_buffer_vert.h" -#include "debug_deferred_buffer_frag.h" +INCLUDE_SHADER(debug_deferred_buffer_vert) +INCLUDE_SHADER(debug_deferred_buffer_frag) using namespace render; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 81a33f17e3..8ec2c74353 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -24,18 +24,18 @@ #include "TextureCache.h" #include "FramebufferCache.h" -#include "deferred_light_vert.h" -#include "deferred_light_point_vert.h" -#include "deferred_light_spot_vert.h" +INCLUDE_SHADER(deferred_light_vert) +INCLUDE_SHADER(deferred_light_point_vert) +INCLUDE_SHADER(deferred_light_spot_vert) -#include "directional_ambient_light_frag.h" -#include "directional_skybox_light_frag.h" +INCLUDE_SHADER(directional_ambient_light_frag) +INCLUDE_SHADER(directional_skybox_light_frag) -#include "directional_ambient_light_shadow_frag.h" -#include "directional_skybox_light_shadow_frag.h" +INCLUDE_SHADER(directional_ambient_light_shadow_frag) +INCLUDE_SHADER(directional_skybox_light_shadow_frag) -#include "local_lights_shading_frag.h" -#include "local_lights_drawOutline_frag.h" +INCLUDE_SHADER(local_lights_shading_frag) +INCLUDE_SHADER(local_lights_drawOutline_frag) using namespace render; diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index da07f5bd9b..dc1893b347 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -19,7 +19,7 @@ #include "HazeStage.h" #include "LightStage.h" -#include "Haze_frag.h" +INCLUDE_SHADER(Haze_frag) void HazeConfig::setHazeColor(const glm::vec3 value) { hazeColor = value; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2616d08600..ac8b300e49 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -34,21 +34,21 @@ #include "model/TextureMap.h" #include "render/Args.h" -#include "standardTransformPNTC_vert.h" -#include "standardDrawTexture_frag.h" +INCLUDE_SHADER(standardTransformPNTC_vert) +INCLUDE_SHADER(standardDrawTexture_frag) -#include "simple_vert.h" -#include "simple_textured_frag.h" -#include "simple_textured_unlit_frag.h" -#include "simple_fade_vert.h" -#include "simple_textured_fade_frag.h" -#include "simple_textured_unlit_fade_frag.h" -#include "simple_opaque_web_browser_frag.h" -#include "simple_transparent_web_browser_frag.h" -#include "glowLine_vert.h" -#include "glowLine_frag.h" +INCLUDE_SHADER(simple_vert) +INCLUDE_SHADER(simple_textured_frag) +INCLUDE_SHADER(simple_textured_unlit_frag) +INCLUDE_SHADER(simple_fade_vert) +INCLUDE_SHADER(simple_textured_fade_frag) +INCLUDE_SHADER(simple_textured_unlit_fade_frag) +INCLUDE_SHADER(simple_opaque_web_browser_frag) +INCLUDE_SHADER(simple_transparent_web_browser_frag) +INCLUDE_SHADER(glowLine_vert) +INCLUDE_SHADER(glowLine_frag) -#include "grid_frag.h" +INCLUDE_SHADER(grid_frag) //#define WANT_DEBUG diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index fee1f4a568..69feffb055 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -22,13 +22,13 @@ #include -#include "surfaceGeometry_copyDepth_frag.h" -#include "debug_deferred_buffer_vert.h" -#include "debug_deferred_buffer_frag.h" -#include "Highlight_frag.h" -#include "Highlight_filled_frag.h" -#include "Highlight_aabox_vert.h" -#include "nop_frag.h" +INCLUDE_SHADER(surfaceGeometry_copyDepth_frag) +INCLUDE_SHADER(debug_deferred_buffer_vert) +INCLUDE_SHADER(debug_deferred_buffer_frag) +INCLUDE_SHADER(Highlight_frag) +INCLUDE_SHADER(Highlight_filled_frag) +INCLUDE_SHADER(Highlight_aabox_vert) +INCLUDE_SHADER(nop_frag) using namespace render; @@ -547,10 +547,10 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const return task.addJob("TransparentSelection", selectItemInput); } -#include "model_shadow_vert.h" -#include "skin_model_shadow_vert.h" +INCLUDE_SHADER(model_shadow_vert) +INCLUDE_SHADER(skin_model_shadow_vert) -#include "model_shadow_frag.h" +INCLUDE_SHADER(model_shadow_frag) void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index d6ac7fd2e2..79d755683f 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -18,15 +18,15 @@ #include "StencilMaskPass.h" -#include "lightClusters_drawGrid_vert.h" -#include "lightClusters_drawGrid_frag.h" +INCLUDE_SHADER(lightClusters_drawGrid_vert) +INCLUDE_SHADER(lightClusters_drawGrid_frag) -//#include "lightClusters_drawClusterFromDepth_vert.h" -#include "lightClusters_drawClusterFromDepth_frag.h" +//INCLUDE_SHADER(lightClusters_drawClusterFromDepth_vert) +INCLUDE_SHADER(lightClusters_drawClusterFromDepth_frag) -#include "lightClusters_drawClusterContent_vert.h" -#include "lightClusters_drawClusterContent_frag.h" +INCLUDE_SHADER(lightClusters_drawClusterContent_vert) +INCLUDE_SHADER(lightClusters_drawClusterContent_frag) enum LightClusterGridShader_MapSlot { DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0, diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index c83251c605..8d02281d05 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -24,7 +24,7 @@ #include -#include "nop_frag.h" +INCLUDE_SHADER(nop_frag) using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 7f644add72..62252d3a0b 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -20,86 +20,86 @@ #include "TextureCache.h" #include "render/DrawTask.h" -#include "model_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_normal_map_vert.h" +INCLUDE_SHADER(model_vert) +INCLUDE_SHADER(model_normal_map_vert) +INCLUDE_SHADER(model_lightmap_vert) +INCLUDE_SHADER(model_lightmap_normal_map_vert) +INCLUDE_SHADER(skin_model_vert) +INCLUDE_SHADER(skin_model_normal_map_vert) -#include "model_lightmap_fade_vert.h" -#include "model_lightmap_normal_map_fade_vert.h" -#include "skin_model_fade_vert.h" -#include "skin_model_normal_map_fade_vert.h" +INCLUDE_SHADER(model_lightmap_fade_vert) +INCLUDE_SHADER(model_lightmap_normal_map_fade_vert) +INCLUDE_SHADER(skin_model_fade_vert) +INCLUDE_SHADER(skin_model_normal_map_fade_vert) -#include "simple_vert.h" -#include "simple_textured_frag.h" -#include "simple_textured_unlit_frag.h" -#include "simple_transparent_textured_frag.h" -#include "simple_transparent_textured_unlit_frag.h" +INCLUDE_SHADER(simple_vert) +INCLUDE_SHADER(simple_textured_frag) +INCLUDE_SHADER(simple_textured_unlit_frag) +INCLUDE_SHADER(simple_transparent_textured_frag) +INCLUDE_SHADER(simple_transparent_textured_unlit_frag) -#include "simple_fade_vert.h" -#include "simple_textured_fade_frag.h" -#include "simple_textured_unlit_fade_frag.h" -#include "simple_transparent_textured_fade_frag.h" -#include "simple_transparent_textured_unlit_fade_frag.h" +INCLUDE_SHADER(simple_fade_vert) +INCLUDE_SHADER(simple_textured_fade_frag) +INCLUDE_SHADER(simple_textured_unlit_fade_frag) +INCLUDE_SHADER(simple_transparent_textured_fade_frag) +INCLUDE_SHADER(simple_transparent_textured_unlit_fade_frag) -#include "model_frag.h" -#include "model_unlit_frag.h" -#include "model_normal_map_frag.h" -#include "model_normal_specular_map_frag.h" -#include "model_specular_map_frag.h" +INCLUDE_SHADER(model_frag) +INCLUDE_SHADER(model_unlit_frag) +INCLUDE_SHADER(model_normal_map_frag) +INCLUDE_SHADER(model_normal_specular_map_frag) +INCLUDE_SHADER(model_specular_map_frag) -#include "model_fade_vert.h" -#include "model_normal_map_fade_vert.h" +INCLUDE_SHADER(model_fade_vert) +INCLUDE_SHADER(model_normal_map_fade_vert) -#include "model_fade_frag.h" -#include "model_unlit_fade_frag.h" -#include "model_normal_map_fade_frag.h" -#include "model_normal_specular_map_fade_frag.h" -#include "model_specular_map_fade_frag.h" +INCLUDE_SHADER(model_fade_frag) +INCLUDE_SHADER(model_unlit_fade_frag) +INCLUDE_SHADER(model_normal_map_fade_frag) +INCLUDE_SHADER(model_normal_specular_map_fade_frag) +INCLUDE_SHADER(model_specular_map_fade_frag) -#include "forward_model_frag.h" -#include "forward_model_unlit_frag.h" -#include "forward_model_normal_map_frag.h" -#include "forward_model_normal_specular_map_frag.h" -#include "forward_model_specular_map_frag.h" +INCLUDE_SHADER(forward_model_frag) +INCLUDE_SHADER(forward_model_unlit_frag) +INCLUDE_SHADER(forward_model_normal_map_frag) +INCLUDE_SHADER(forward_model_normal_specular_map_frag) +INCLUDE_SHADER(forward_model_specular_map_frag) -#include "model_lightmap_frag.h" -#include "model_lightmap_normal_map_frag.h" -#include "model_lightmap_normal_specular_map_frag.h" -#include "model_lightmap_specular_map_frag.h" -#include "model_translucent_frag.h" -#include "model_translucent_unlit_frag.h" +INCLUDE_SHADER(model_lightmap_frag) +INCLUDE_SHADER(model_lightmap_normal_map_frag) +INCLUDE_SHADER(model_lightmap_normal_specular_map_frag) +INCLUDE_SHADER(model_lightmap_specular_map_frag) +INCLUDE_SHADER(model_translucent_frag) +INCLUDE_SHADER(model_translucent_unlit_frag) -#include "model_lightmap_fade_frag.h" -#include "model_lightmap_normal_map_fade_frag.h" -#include "model_lightmap_normal_specular_map_fade_frag.h" -#include "model_lightmap_specular_map_fade_frag.h" -#include "model_translucent_fade_frag.h" -#include "model_translucent_unlit_fade_frag.h" +INCLUDE_SHADER(model_lightmap_fade_frag) +INCLUDE_SHADER(model_lightmap_normal_map_fade_frag) +INCLUDE_SHADER(model_lightmap_normal_specular_map_fade_frag) +INCLUDE_SHADER(model_lightmap_specular_map_fade_frag) +INCLUDE_SHADER(model_translucent_fade_frag) +INCLUDE_SHADER(model_translucent_unlit_fade_frag) -#include "overlay3D_vert.h" -#include "overlay3D_frag.h" -#include "overlay3D_model_frag.h" -#include "overlay3D_model_translucent_frag.h" -#include "overlay3D_translucent_frag.h" -#include "overlay3D_unlit_frag.h" -#include "overlay3D_translucent_unlit_frag.h" -#include "overlay3D_model_unlit_frag.h" -#include "overlay3D_model_translucent_unlit_frag.h" +INCLUDE_SHADER(overlay3D_vert) +INCLUDE_SHADER(overlay3D_frag) +INCLUDE_SHADER(overlay3D_model_frag) +INCLUDE_SHADER(overlay3D_model_translucent_frag) +INCLUDE_SHADER(overlay3D_translucent_frag) +INCLUDE_SHADER(overlay3D_unlit_frag) +INCLUDE_SHADER(overlay3D_translucent_unlit_frag) +INCLUDE_SHADER(overlay3D_model_unlit_frag) +INCLUDE_SHADER(overlay3D_model_translucent_unlit_frag) -#include "model_shadow_vert.h" -#include "skin_model_shadow_vert.h" +INCLUDE_SHADER(model_shadow_vert) +INCLUDE_SHADER(skin_model_shadow_vert) -#include "model_shadow_frag.h" -#include "skin_model_shadow_frag.h" +INCLUDE_SHADER(model_shadow_frag) +INCLUDE_SHADER(skin_model_shadow_frag) -#include "model_shadow_fade_vert.h" -#include "skin_model_shadow_fade_vert.h" +INCLUDE_SHADER(model_shadow_fade_vert) +INCLUDE_SHADER(skin_model_shadow_fade_vert) -#include "model_shadow_fade_frag.h" -#include "skin_model_shadow_fade_frag.h" +INCLUDE_SHADER(model_shadow_fade_frag) +INCLUDE_SHADER(skin_model_shadow_fade_frag) using namespace render; using namespace std::placeholders; diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index f71111b64e..e2a8b31f08 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -17,7 +17,7 @@ #include -#include "stencil_drawMask_frag.h" +INCLUDE_SHADER(stencil_drawMask_frag) using namespace render; diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 1786898e57..e8d7e23ec2 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -17,11 +17,11 @@ #include "DeferredLightingEffect.h" -#include "subsurfaceScattering_makeProfile_frag.h" -#include "subsurfaceScattering_makeLUT_frag.h" -#include "subsurfaceScattering_makeSpecularBeckmann_frag.h" +INCLUDE_SHADER(subsurfaceScattering_makeProfile_frag) +INCLUDE_SHADER(subsurfaceScattering_makeLUT_frag) +INCLUDE_SHADER(subsurfaceScattering_makeSpecularBeckmann_frag) -#include "subsurfaceScattering_drawScattering_frag.h" +INCLUDE_SHADER(subsurfaceScattering_drawScattering_frag) enum ScatteringShaderBufferSlots { ScatteringTask_FrameTransformSlot = 0, diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index c4eea7ce7f..6ad8dc6137 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -25,10 +25,10 @@ const int SurfaceGeometryPass_ParamsSlot = 1; const int SurfaceGeometryPass_DepthMapSlot = 0; const int SurfaceGeometryPass_NormalMapSlot = 1; -#include "surfaceGeometry_makeLinearDepth_frag.h" -#include "surfaceGeometry_downsampleDepthNormal_frag.h" +INCLUDE_SHADER(surfaceGeometry_makeLinearDepth_frag) +INCLUDE_SHADER(surfaceGeometry_downsampleDepthNormal_frag) -#include "surfaceGeometry_makeCurvature_frag.h" +INCLUDE_SHADER(surfaceGeometry_makeCurvature_frag) diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 9c85952107..06e041685a 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -25,8 +25,8 @@ #include "MatrixStack.h" #include "RenderUtilsLogging.h" -#include "sdf_text3D_vert.h" -#include "sdf_text3D_frag.h" +INCLUDE_SHADER(sdf_text3D_vert) +INCLUDE_SHADER(sdf_text3D_frag) #include "GeometryCache.h" diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 72d692c5b2..3d3a11f7b3 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -17,7 +17,7 @@ #include "StencilMaskPass.h" #include "FramebufferCache.h" -#include "toneMapping_frag.h" +INCLUDE_SHADER(toneMapping_frag) const int ToneMappingEffect_ParamsSlot = 0; const int ToneMappingEffect_LightingMapSlot = 0; diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index c0d01c2eaf..77b5c492d3 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -20,9 +20,9 @@ #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" -#include "zone_drawKeyLight_frag.h" -#include "zone_drawAmbient_frag.h" -#include "zone_drawSkybox_frag.h" +INCLUDE_SHADER(zone_drawKeyLight_frag) +INCLUDE_SHADER(zone_drawAmbient_frag) +INCLUDE_SHADER(zone_drawSkybox_frag) using namespace render; diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 8449c58c7c..9e0fbd1522 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -7,9 +7,9 @@ #include -#include "sdf_text3D_vert.h" -#include "sdf_text3D_frag.h" -#include "sdf_text3D_transparent_frag.h" +INCLUDE_SHADER(sdf_text3D_vert) +INCLUDE_SHADER(sdf_text3D_frag) +INCLUDE_SHADER(sdf_text3D_transparent_frag) #include "../RenderUtilsLogging.h" #include "FontFamilies.h" diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 2be6f8fad2..4b5d6da8e3 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -13,11 +13,11 @@ #include #include -#include "blurGaussianV_frag.h" -#include "blurGaussianH_frag.h" +INCLUDE_SHADER(blurGaussianV_frag) +INCLUDE_SHADER(blurGaussianH_frag) -#include "blurGaussianDepthAwareV_frag.h" -#include "blurGaussianDepthAwareH_frag.h" +INCLUDE_SHADER(blurGaussianDepthAwareV_frag) +INCLUDE_SHADER(blurGaussianDepthAwareH_frag) using namespace render; diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 36663a454a..7823d85dae 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -22,12 +22,12 @@ #include "Args.h" -#include "drawCellBounds_vert.h" -#include "drawCellBounds_frag.h" -#include "drawLODReticle_frag.h" +INCLUDE_SHADER(drawCellBounds_vert) +INCLUDE_SHADER(drawCellBounds_frag) +INCLUDE_SHADER(drawLODReticle_frag) -#include "drawItemBounds_vert.h" -#include "drawItemBounds_frag.h" +INCLUDE_SHADER(drawItemBounds_vert) +INCLUDE_SHADER(drawItemBounds_frag) using namespace render; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 148e104453..1c6d7749f8 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -21,10 +21,10 @@ #include "Args.h" -#include "drawItemBounds_vert.h" -#include "drawItemBounds_frag.h" -#include "drawItemStatus_vert.h" -#include "drawItemStatus_frag.h" +INCLUDE_SHADER(drawItemBounds_vert) +INCLUDE_SHADER(drawItemBounds_frag) +INCLUDE_SHADER(drawItemStatus_vert) +INCLUDE_SHADER(drawItemStatus_frag) using namespace render; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 629cc55ccb..a6d5072cca 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -22,8 +22,8 @@ #include #include -#include -#include +INCLUDE_SHADER(drawItemBounds_vert) +INCLUDE_SHADER(drawItemBounds_frag) using namespace render; diff --git a/libraries/render/src/render/drawItemBounds.slf b/libraries/render/src/render/drawItemBounds.slf index e01d1607bd..84c47d0933 100644 --- a/libraries/render/src/render/drawItemBounds.slf +++ b/libraries/render/src/render/drawItemBounds.slf @@ -15,7 +15,6 @@ in vec4 varColor; in vec2 varTexcoord; out vec4 outFragColor; - void main(void) { float var = step(fract(varTexcoord.x * varTexcoord.y * 1.0), 0.5); diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 7c6886ad93..e0babc8b47 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -23,65 +23,65 @@ #include -#include -#include -#include -#include +INCLUDE_SHADER(simple_vert) +INCLUDE_SHADER(simple_frag) +INCLUDE_SHADER(simple_textured_frag) +INCLUDE_SHADER(simple_textured_unlit_frag) -#include -#include -#include +INCLUDE_SHADER(deferred_light_vert) +INCLUDE_SHADER(deferred_light_point_vert) +INCLUDE_SHADER(deferred_light_spot_vert) -#include -#include +INCLUDE_SHADER(directional_ambient_light_frag) +INCLUDE_SHADER(directional_skybox_light_frag) -#include -#include +INCLUDE_SHADER(standardTransformPNTC_vert) +INCLUDE_SHADER(standardDrawTexture_frag) -#include -#include -#include -#include -#include -#include -#include -#include +INCLUDE_SHADER(model_vert) +INCLUDE_SHADER(model_shadow_vert) +INCLUDE_SHADER(model_normal_map_vert) +INCLUDE_SHADER(model_lightmap_vert) +INCLUDE_SHADER(model_lightmap_normal_map_vert) +INCLUDE_SHADER(skin_model_vert) +INCLUDE_SHADER(skin_model_shadow_vert) +INCLUDE_SHADER(skin_model_normal_map_vert) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +INCLUDE_SHADER(model_frag) +INCLUDE_SHADER(model_shadow_frag) +INCLUDE_SHADER(model_normal_map_frag) +INCLUDE_SHADER(model_normal_specular_map_frag) +INCLUDE_SHADER(model_specular_map_frag) +INCLUDE_SHADER(model_lightmap_frag) +INCLUDE_SHADER(model_lightmap_normal_map_frag) +INCLUDE_SHADER(model_lightmap_normal_specular_map_frag) +INCLUDE_SHADER(model_lightmap_specular_map_frag) +INCLUDE_SHADER(model_translucent_frag) -#include -#include +INCLUDE_SHADER(textured_particle_frag) +INCLUDE_SHADER(textured_particle_vert) -#include -#include +INCLUDE_SHADER(overlay3D_vert) +INCLUDE_SHADER(overlay3D_frag) -#include -#include +INCLUDE_SHADER(skybox_vert) +INCLUDE_SHADER(skybox_frag) -#include -#include -#include -#include -#include -#include +INCLUDE_SHADER(DrawTransformUnitQuad_vert) +INCLUDE_SHADER(DrawTexcoordRectTransformUnitQuad_vert) +INCLUDE_SHADER(DrawViewportQuadTransformTexcoord_vert) +INCLUDE_SHADER(DrawTexture_frag) +INCLUDE_SHADER(DrawTextureOpaque_frag) +INCLUDE_SHADER(DrawColoredTexture_frag) -#include -#include +INCLUDE_SHADER(sdf_text3D_vert) +INCLUDE_SHADER(sdf_text3D_frag) -#include -#include +INCLUDE_SHADER(paintStroke_vert) +INCLUDE_SHADER(paintStroke_frag) -#include -#include +INCLUDE_SHADER(polyvox_vert) +INCLUDE_SHADER(polyvox_frag) // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index 810f6c0f45..fef2ea0308 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -123,7 +123,7 @@ int main (int argc, char** argv) { cerr << " varname and varvalue must be made of alpha numerical characters with no spaces." << endl; cerr << " -listVars : Will list the vars name and value in the standard output." << endl; cerr << " -showParseTree : Draw the tree obtained while parsing the source" << endl; - cerr << " -c++ : Generate a c++ header file containing the output file stream stored as a char[] variable" << endl; + cerr << " -c++ : Generate a c++ source file containing the output file stream stored as a char[] variable" << endl; return 0; } @@ -209,9 +209,7 @@ int main (int argc, char** argv) { } targetStringStream << "// File generated by Scribe " << vars["_SCRIBE_DATE"] << std::endl; - targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl; - targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl; - + targetStringStream << "extern const char " << targetName << "[];\n"; targetStringStream << "const char " << targetName << "[] = \n"; // Write the pages content @@ -219,8 +217,6 @@ int main (int argc, char** argv) { targetStringStream << "R\"SCRIBE(\n" << page->str() << "\n)SCRIBE\"\n"; } targetStringStream << ";\n" << std::endl << std::endl; - - targetStringStream << "#endif" << std::endl; } else { targetStringStream << destStringStream.str(); } From 420b58fd5b031bac28f11e281e006cd6d891f113 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 12 Jan 2018 15:13:55 +0100 Subject: [PATCH 025/272] Trying to fix Android build error --- tools/scribe/src/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index fef2ea0308..b95d1df6ec 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -209,8 +209,7 @@ int main (int argc, char** argv) { } targetStringStream << "// File generated by Scribe " << vars["_SCRIBE_DATE"] << std::endl; - targetStringStream << "extern const char " << targetName << "[];\n"; - targetStringStream << "const char " << targetName << "[] = \n"; + targetStringStream << "extern const char " << targetName << "[] = \n"; // Write the pages content for (auto page : pages) { From 98a47e56fc447f9ad3ad2fd1057ed1ee218ac146 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 12 Jan 2018 17:32:12 +0100 Subject: [PATCH 026/272] Added a hack to force referencing of shader source on Android --- tools/scribe/src/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index b95d1df6ec..8e6ca31c71 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -127,7 +127,7 @@ int main (int argc, char** argv) { return 0; } - // Define targetName: if none, get destFilenmae, if none get srcFilename + // Define targetName: if none, get destFilename, if none get srcFilename if (targetName.empty()) { if (destFilename.empty()) { targetName = srcFilename; @@ -216,6 +216,8 @@ int main (int argc, char** argv) { targetStringStream << "R\"SCRIBE(\n" << page->str() << "\n)SCRIBE\"\n"; } targetStringStream << ";\n" << std::endl << std::endl; + targetStringStream << "// Hack to fix Android link error by forcing a reference to global variable\n"; + targetStringStream << "class " << targetName << "_used {\npublic:\nstatic const char* get() { return " << targetName << "; }\n};\n" << std::endl; } else { targetStringStream << destStringStream.str(); } From 241849139ffe1c0a28181c7cd32a0d65857379dd Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 15 Jan 2018 10:21:16 -0800 Subject: [PATCH 027/272] 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 3911ce59cc94828ba6c418af947c993d73903632 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Tue, 16 Jan 2018 19:02:12 +0100 Subject: [PATCH 028/272] Scribe now outputs .h and .cpp. Need to change how shader source is referenced in C++ code --- cmake/macros/AutoScribeShader.cmake | 37 ++-- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 4 +- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../src/RenderablePolyLineEntityItem.cpp | 8 +- .../src/RenderablePolyVoxEntityItem.cpp | 16 +- .../src/RenderableShapeEntityItem.cpp | 4 +- libraries/gpu/src/gpu/Shader.h | 2 - libraries/gpu/src/gpu/StandardShaderLib.cpp | 48 ++--- libraries/model/src/model/Skybox.cpp | 8 +- .../procedural/src/procedural/Procedural.cpp | 4 +- .../src/procedural/ProceduralSkybox.cpp | 4 +- .../src/AmbientOcclusionEffect.cpp | 10 +- libraries/render-utils/src/AnimDebugDraw.cpp | 4 +- .../render-utils/src/AntialiasingEffect.cpp | 6 +- libraries/render-utils/src/BloomEffect.cpp | 4 +- .../render-utils/src/DebugDeferredBuffer.cpp | 4 +- .../src/DeferredLightingEffect.cpp | 18 +- libraries/render-utils/src/DrawHaze.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 26 +-- .../render-utils/src/HighlightEffect.cpp | 20 +- libraries/render-utils/src/LightClusters.cpp | 12 +- .../render-utils/src/RenderForwardTask.cpp | 4 +- .../render-utils/src/RenderPipelines.cpp | 132 +++++++------- .../render-utils/src/StencilMaskPass.cpp | 4 +- .../render-utils/src/SubsurfaceScattering.cpp | 8 +- .../render-utils/src/SurfaceGeometryPass.cpp | 12 +- libraries/render-utils/src/TextRenderer3D.cpp | 4 +- .../render-utils/src/ToneMappingEffect.cpp | 4 +- libraries/render-utils/src/ZoneRenderer.cpp | 6 +- libraries/render-utils/src/text/Font.cpp | 6 +- libraries/render/src/render/BlurTask.cpp | 8 +- .../render/src/render/DrawSceneOctree.cpp | 10 +- libraries/render/src/render/DrawStatus.cpp | 8 +- libraries/render/src/render/DrawTask.cpp | 4 +- tests/shaders/src/main.cpp | 172 +++++++++--------- tools/scribe/src/main.cpp | 136 ++++++++++++-- 36 files changed, 433 insertions(+), 330 deletions(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index d25e0e553f..c92f7a3ffe 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -39,24 +39,28 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) get_filename_component(SHADER_TARGET ${SHADER_FILE} NAME_WE) get_filename_component(SHADER_EXT ${SHADER_FILE} EXT) if(SHADER_EXT STREQUAL .slv) - set(SHADER_TARGET ${SHADER_TARGET}_vert.cpp) + set(SHADER_TYPE vert) elseif(${SHADER_EXT} STREQUAL .slf) - set(SHADER_TARGET ${SHADER_TARGET}_frag.cpp) + set(SHADER_TYPE frag) elseif(${SHADER_EXT} STREQUAL .slg) - set(SHADER_TARGET ${SHADER_TARGET}_geom.cpp) + set(SHADER_TYPE geom) endif() + set(SHADER_TARGET ${SHADER_TARGET}_${SHADER_TYPE}) set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_TARGET}") + set(SHADER_TARGET_HEADER ${SHADER_TARGET}.h) + set(SHADER_TARGET_SOURCE ${SHADER_TARGET}.cpp) # Target dependant Custom rule on the SHADER_FILE if (APPLE) set(GLPROFILE MAC_GL) - set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) - add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) + add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (ANDROID) set(GLPROFILE LINUX_GL) - set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) # for an android build, we can't use the scribe that cmake would normally produce as a target, # since it's unrunnable by the cross-compiling build machine @@ -72,23 +76,25 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) ") endif () - add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS}) + add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (UNIX) set(GLPROFILE LINUX_GL) - set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) - add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) + add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) else () set(GLPROFILE PC_GL) - set(SCRIBE_ARGS -c++ -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) - add_custom_command(OUTPUT ${SHADER_TARGET} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) endif() #output the generated file name - set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET} PARENT_SCOPE) + set(AUTOSCRIBE_SHADER_RETURN ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} PARENT_SCOPE) - file(GLOB INCLUDE_FILES ${SHADER_TARGET}) + file(GLOB INCLUDE_FILES ${SHADER_TARGET_HEADER}) endfunction() @@ -134,6 +140,9 @@ macro(AUTOSCRIBE_SHADER_LIB) list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_SRC}) # Link library shaders, if they exist - #include_directories("${SHADERS_DIR}") + include_directories("${SHADERS_DIR}") + + # Add search directory to find gpu/Shader.h + include_directories("${HIFI_LIBRARY_DIR}/gpu/src") endmacro() diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 4f50b5ecd9..f39203c89d 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -33,8 +33,8 @@ #include "../Logging.h" #include "../CompositorHelper.h" -INCLUDE_SHADER(hmd_ui_vert) -INCLUDE_SHADER(hmd_ui_frag) +#include "hmd_ui_vert.h" +#include "hmd_ui_frag.h" static const QString MONO_PREVIEW = "Mono Preview"; static const QString DISABLE_PREVIEW = "Disable Preview"; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index b8f979b7fd..a3e6cd4341 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -14,8 +14,8 @@ #include -INCLUDE_SHADER(textured_particle_vert) -INCLUDE_SHADER(textured_particle_frag) +#include "textured_particle_vert.h" +#include "textured_particle_frag.h" using namespace render; using namespace render::entities; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index b85771f5b6..b362721cde 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -23,11 +23,11 @@ # include #endif -INCLUDE_SHADER(paintStroke_vert) -INCLUDE_SHADER(paintStroke_frag) +#include "paintStroke_vert.h" +#include "paintStroke_frag.h" -INCLUDE_SHADER(paintStroke_fade_vert) -INCLUDE_SHADER(paintStroke_fade_frag) +#include "paintStroke_fade_vert.h" +#include "paintStroke_fade_frag.h" using namespace render; using namespace render::entities; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index b245ed7cda..cf12da86e9 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -28,10 +28,10 @@ #include "EntityTreeRenderer.h" -INCLUDE_SHADER(polyvox_vert) -INCLUDE_SHADER(polyvox_frag) -INCLUDE_SHADER(polyvox_fade_vert) -INCLUDE_SHADER(polyvox_fade_frag) +#include "polyvox_vert.h" +#include "polyvox_frag.h" +#include "polyvox_fade_vert.h" +#include "polyvox_fade_frag.h" #ifdef POLYVOX_ENTITY_USE_FADE_EFFECT # include @@ -72,10 +72,10 @@ INCLUDE_SHADER(polyvox_fade_frag) #include "EntityTreeRenderer.h" -INCLUDE_SHADER(polyvox_vert) -INCLUDE_SHADER(polyvox_frag) -INCLUDE_SHADER(polyvox_fade_vert) -INCLUDE_SHADER(polyvox_fade_frag) +#include "polyvox_vert.h" +#include "polyvox_frag.h" +#include "polyvox_fade_vert.h" +#include "polyvox_fade_frag.h" #include "RenderablePolyVoxEntityItem.h" #include "EntityEditPacketSender.h" diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index cd02186440..eddde317fe 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -16,8 +16,8 @@ #include #include -INCLUDE_SHADER(simple_vert) -INCLUDE_SHADER(simple_frag) +#include "simple_vert.h" +#include "simple_frag.h" //#define SHAPE_ENTITY_USE_FADE_EFFECT #ifdef SHAPE_ENTITY_USE_FADE_EFFECT diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 5cfdbc8bf4..181c9b5e78 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -17,8 +17,6 @@ #include #include - -#define INCLUDE_SHADER(source) extern const char source[]; namespace gpu { diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 93c2228de6..0d829fb21f 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -12,21 +12,21 @@ // #include "StandardShaderLib.h" -INCLUDE_SHADER(DrawUnitQuadTexcoord_vert) -INCLUDE_SHADER(DrawTransformUnitQuad_vert) -INCLUDE_SHADER(DrawTexcoordRectTransformUnitQuad_vert) -INCLUDE_SHADER(DrawViewportQuadTransformTexcoord_vert) -INCLUDE_SHADER(DrawVertexPosition_vert) -INCLUDE_SHADER(DrawTransformVertexPosition_vert) +#include "DrawUnitQuadTexcoord_vert.h" +#include "DrawTransformUnitQuad_vert.h" +#include "DrawTexcoordRectTransformUnitQuad_vert.h" +#include "DrawViewportQuadTransformTexcoord_vert.h" +#include "DrawVertexPosition_vert.h" +#include "DrawTransformVertexPosition_vert.h" const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple... -INCLUDE_SHADER(DrawWhite_frag) -INCLUDE_SHADER(DrawColor_frag) -INCLUDE_SHADER(DrawTexture_frag) -INCLUDE_SHADER(DrawTextureMirroredX_frag) -INCLUDE_SHADER(DrawTextureOpaque_frag) -INCLUDE_SHADER(DrawColoredTexture_frag) +#include "DrawWhite_frag.h" +#include "DrawColor_frag.h" +#include "DrawTexture_frag.h" +#include "DrawTextureMirroredX_frag.h" +#include "DrawTextureOpaque_frag.h" +#include "DrawColoredTexture_frag.h" using namespace gpu; @@ -73,42 +73,42 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) { ShaderPointer StandardShaderLib::getDrawUnitQuadTexcoordVS() { if (!_drawUnitQuadTexcoordVS) { - _drawUnitQuadTexcoordVS = gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert)); + _drawUnitQuadTexcoordVS = DrawUnitQuadTexcoord_vert::getShader(); } return _drawUnitQuadTexcoordVS; } ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() { if (!_drawTransformUnitQuadVS) { - _drawTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTransformUnitQuad_vert)); + _drawTransformUnitQuadVS = DrawTransformUnitQuad_vert::getShader(); } return _drawTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS() { if (!_drawTexcoordRectTransformUnitQuadVS) { - _drawTexcoordRectTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert)); + _drawTexcoordRectTransformUnitQuadVS = DrawTexcoordRectTransformUnitQuad_vert::getShader(); } return _drawTexcoordRectTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() { if (!_drawViewportQuadTransformTexcoordVS) { - _drawViewportQuadTransformTexcoordVS = gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert)); + _drawViewportQuadTransformTexcoordVS = DrawViewportQuadTransformTexcoord_vert::getShader(); } return _drawViewportQuadTransformTexcoordVS; } ShaderPointer StandardShaderLib::getDrawVertexPositionVS() { if (!_drawVertexPositionVS) { - _drawVertexPositionVS = gpu::Shader::createVertex(std::string(DrawVertexPosition_vert)); + _drawVertexPositionVS = DrawVertexPosition_vert::getShader(); } return _drawVertexPositionVS; } ShaderPointer StandardShaderLib::getDrawTransformVertexPositionVS() { if (!_drawTransformVertexPositionVS) { - _drawTransformVertexPositionVS = gpu::Shader::createVertex(std::string(DrawTransformVertexPosition_vert)); + _drawTransformVertexPositionVS = DrawTransformVertexPosition_vert::getShader(); } return _drawTransformVertexPositionVS; } @@ -122,42 +122,42 @@ ShaderPointer StandardShaderLib::getDrawNadaPS() { ShaderPointer StandardShaderLib::getDrawWhitePS() { if (!_drawWhitePS) { - _drawWhitePS = gpu::Shader::createPixel(std::string(DrawWhite_frag)); + _drawWhitePS = DrawWhite_frag::getShader(); } return _drawWhitePS; } ShaderPointer StandardShaderLib::getDrawColorPS() { if (!_drawColorPS) { - _drawColorPS = gpu::Shader::createPixel(std::string(DrawColor_frag)); + _drawColorPS = DrawColor_frag::getShader(); } return _drawColorPS; } ShaderPointer StandardShaderLib::getDrawTexturePS() { if (!_drawTexturePS) { - _drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag)); + _drawTexturePS = DrawTexture_frag::getShader(); } return _drawTexturePS; } ShaderPointer StandardShaderLib::getDrawTextureMirroredXPS() { if (!_drawTextureMirroredXPS) { - _drawTextureMirroredXPS = gpu::Shader::createPixel(std::string(DrawTextureMirroredX_frag)); + _drawTextureMirroredXPS = DrawTextureMirroredX_frag::getShader(); } return _drawTextureMirroredXPS; } ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { if (!_drawTextureOpaquePS) { - _drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag)); + _drawTextureOpaquePS = DrawTextureOpaque_frag::getShader(); } return _drawTextureOpaquePS; } ShaderPointer StandardShaderLib::getDrawColoredTexturePS() { if (!_drawColoredTexturePS) { - _drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)); + _drawColoredTexturePS = DrawColoredTexture_frag::getShader(); } return _drawColoredTexturePS; } diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 7e03890c85..e2877d4bb4 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -15,8 +15,8 @@ #include #include -INCLUDE_SHADER(skybox_vert) -INCLUDE_SHADER(skybox_frag) +#include "skybox_vert.h" +#include "skybox_frag.h" using namespace model; @@ -85,8 +85,8 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky static std::once_flag once; std::call_once(once, [&] { { - auto skyVS = gpu::Shader::createVertex(std::string(skybox_vert)); - auto skyFS = gpu::Shader::createPixel(std::string(skybox_frag)); + auto skyVS = skybox_vert::getShader(); + auto skyFS = skybox_frag::getShader(); auto skyShader = gpu::Shader::createProgram(skyVS, skyFS); gpu::Shader::BindingSet bindings; diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index c0ebdbb186..ba29768f68 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -20,7 +20,7 @@ #include #include -INCLUDE_SHADER(ProceduralCommon_frag) +#include "ProceduralCommon_frag.h" #include "Logging.h" @@ -241,7 +241,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm std::string fragmentShaderSource = _fragmentSource; size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); if (replaceIndex != std::string::npos) { - fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag); + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag.h"; } replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 452d3f639a..60fde7bd14 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -15,8 +15,8 @@ #include #include -INCLUDE_SHADER(skybox_vert) -INCLUDE_SHADER(skybox_frag) +#include "skybox_vert.h" +#include "skybox_frag.h" ProceduralSkybox::ProceduralSkybox() : model::Skybox() { _procedural._vertexSource = skybox_vert; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f5b4f0f6bb..83753131c8 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -28,11 +28,11 @@ #include "DependencyManager.h" #include "ViewFrustum.h" -INCLUDE_SHADER(ssao_makePyramid_frag) -INCLUDE_SHADER(ssao_makeOcclusion_frag) -INCLUDE_SHADER(ssao_debugOcclusion_frag) -INCLUDE_SHADER(ssao_makeHorizontalBlur_frag) -INCLUDE_SHADER(ssao_makeVerticalBlur_frag) +#include "ssao_makePyramid_frag.h" +#include "ssao_makeOcclusion_frag.h" +#include "ssao_debugOcclusion_frag.h" +#include "ssao_makeHorizontalBlur_frag.h" +#include "ssao_makeVerticalBlur_frag.h" AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 53ed3ea9a0..382b4e2d93 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -17,8 +17,8 @@ #include "AnimDebugDraw.h" -INCLUDE_SHADER(animdebugdraw_vert) -INCLUDE_SHADER(animdebugdraw_frag) +#include "animdebugdraw_vert.h" +#include "animdebugdraw_frag.h" class AnimDebugDrawData { public: diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 078e906fad..70c2e3b5ce 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -23,9 +23,9 @@ #include "ViewFrustum.h" #include "GeometryCache.h" -INCLUDE_SHADER(fxaa_vert) -INCLUDE_SHADER(fxaa_frag) -INCLUDE_SHADER(fxaa_blend_frag) +#include "fxaa_vert.h" +#include "fxaa_frag.h" +#include "fxaa_blend_frag.h" Antialiasing::Antialiasing() { diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index ace347f99e..9d9367a6d5 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -16,8 +16,8 @@ #include #include -INCLUDE_SHADER(BloomThreshold_frag) -INCLUDE_SHADER(BloomApply_frag) +#include "BloomThreshold_frag.h" +#include "BloomApply_frag.h" #define BLOOM_BLUR_LEVEL_COUNT 3 diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 05cd6a6f0e..fe03ead4e1 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -23,8 +23,8 @@ #include "TextureCache.h" #include "DeferredLightingEffect.h" -INCLUDE_SHADER(debug_deferred_buffer_vert) -INCLUDE_SHADER(debug_deferred_buffer_frag) +#include "debug_deferred_buffer_vert.h" +#include "debug_deferred_buffer_frag.h" using namespace render; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8ec2c74353..81a33f17e3 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -24,18 +24,18 @@ #include "TextureCache.h" #include "FramebufferCache.h" -INCLUDE_SHADER(deferred_light_vert) -INCLUDE_SHADER(deferred_light_point_vert) -INCLUDE_SHADER(deferred_light_spot_vert) +#include "deferred_light_vert.h" +#include "deferred_light_point_vert.h" +#include "deferred_light_spot_vert.h" -INCLUDE_SHADER(directional_ambient_light_frag) -INCLUDE_SHADER(directional_skybox_light_frag) +#include "directional_ambient_light_frag.h" +#include "directional_skybox_light_frag.h" -INCLUDE_SHADER(directional_ambient_light_shadow_frag) -INCLUDE_SHADER(directional_skybox_light_shadow_frag) +#include "directional_ambient_light_shadow_frag.h" +#include "directional_skybox_light_shadow_frag.h" -INCLUDE_SHADER(local_lights_shading_frag) -INCLUDE_SHADER(local_lights_drawOutline_frag) +#include "local_lights_shading_frag.h" +#include "local_lights_drawOutline_frag.h" using namespace render; diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index dc1893b347..da07f5bd9b 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -19,7 +19,7 @@ #include "HazeStage.h" #include "LightStage.h" -INCLUDE_SHADER(Haze_frag) +#include "Haze_frag.h" void HazeConfig::setHazeColor(const glm::vec3 value) { hazeColor = value; diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index ac8b300e49..2616d08600 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -34,21 +34,21 @@ #include "model/TextureMap.h" #include "render/Args.h" -INCLUDE_SHADER(standardTransformPNTC_vert) -INCLUDE_SHADER(standardDrawTexture_frag) +#include "standardTransformPNTC_vert.h" +#include "standardDrawTexture_frag.h" -INCLUDE_SHADER(simple_vert) -INCLUDE_SHADER(simple_textured_frag) -INCLUDE_SHADER(simple_textured_unlit_frag) -INCLUDE_SHADER(simple_fade_vert) -INCLUDE_SHADER(simple_textured_fade_frag) -INCLUDE_SHADER(simple_textured_unlit_fade_frag) -INCLUDE_SHADER(simple_opaque_web_browser_frag) -INCLUDE_SHADER(simple_transparent_web_browser_frag) -INCLUDE_SHADER(glowLine_vert) -INCLUDE_SHADER(glowLine_frag) +#include "simple_vert.h" +#include "simple_textured_frag.h" +#include "simple_textured_unlit_frag.h" +#include "simple_fade_vert.h" +#include "simple_textured_fade_frag.h" +#include "simple_textured_unlit_fade_frag.h" +#include "simple_opaque_web_browser_frag.h" +#include "simple_transparent_web_browser_frag.h" +#include "glowLine_vert.h" +#include "glowLine_frag.h" -INCLUDE_SHADER(grid_frag) +#include "grid_frag.h" //#define WANT_DEBUG diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 69feffb055..fee1f4a568 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -22,13 +22,13 @@ #include -INCLUDE_SHADER(surfaceGeometry_copyDepth_frag) -INCLUDE_SHADER(debug_deferred_buffer_vert) -INCLUDE_SHADER(debug_deferred_buffer_frag) -INCLUDE_SHADER(Highlight_frag) -INCLUDE_SHADER(Highlight_filled_frag) -INCLUDE_SHADER(Highlight_aabox_vert) -INCLUDE_SHADER(nop_frag) +#include "surfaceGeometry_copyDepth_frag.h" +#include "debug_deferred_buffer_vert.h" +#include "debug_deferred_buffer_frag.h" +#include "Highlight_frag.h" +#include "Highlight_filled_frag.h" +#include "Highlight_aabox_vert.h" +#include "nop_frag.h" using namespace render; @@ -547,10 +547,10 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const return task.addJob("TransparentSelection", selectItemInput); } -INCLUDE_SHADER(model_shadow_vert) -INCLUDE_SHADER(skin_model_shadow_vert) +#include "model_shadow_vert.h" +#include "skin_model_shadow_vert.h" -INCLUDE_SHADER(model_shadow_frag) +#include "model_shadow_frag.h" void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index 79d755683f..d6ac7fd2e2 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -18,15 +18,15 @@ #include "StencilMaskPass.h" -INCLUDE_SHADER(lightClusters_drawGrid_vert) -INCLUDE_SHADER(lightClusters_drawGrid_frag) +#include "lightClusters_drawGrid_vert.h" +#include "lightClusters_drawGrid_frag.h" -//INCLUDE_SHADER(lightClusters_drawClusterFromDepth_vert) -INCLUDE_SHADER(lightClusters_drawClusterFromDepth_frag) +//#include "lightClusters_drawClusterFromDepth_vert.h" +#include "lightClusters_drawClusterFromDepth_frag.h" -INCLUDE_SHADER(lightClusters_drawClusterContent_vert) -INCLUDE_SHADER(lightClusters_drawClusterContent_frag) +#include "lightClusters_drawClusterContent_vert.h" +#include "lightClusters_drawClusterContent_frag.h" enum LightClusterGridShader_MapSlot { DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 0, diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 8d02281d05..16e739f432 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -24,7 +24,7 @@ #include -INCLUDE_SHADER(nop_frag) +#include "nop_frag.h" using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); @@ -125,7 +125,7 @@ void Draw::run(const RenderContextPointer& renderContext, const gpu::PipelinePointer Stencil::getPipeline() { if (!_stencilPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(nop_frag)); + auto ps = gpu::Shader::createPixel(std::string(nop_frag); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram(*program); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 62252d3a0b..7f644add72 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -20,86 +20,86 @@ #include "TextureCache.h" #include "render/DrawTask.h" -INCLUDE_SHADER(model_vert) -INCLUDE_SHADER(model_normal_map_vert) -INCLUDE_SHADER(model_lightmap_vert) -INCLUDE_SHADER(model_lightmap_normal_map_vert) -INCLUDE_SHADER(skin_model_vert) -INCLUDE_SHADER(skin_model_normal_map_vert) +#include "model_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_normal_map_vert.h" -INCLUDE_SHADER(model_lightmap_fade_vert) -INCLUDE_SHADER(model_lightmap_normal_map_fade_vert) -INCLUDE_SHADER(skin_model_fade_vert) -INCLUDE_SHADER(skin_model_normal_map_fade_vert) +#include "model_lightmap_fade_vert.h" +#include "model_lightmap_normal_map_fade_vert.h" +#include "skin_model_fade_vert.h" +#include "skin_model_normal_map_fade_vert.h" -INCLUDE_SHADER(simple_vert) -INCLUDE_SHADER(simple_textured_frag) -INCLUDE_SHADER(simple_textured_unlit_frag) -INCLUDE_SHADER(simple_transparent_textured_frag) -INCLUDE_SHADER(simple_transparent_textured_unlit_frag) +#include "simple_vert.h" +#include "simple_textured_frag.h" +#include "simple_textured_unlit_frag.h" +#include "simple_transparent_textured_frag.h" +#include "simple_transparent_textured_unlit_frag.h" -INCLUDE_SHADER(simple_fade_vert) -INCLUDE_SHADER(simple_textured_fade_frag) -INCLUDE_SHADER(simple_textured_unlit_fade_frag) -INCLUDE_SHADER(simple_transparent_textured_fade_frag) -INCLUDE_SHADER(simple_transparent_textured_unlit_fade_frag) +#include "simple_fade_vert.h" +#include "simple_textured_fade_frag.h" +#include "simple_textured_unlit_fade_frag.h" +#include "simple_transparent_textured_fade_frag.h" +#include "simple_transparent_textured_unlit_fade_frag.h" -INCLUDE_SHADER(model_frag) -INCLUDE_SHADER(model_unlit_frag) -INCLUDE_SHADER(model_normal_map_frag) -INCLUDE_SHADER(model_normal_specular_map_frag) -INCLUDE_SHADER(model_specular_map_frag) +#include "model_frag.h" +#include "model_unlit_frag.h" +#include "model_normal_map_frag.h" +#include "model_normal_specular_map_frag.h" +#include "model_specular_map_frag.h" -INCLUDE_SHADER(model_fade_vert) -INCLUDE_SHADER(model_normal_map_fade_vert) +#include "model_fade_vert.h" +#include "model_normal_map_fade_vert.h" -INCLUDE_SHADER(model_fade_frag) -INCLUDE_SHADER(model_unlit_fade_frag) -INCLUDE_SHADER(model_normal_map_fade_frag) -INCLUDE_SHADER(model_normal_specular_map_fade_frag) -INCLUDE_SHADER(model_specular_map_fade_frag) +#include "model_fade_frag.h" +#include "model_unlit_fade_frag.h" +#include "model_normal_map_fade_frag.h" +#include "model_normal_specular_map_fade_frag.h" +#include "model_specular_map_fade_frag.h" -INCLUDE_SHADER(forward_model_frag) -INCLUDE_SHADER(forward_model_unlit_frag) -INCLUDE_SHADER(forward_model_normal_map_frag) -INCLUDE_SHADER(forward_model_normal_specular_map_frag) -INCLUDE_SHADER(forward_model_specular_map_frag) +#include "forward_model_frag.h" +#include "forward_model_unlit_frag.h" +#include "forward_model_normal_map_frag.h" +#include "forward_model_normal_specular_map_frag.h" +#include "forward_model_specular_map_frag.h" -INCLUDE_SHADER(model_lightmap_frag) -INCLUDE_SHADER(model_lightmap_normal_map_frag) -INCLUDE_SHADER(model_lightmap_normal_specular_map_frag) -INCLUDE_SHADER(model_lightmap_specular_map_frag) -INCLUDE_SHADER(model_translucent_frag) -INCLUDE_SHADER(model_translucent_unlit_frag) +#include "model_lightmap_frag.h" +#include "model_lightmap_normal_map_frag.h" +#include "model_lightmap_normal_specular_map_frag.h" +#include "model_lightmap_specular_map_frag.h" +#include "model_translucent_frag.h" +#include "model_translucent_unlit_frag.h" -INCLUDE_SHADER(model_lightmap_fade_frag) -INCLUDE_SHADER(model_lightmap_normal_map_fade_frag) -INCLUDE_SHADER(model_lightmap_normal_specular_map_fade_frag) -INCLUDE_SHADER(model_lightmap_specular_map_fade_frag) -INCLUDE_SHADER(model_translucent_fade_frag) -INCLUDE_SHADER(model_translucent_unlit_fade_frag) +#include "model_lightmap_fade_frag.h" +#include "model_lightmap_normal_map_fade_frag.h" +#include "model_lightmap_normal_specular_map_fade_frag.h" +#include "model_lightmap_specular_map_fade_frag.h" +#include "model_translucent_fade_frag.h" +#include "model_translucent_unlit_fade_frag.h" -INCLUDE_SHADER(overlay3D_vert) -INCLUDE_SHADER(overlay3D_frag) -INCLUDE_SHADER(overlay3D_model_frag) -INCLUDE_SHADER(overlay3D_model_translucent_frag) -INCLUDE_SHADER(overlay3D_translucent_frag) -INCLUDE_SHADER(overlay3D_unlit_frag) -INCLUDE_SHADER(overlay3D_translucent_unlit_frag) -INCLUDE_SHADER(overlay3D_model_unlit_frag) -INCLUDE_SHADER(overlay3D_model_translucent_unlit_frag) +#include "overlay3D_vert.h" +#include "overlay3D_frag.h" +#include "overlay3D_model_frag.h" +#include "overlay3D_model_translucent_frag.h" +#include "overlay3D_translucent_frag.h" +#include "overlay3D_unlit_frag.h" +#include "overlay3D_translucent_unlit_frag.h" +#include "overlay3D_model_unlit_frag.h" +#include "overlay3D_model_translucent_unlit_frag.h" -INCLUDE_SHADER(model_shadow_vert) -INCLUDE_SHADER(skin_model_shadow_vert) +#include "model_shadow_vert.h" +#include "skin_model_shadow_vert.h" -INCLUDE_SHADER(model_shadow_frag) -INCLUDE_SHADER(skin_model_shadow_frag) +#include "model_shadow_frag.h" +#include "skin_model_shadow_frag.h" -INCLUDE_SHADER(model_shadow_fade_vert) -INCLUDE_SHADER(skin_model_shadow_fade_vert) +#include "model_shadow_fade_vert.h" +#include "skin_model_shadow_fade_vert.h" -INCLUDE_SHADER(model_shadow_fade_frag) -INCLUDE_SHADER(skin_model_shadow_fade_frag) +#include "model_shadow_fade_frag.h" +#include "skin_model_shadow_fade_frag.h" using namespace render; using namespace std::placeholders; diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index e2a8b31f08..80c97cf29f 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -17,7 +17,7 @@ #include -INCLUDE_SHADER(stencil_drawMask_frag) +#include "stencil_drawMask_frag.h" using namespace render; @@ -60,7 +60,7 @@ gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() { gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() { if (!_paintStencilPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(stencil_drawMask_frag)); + auto ps = gpu::Shader::createPixel(std::string(stencil_drawMask_frag); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index e8d7e23ec2..1786898e57 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -17,11 +17,11 @@ #include "DeferredLightingEffect.h" -INCLUDE_SHADER(subsurfaceScattering_makeProfile_frag) -INCLUDE_SHADER(subsurfaceScattering_makeLUT_frag) -INCLUDE_SHADER(subsurfaceScattering_makeSpecularBeckmann_frag) +#include "subsurfaceScattering_makeProfile_frag.h" +#include "subsurfaceScattering_makeLUT_frag.h" +#include "subsurfaceScattering_makeSpecularBeckmann_frag.h" -INCLUDE_SHADER(subsurfaceScattering_drawScattering_frag) +#include "subsurfaceScattering_drawScattering_frag.h" enum ScatteringShaderBufferSlots { ScatteringTask_FrameTransformSlot = 0, diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 6ad8dc6137..af6ff09082 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -25,10 +25,10 @@ const int SurfaceGeometryPass_ParamsSlot = 1; const int SurfaceGeometryPass_DepthMapSlot = 0; const int SurfaceGeometryPass_NormalMapSlot = 1; -INCLUDE_SHADER(surfaceGeometry_makeLinearDepth_frag) -INCLUDE_SHADER(surfaceGeometry_downsampleDepthNormal_frag) +#include "surfaceGeometry_makeLinearDepth_frag.h" +#include "surfaceGeometry_downsampleDepthNormal_frag.h" -INCLUDE_SHADER(surfaceGeometry_makeCurvature_frag) +#include "surfaceGeometry_makeCurvature_frag.h" @@ -212,7 +212,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() { if (!_linearDepthPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeLinearDepth_frag)); + auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeLinearDepth_frag); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -239,7 +239,7 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() { const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() { if (!_downsamplePipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_downsampleDepthNormal_frag)); + auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_downsampleDepthNormal_frag); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -540,7 +540,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext, const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() { if (!_curvaturePipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeCurvature_frag)); + auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeCurvature_frag); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 06e041685a..9c85952107 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -25,8 +25,8 @@ #include "MatrixStack.h" #include "RenderUtilsLogging.h" -INCLUDE_SHADER(sdf_text3D_vert) -INCLUDE_SHADER(sdf_text3D_frag) +#include "sdf_text3D_vert.h" +#include "sdf_text3D_frag.h" #include "GeometryCache.h" diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 3d3a11f7b3..6cb9541dae 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -17,7 +17,7 @@ #include "StencilMaskPass.h" #include "FramebufferCache.h" -INCLUDE_SHADER(toneMapping_frag) +#include "toneMapping_frag.h" const int ToneMappingEffect_ParamsSlot = 0; const int ToneMappingEffect_LightingMapSlot = 0; @@ -28,7 +28,7 @@ ToneMappingEffect::ToneMappingEffect() { } void ToneMappingEffect::init() { - auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(toneMapping_frag))); + auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(toneMapping_frag)); auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 77b5c492d3..c0d01c2eaf 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -20,9 +20,9 @@ #include "StencilMaskPass.h" #include "DeferredLightingEffect.h" -INCLUDE_SHADER(zone_drawKeyLight_frag) -INCLUDE_SHADER(zone_drawAmbient_frag) -INCLUDE_SHADER(zone_drawSkybox_frag) +#include "zone_drawKeyLight_frag.h" +#include "zone_drawAmbient_frag.h" +#include "zone_drawSkybox_frag.h" using namespace render; diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 9e0fbd1522..8449c58c7c 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -7,9 +7,9 @@ #include -INCLUDE_SHADER(sdf_text3D_vert) -INCLUDE_SHADER(sdf_text3D_frag) -INCLUDE_SHADER(sdf_text3D_transparent_frag) +#include "sdf_text3D_vert.h" +#include "sdf_text3D_frag.h" +#include "sdf_text3D_transparent_frag.h" #include "../RenderUtilsLogging.h" #include "FontFamilies.h" diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 4b5d6da8e3..2be6f8fad2 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -13,11 +13,11 @@ #include #include -INCLUDE_SHADER(blurGaussianV_frag) -INCLUDE_SHADER(blurGaussianH_frag) +#include "blurGaussianV_frag.h" +#include "blurGaussianH_frag.h" -INCLUDE_SHADER(blurGaussianDepthAwareV_frag) -INCLUDE_SHADER(blurGaussianDepthAwareH_frag) +#include "blurGaussianDepthAwareV_frag.h" +#include "blurGaussianDepthAwareH_frag.h" using namespace render; diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 7823d85dae..36663a454a 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -22,12 +22,12 @@ #include "Args.h" -INCLUDE_SHADER(drawCellBounds_vert) -INCLUDE_SHADER(drawCellBounds_frag) -INCLUDE_SHADER(drawLODReticle_frag) +#include "drawCellBounds_vert.h" +#include "drawCellBounds_frag.h" +#include "drawLODReticle_frag.h" -INCLUDE_SHADER(drawItemBounds_vert) -INCLUDE_SHADER(drawItemBounds_frag) +#include "drawItemBounds_vert.h" +#include "drawItemBounds_frag.h" using namespace render; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 1c6d7749f8..148e104453 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -21,10 +21,10 @@ #include "Args.h" -INCLUDE_SHADER(drawItemBounds_vert) -INCLUDE_SHADER(drawItemBounds_frag) -INCLUDE_SHADER(drawItemStatus_vert) -INCLUDE_SHADER(drawItemStatus_frag) +#include "drawItemBounds_vert.h" +#include "drawItemBounds_frag.h" +#include "drawItemStatus_vert.h" +#include "drawItemStatus_frag.h" using namespace render; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index a6d5072cca..a60bf91062 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -22,8 +22,8 @@ #include #include -INCLUDE_SHADER(drawItemBounds_vert) -INCLUDE_SHADER(drawItemBounds_frag) +#include "drawItemBounds_vert.h" +#include "drawItemBounds_frag.h" using namespace render; diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index e0babc8b47..de37c505a6 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -23,65 +23,65 @@ #include -INCLUDE_SHADER(simple_vert) -INCLUDE_SHADER(simple_frag) -INCLUDE_SHADER(simple_textured_frag) -INCLUDE_SHADER(simple_textured_unlit_frag) +#include "simple_vert.h" +#include "simple_frag.h" +#include "simple_textured_frag.h" +#include "simple_textured_unlit_frag.h" -INCLUDE_SHADER(deferred_light_vert) -INCLUDE_SHADER(deferred_light_point_vert) -INCLUDE_SHADER(deferred_light_spot_vert) +#include "deferred_light_vert.h" +#include "deferred_light_point_vert.h" +#include "deferred_light_spot_vert.h" -INCLUDE_SHADER(directional_ambient_light_frag) -INCLUDE_SHADER(directional_skybox_light_frag) +#include "directional_ambient_light_frag.h" +#include "directional_skybox_light_frag.h" -INCLUDE_SHADER(standardTransformPNTC_vert) -INCLUDE_SHADER(standardDrawTexture_frag) +#include "standardTransformPNTC_vert.h" +#include "standardDrawTexture_frag.h" -INCLUDE_SHADER(model_vert) -INCLUDE_SHADER(model_shadow_vert) -INCLUDE_SHADER(model_normal_map_vert) -INCLUDE_SHADER(model_lightmap_vert) -INCLUDE_SHADER(model_lightmap_normal_map_vert) -INCLUDE_SHADER(skin_model_vert) -INCLUDE_SHADER(skin_model_shadow_vert) -INCLUDE_SHADER(skin_model_normal_map_vert) +#include "model_vert.h" +#include "model_shadow_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_normal_map_vert.h" -INCLUDE_SHADER(model_frag) -INCLUDE_SHADER(model_shadow_frag) -INCLUDE_SHADER(model_normal_map_frag) -INCLUDE_SHADER(model_normal_specular_map_frag) -INCLUDE_SHADER(model_specular_map_frag) -INCLUDE_SHADER(model_lightmap_frag) -INCLUDE_SHADER(model_lightmap_normal_map_frag) -INCLUDE_SHADER(model_lightmap_normal_specular_map_frag) -INCLUDE_SHADER(model_lightmap_specular_map_frag) -INCLUDE_SHADER(model_translucent_frag) +#include "model_frag.h" +#include "model_shadow_frag.h" +#include "model_normal_map_frag.h" +#include "model_normal_specular_map_frag.h" +#include "model_specular_map_frag.h" +#include "model_lightmap_frag.h" +#include "model_lightmap_normal_map_frag.h" +#include "model_lightmap_normal_specular_map_frag.h" +#include "model_lightmap_specular_map_frag.h" +#include "model_translucent_frag.h" -INCLUDE_SHADER(textured_particle_frag) -INCLUDE_SHADER(textured_particle_vert) +#include "textured_particle_frag.h" +#include "textured_particle_vert.h" -INCLUDE_SHADER(overlay3D_vert) -INCLUDE_SHADER(overlay3D_frag) +#include "overlay3D_vert.h" +#include "overlay3D_frag.h" -INCLUDE_SHADER(skybox_vert) -INCLUDE_SHADER(skybox_frag) +#include "skybox_vert.h" +#include "skybox_frag.h" -INCLUDE_SHADER(DrawTransformUnitQuad_vert) -INCLUDE_SHADER(DrawTexcoordRectTransformUnitQuad_vert) -INCLUDE_SHADER(DrawViewportQuadTransformTexcoord_vert) -INCLUDE_SHADER(DrawTexture_frag) -INCLUDE_SHADER(DrawTextureOpaque_frag) -INCLUDE_SHADER(DrawColoredTexture_frag) +#include "DrawTransformUnitQuad_vert.h" +#include "DrawTexcoordRectTransformUnitQuad_vert.h" +#include "DrawViewportQuadTransformTexcoord_vert.h" +#include "DrawTexture_frag.h" +#include "DrawTextureOpaque_frag.h" +#include "DrawColoredTexture_frag.h" -INCLUDE_SHADER(sdf_text3D_vert) -INCLUDE_SHADER(sdf_text3D_frag) +#include "sdf_text3D_vert.h" +#include "sdf_text3D_frag.h" -INCLUDE_SHADER(paintStroke_vert) -INCLUDE_SHADER(paintStroke_frag) +#include "paintStroke_vert.h" +#include "paintStroke_frag.h" -INCLUDE_SHADER(polyvox_vert) -INCLUDE_SHADER(polyvox_frag) +#include "polyvox_vert.h" +#include "polyvox_frag.h" // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { @@ -159,54 +159,54 @@ void QTestWindow::draw() { static std::once_flag once; std::call_once(once, [&]{ - testShaderBuild(sdf_text3D_vert, sdf_text3D_frag); + testShaderBuild(sdf_text3D_vert, sdf_text3D_frag.h"; - testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag); - testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag); - testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag); - testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag); - testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag); + testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag.h"; + testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag.h"; + testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag.h"; + testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag.h"; + testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag.h"; - testShaderBuild(skybox_vert, skybox_frag); - testShaderBuild(simple_vert, simple_frag); - testShaderBuild(simple_vert, simple_textured_frag); - testShaderBuild(simple_vert, simple_textured_unlit_frag); - testShaderBuild(deferred_light_vert, directional_ambient_light_frag); - testShaderBuild(deferred_light_vert, directional_skybox_light_frag); - testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag); - testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag); + testShaderBuild(skybox_vert, skybox_frag.h"; + testShaderBuild(simple_vert, simple_frag.h"; + testShaderBuild(simple_vert, simple_textured_frag.h"; + testShaderBuild(simple_vert, simple_textured_unlit_frag.h"; + testShaderBuild(deferred_light_vert, directional_ambient_light_frag.h"; + testShaderBuild(deferred_light_vert, directional_skybox_light_frag.h"; + testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag.h"; + testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag.h"; - testShaderBuild(model_vert, model_frag); - testShaderBuild(model_normal_map_vert, model_normal_map_frag); - testShaderBuild(model_vert, model_specular_map_frag); - testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag); - testShaderBuild(model_vert, model_translucent_frag); - testShaderBuild(model_normal_map_vert, model_translucent_frag); - testShaderBuild(model_lightmap_vert, model_lightmap_frag); - testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag); - testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag); - testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag); + testShaderBuild(model_vert, model_frag.h"; + testShaderBuild(model_normal_map_vert, model_normal_map_frag.h"; + testShaderBuild(model_vert, model_specular_map_frag.h"; + testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag.h"; + testShaderBuild(model_vert, model_translucent_frag.h"; + testShaderBuild(model_normal_map_vert, model_translucent_frag.h"; + testShaderBuild(model_lightmap_vert, model_lightmap_frag.h"; + testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag.h"; + testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag.h"; + testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag.h"; - testShaderBuild(skin_model_vert, model_frag); - testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag); - testShaderBuild(skin_model_vert, model_specular_map_frag); - testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag); - testShaderBuild(skin_model_vert, model_translucent_frag); - testShaderBuild(skin_model_normal_map_vert, model_translucent_frag); + testShaderBuild(skin_model_vert, model_frag.h"; + testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag.h"; + testShaderBuild(skin_model_vert, model_specular_map_frag.h"; + testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag.h"; + testShaderBuild(skin_model_vert, model_translucent_frag.h"; + testShaderBuild(skin_model_normal_map_vert, model_translucent_frag.h"; - testShaderBuild(model_shadow_vert, model_shadow_frag); - testShaderBuild(textured_particle_vert, textured_particle_frag); + testShaderBuild(model_shadow_vert, model_shadow_frag.h"; + testShaderBuild(textured_particle_vert, textured_particle_frag.h"; /* FIXME: Bring back the ssao shader tests - testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag); - testShaderBuild(gaussian_blur_horizontal_vert, gaussian_blur_frag); - testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag); - testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag); + testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag.h"; + testShaderBuild(gaussian_blur_horizontal_vert, gaussian_blur_frag.h"; + testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag.h"; + testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag.h"; */ - testShaderBuild(overlay3D_vert, overlay3D_frag); + testShaderBuild(overlay3D_vert, overlay3D_frag.h"; - testShaderBuild(paintStroke_vert,paintStroke_frag); - testShaderBuild(polyvox_vert, polyvox_frag); + testShaderBuild(paintStroke_vert,paintStroke_frag.h"; + testShaderBuild(polyvox_vert, polyvox_frag.h"; }); _context.swapBuffers(this); diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index 8e6ca31c71..2092bc0ea2 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -44,6 +44,18 @@ int main (int argc, char** argv) { EXIT, } mode = READY; + enum Type { + VERTEX = 0, + FRAGMENT, + GEOMETRY, + } type = VERTEX; + static const char* shaderTypeString[] = { + "VERTEX", "PIXEL", "GEOMETRY" + }; + static const char* shaderCreateString[] = { + "Vertex", "Pixel", "Geometry" + }; + for (int ii = 1; (mode != EXIT) && (ii < argc); ii++) { inputs.push_back(argv[ii]); @@ -66,6 +78,15 @@ int main (int argc, char** argv) { } else if (inputs.back() == "-c++") { makeCPlusPlus = true; mode = READY; + } else if (inputs.back() == "-vert") { + type = VERTEX; + mode = READY; + } else if (inputs.back() == "-frag") { + type = FRAGMENT; + mode = READY; + } else if (inputs.back() == "-geom") { + type = GEOMETRY; + mode = READY; } else { // just grabbed the source filename, stop parameter parsing srcFilename = inputs.back(); @@ -186,7 +207,6 @@ int main (int argc, char** argv) { scribe->displayTree(cerr, level); } - std::ostringstream targetStringStream; if (makeCPlusPlus) { // Because there is a maximum size for literal strings declared in source we need to partition the // full source string stream into pages that seems to be around that value... @@ -208,32 +228,108 @@ int main (int argc, char** argv) { pageSize += lineSize; } - targetStringStream << "// File generated by Scribe " << vars["_SCRIBE_DATE"] << std::endl; - targetStringStream << "extern const char " << targetName << "[] = \n"; + std::stringstream headerStringStream; + std::stringstream sourceStringStream; + std::string headerFileName = destFilename + ".h"; + std::string sourceFileName = destFilename + ".cpp"; + sourceStringStream << "// File generated by Scribe " << vars["_SCRIBE_DATE"] << std::endl; + + // Write header file + headerStringStream << "#ifndef " << targetName << "_h" << std::endl; + headerStringStream << "#define " << targetName << "_h\n" << std::endl; + headerStringStream << "#include \n" << std::endl; + headerStringStream << "class " << targetName << " {" << std::endl; + headerStringStream << "public:" << std::endl; + headerStringStream << "\tstatic gpu::Shader::Type getType() { return gpu::Shader::" << shaderTypeString[type] << "; }" << std::endl; + headerStringStream << "\tstatic const char* getSource() { return _source; }" << std::endl; + headerStringStream << "\tstatic gpu::ShaderPointer getShader();" << std::endl; + headerStringStream << "private:" << std::endl; + headerStringStream << "\tstatic const char* _source;" << std::endl; + headerStringStream << "\tstatic gpu::ShaderPointer _shader;" << std::endl; + headerStringStream << "};\n" << std::endl; + headerStringStream << "#endif // " << targetName << "_h" << std::endl; + + bool mustOutputHeader = destFilename.empty(); + // Compare with existing file + { + std::fstream headerFile; + headerFile.open(headerFileName, std::fstream::in); + if (headerFile.is_open()) { + // Skip first line + std::string line; + std::stringstream previousHeaderStringStream; + std::getline(headerFile, line); + + previousHeaderStringStream << headerFile.rdbuf(); + mustOutputHeader = mustOutputHeader || previousHeaderStringStream.str() != headerStringStream.str(); + } else { + mustOutputHeader = true; + } + } + + if (mustOutputHeader) { + if (!destFilename.empty()) { + // File content has changed so write it + std::fstream headerFile; + headerFile.open(headerFileName, std::fstream::out); + if (headerFile.is_open()) { + // First line contains the date of modification + headerFile << sourceStringStream.str(); + headerFile << headerStringStream.str(); + } else { + cerr << "Scribe output file <" << headerFileName << "> failed to open." << endl; + return 0; + } + } else { + cerr << sourceStringStream.str(); + cerr << headerStringStream.str(); + } + } + + // Write source file + sourceStringStream << "#include \"" << targetName << ".h\"\n" << std::endl; + sourceStringStream << "gpu::ShaderPointer " << targetName << "::_shader;" << std::endl; + sourceStringStream << "const char* " << targetName << "::_source = "; // Write the pages content for (auto page : pages) { - targetStringStream << "R\"SCRIBE(\n" << page->str() << "\n)SCRIBE\"\n"; + sourceStringStream << "R\"SCRIBE(\n" << page->str() << "\n)SCRIBE\"\n"; } - targetStringStream << ";\n" << std::endl << std::endl; - targetStringStream << "// Hack to fix Android link error by forcing a reference to global variable\n"; - targetStringStream << "class " << targetName << "_used {\npublic:\nstatic const char* get() { return " << targetName << "; }\n};\n" << std::endl; - } else { - targetStringStream << destStringStream.str(); - } + sourceStringStream << ";\n" << std::endl << std::endl; - // Destination stream - if (!destFilename.empty()) { - std::fstream destFileStream; - destFileStream.open(destFilename, std::fstream::out); - if (!destFileStream.is_open()) { - cerr << "Scribe output file " << destFilename << "> failed to open." << endl; - return 0; + sourceStringStream << "gpu::ShaderPointer " << targetName << "::getShader() {" << std::endl; + sourceStringStream << "\tif (_shader==nullptr) {" << std::endl; + sourceStringStream << "\t\t_shader = gpu::Shader::create" << shaderCreateString[type] << "(std::string(_source));" << std::endl; + sourceStringStream << "\t}" << std::endl; + sourceStringStream << "\treturn _shader;" << std::endl; + sourceStringStream << "}\n" << std::endl; + + // Destination stream + if (!destFilename.empty()) { + std::fstream sourceFile; + sourceFile.open(sourceFileName, std::fstream::out); + if (!sourceFile.is_open()) { + cerr << "Scribe output file <" << sourceFileName << "> failed to open." << endl; + return 0; + } + sourceFile << sourceStringStream.str(); + } else { + cerr << sourceStringStream.str(); } - - destFileStream << targetStringStream.str(); } else { - cerr << targetStringStream.str(); + // Destination stream + if (!destFilename.empty()) { + std::fstream destFileStream; + destFileStream.open(destFilename, std::fstream::out); + if (!destFileStream.is_open()) { + cerr << "Scribe output file <" << destFilename << "> failed to open." << endl; + return 0; + } + + destFileStream << destStringStream.str(); + } else { + cerr << destStringStream.str(); + } } return 0; From 49549ced171962fc090ee8bfe4d3d8e27be260f0 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 17 Jan 2018 10:52:58 +0100 Subject: [PATCH 029/272] Fixed compilation with new shader system --- .../display-plugins/hmd/HmdDisplayPlugin.cpp | 8 +- .../RenderableParticleEffectEntityItem.cpp | 4 +- .../src/RenderablePolyLineEntityItem.cpp | 4 +- .../src/RenderablePolyVoxEntityItem.cpp | 4 +- .../src/RenderableShapeEntityItem.cpp | 8 +- .../procedural/src/procedural/Procedural.cpp | 2 +- .../src/procedural/ProceduralSkybox.cpp | 8 +- .../src/AmbientOcclusionEffect.cpp | 8 +- libraries/render-utils/src/AnimDebugDraw.cpp | 4 +- .../render-utils/src/AntialiasingEffect.cpp | 8 +- libraries/render-utils/src/BloomEffect.cpp | 4 +- .../render-utils/src/DebugDeferredBuffer.cpp | 5 +- .../src/DeferredLightingEffect.cpp | 25 ++- libraries/render-utils/src/DrawHaze.cpp | 2 +- libraries/render-utils/src/GeometryCache.cpp | 35 ++-- .../render-utils/src/HighlightEffect.cpp | 19 +- libraries/render-utils/src/LightClusters.cpp | 8 +- .../render-utils/src/RenderForwardTask.cpp | 2 +- .../render-utils/src/RenderPipelines.cpp | 154 ++++++++-------- .../render-utils/src/StencilMaskPass.cpp | 2 +- .../render-utils/src/SubsurfaceScattering.cpp | 8 +- .../render-utils/src/SurfaceGeometryPass.cpp | 6 +- .../render-utils/src/ToneMappingEffect.cpp | 2 +- libraries/render-utils/src/ZoneRenderer.cpp | 6 +- libraries/render-utils/src/text/Font.cpp | 6 +- libraries/render/src/render/BlurTask.cpp | 8 +- .../render/src/render/DrawSceneOctree.cpp | 10 +- libraries/render/src/render/DrawStatus.cpp | 8 +- libraries/render/src/render/DrawTask.cpp | 4 +- tests/shaders/src/main.cpp | 172 +++++++++--------- tools/scribe/src/main.cpp | 10 +- 31 files changed, 273 insertions(+), 281 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index f39203c89d..0a5704f6da 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -33,8 +33,8 @@ #include "../Logging.h" #include "../CompositorHelper.h" -#include "hmd_ui_vert.h" -#include "hmd_ui_frag.h" +#include "render-utils/hmd_ui_vert.h" +#include "render-utils/hmd_ui_frag.h" static const QString MONO_PREVIEW = "Mono Preview"; static const QString DISABLE_PREVIEW = "Disable Preview"; @@ -403,8 +403,8 @@ void HmdDisplayPlugin::HUDRenderer::build() { void HmdDisplayPlugin::HUDRenderer::updatePipeline() { if (!pipeline) { - auto vs = gpu::Shader::createVertex(std::string(hmd_ui_vert)); - auto ps = gpu::Shader::createPixel(std::string(hmd_ui_frag)); + auto vs = hmd_ui_vert::getShader(); + auto ps = hmd_ui_frag::getShader(); auto program = gpu::Shader::createProgram(vs, ps); gpu::gl::GLBackend::makeProgram(*program, gpu::Shader::BindingSet()); uniformsLocation = program->getUniformBuffers().findLocation("hudBuffer"); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a3e6cd4341..9981245e6f 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -36,8 +36,8 @@ static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, co gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); PrepareStencil::testMask(*state); - auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert)); - auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag)); + auto vertShader = textured_particle_vert::getShader(); + auto fragShader = textured_particle_frag::getShader(); auto program = gpu::Shader::createProgram(vertShader, fragShader); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index b362721cde..8a53c9fba5 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -48,8 +48,8 @@ struct PolyLineUniforms { static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) { if (!polylinePipeline) { - auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert)); - auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag)); + auto VS = paintStroke_vert::getShader(); + auto PS = paintStroke_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); #ifdef POLYLINE_ENTITY_USE_FADE_EFFECT auto fadeVS = gpu::Shader::createVertex(std::string(paintStroke_fade_vert)); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index cf12da86e9..379103d4b3 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1461,8 +1461,8 @@ static gpu::Stream::FormatPointer _vertexFormat; ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key) { if (!_pipelines[0]) { - gpu::ShaderPointer vertexShaders[2] = { gpu::Shader::createVertex(std::string(polyvox_vert)), gpu::Shader::createVertex(std::string(polyvox_fade_vert)) }; - gpu::ShaderPointer pixelShaders[2] = { gpu::Shader::createPixel(std::string(polyvox_frag)), gpu::Shader::createPixel(std::string(polyvox_fade_frag)) }; + gpu::ShaderPointer vertexShaders[2] = { polyvox_vert::getShader(), polyvox_fade_vert::getShader() }; + gpu::ShaderPointer pixelShaders[2] = { polyvox_frag::getShader(), polyvox_fade_frag::getShader() }; gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index eddde317fe..0c4f8cbd39 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -16,8 +16,8 @@ #include #include -#include "simple_vert.h" -#include "simple_frag.h" +#include "render-utils/simple_vert.h" +#include "render-utils/simple_frag.h" //#define SHAPE_ENTITY_USE_FADE_EFFECT #ifdef SHAPE_ENTITY_USE_FADE_EFFECT @@ -32,8 +32,8 @@ static const float SPHERE_ENTITY_SCALE = 0.5f; ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { - _procedural._vertexSource = simple_vert; - _procedural._fragmentSource = simple_frag; + _procedural._vertexSource = simple_vert::getSource(); + _procedural._fragmentSource = simple_frag::getSource(); _procedural._opaqueState->setCullMode(gpu::State::CULL_NONE); _procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index ba29768f68..52c56d1e7d 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -241,7 +241,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm std::string fragmentShaderSource = _fragmentSource; size_t replaceIndex = fragmentShaderSource.find(PROCEDURAL_COMMON_BLOCK); if (replaceIndex != std::string::npos) { - fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag.h"; + fragmentShaderSource.replace(replaceIndex, PROCEDURAL_COMMON_BLOCK.size(), ProceduralCommon_frag::getSource()); } replaceIndex = fragmentShaderSource.find(PROCEDURAL_VERSION); diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 60fde7bd14..8fb74e0b1b 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -15,12 +15,12 @@ #include #include -#include "skybox_vert.h" -#include "skybox_frag.h" +#include "model/skybox_vert.h" +#include "model/skybox_frag.h" ProceduralSkybox::ProceduralSkybox() : model::Skybox() { - _procedural._vertexSource = skybox_vert; - _procedural._fragmentSource = skybox_frag; + _procedural._vertexSource = skybox_vert::getSource(); + _procedural._fragmentSource = skybox_frag::getSource(); // Adjust the pipeline state for background using the stencil test _procedural.setDoesFade(false); // Must match PrepareStencil::STENCIL_BACKGROUND diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 83753131c8..015f5678c8 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -263,7 +263,7 @@ void AmbientOcclusionEffect::configure(const Config& config) { const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { if (!_occlusionPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ssao_makeOcclusion_frag)); + auto ps = ssao_makeOcclusion_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -288,7 +288,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() { const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { if (!_hBlurPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ssao_makeHorizontalBlur_frag)); + auto ps = ssao_makeHorizontalBlur_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -311,7 +311,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() { const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() { if (!_vBlurPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ssao_makeVerticalBlur_frag)); + auto ps = ssao_makeVerticalBlur_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -458,7 +458,7 @@ void DebugAmbientOcclusion::configure(const Config& config) { const gpu::PipelinePointer& DebugAmbientOcclusion::getDebugPipeline() { if (!_debugPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(ssao_debugOcclusion_frag)); + auto ps = ssao_debugOcclusion_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index 382b4e2d93..dc9a4d8a1b 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -102,8 +102,8 @@ AnimDebugDraw::AnimDebugDraw() : state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::Shader::createVertex(std::string(animdebugdraw_vert)); - auto fragShader = gpu::Shader::createPixel(std::string(animdebugdraw_frag)); + auto vertShader = animdebugdraw_vert::getShader(); + auto fragShader = animdebugdraw_frag::getShader(); auto program = gpu::Shader::createProgram(vertShader, fragShader); _pipeline = gpu::Pipeline::create(program, state); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 70c2e3b5ce..bdd8f19a5c 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -57,8 +57,8 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* ar } if (!_antialiasingPipeline) { - auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); - auto ps = gpu::Shader::createPixel(std::string(fxaa_frag)); + auto vs = fxaa_vert::getShader(); + auto ps = fxaa_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -82,8 +82,8 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* ar const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); - auto ps = gpu::Shader::createPixel(std::string(fxaa_blend_frag)); + auto vs = fxaa_vert::getShader(); + auto ps = fxaa_blend_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 9d9367a6d5..89a83a651a 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -61,7 +61,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons if (!_pipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(BloomThreshold_frag)); + auto ps = BloomThreshold_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -113,7 +113,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In if (!_pipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(BloomApply_frag)); + auto ps = BloomApply_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index fe03ead4e1..24cffe2fb8 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -369,8 +369,7 @@ bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::string customFile) { if (pipelineNeedsUpdate(mode, customFile)) { - static const std::string VERTEX_SHADER { debug_deferred_buffer_vert }; - static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag }; + static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag::getSource() }; static const std::string SOURCE_PLACEHOLDER { "//SOURCE_PLACEHOLDER" }; static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, @@ -380,7 +379,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), getShaderSourceCode(mode, customFile)); - static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); + const auto vs = debug_deferred_buffer_vert::getShader(); const auto ps = gpu::Shader::createPixel(bakedFragmentShader); const auto program = gpu::Shader::createProgram(vs, ps); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 81a33f17e3..8c3b76f557 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -79,7 +79,7 @@ enum DeferredShader_BufferSlot { LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, }; -static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); +static void loadLightProgram(const gpu::ShaderPointer& vertShader, const gpu::ShaderPointer& fragShader, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations); void DeferredLightingEffect::init() { _directionalAmbientSphereLightLocations = std::make_shared(); @@ -91,14 +91,14 @@ void DeferredLightingEffect::init() { _localLightLocations = std::make_shared(); _localLightOutlineLocations = std::make_shared(); - loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations); + loadLightProgram(deferred_light_vert::getShader(), directional_ambient_light_frag::getShader(), false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations); + loadLightProgram(deferred_light_vert::getShader(), directional_skybox_light_frag::getShader(), false, _directionalSkyboxLight, _directionalSkyboxLightLocations); - loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_frag, false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); - loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); + loadLightProgram(deferred_light_vert::getShader(), directional_ambient_light_shadow_frag::getShader(), false, _directionalAmbientSphereLightShadow, _directionalAmbientSphereLightShadowLocations); + loadLightProgram(deferred_light_vert::getShader(), directional_skybox_light_shadow_frag::getShader(), false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); - loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations); - loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations); + loadLightProgram(deferred_light_vert::getShader(), local_lights_shading_frag::getShader(), true, _localLight, _localLightLocations); + loadLightProgram(deferred_light_vert::getShader(), local_lights_drawOutline_frag::getShader(), true, _localLightOutline, _localLightOutlineLocations); } void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) { @@ -144,11 +144,8 @@ void DeferredLightingEffect::unsetKeyLightBatch(gpu::Batch& batch, int lightBuff } } -static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* fragSource, LightLocationsPtr& locations) { - auto VS = gpu::Shader::createVertex(std::string(vertSource)); - auto PS = gpu::Shader::createPixel(std::string(fragSource)); - - gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); +static gpu::ShaderPointer makeLightProgram(const gpu::ShaderPointer& vertShader, const gpu::ShaderPointer& fragShader, LightLocationsPtr& locations) { + gpu::ShaderPointer program = gpu::Shader::createProgram(vertShader, fragShader); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("colorMap"), DEFERRED_BUFFER_COLOR_UNIT)); @@ -196,9 +193,9 @@ static gpu::ShaderPointer makeLightProgram(const char* vertSource, const char* f return program; } -static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { +static void loadLightProgram(const gpu::ShaderPointer& vertShader, const gpu::ShaderPointer& fragShader, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { - gpu::ShaderPointer program = makeLightProgram(vertSource, fragSource, locations); + gpu::ShaderPointer program = makeLightProgram(vertShader, fragShader, locations); auto state = std::make_shared(); state->setColorWriteMask(true, true, true, false); diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index da07f5bd9b..986212ca6e 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -133,7 +133,7 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu RenderArgs* args = renderContext->args; if (!_hazePipeline) { - gpu::ShaderPointer ps = gpu::Shader::createPixel(std::string(Haze_frag)); + gpu::ShaderPointer ps = Haze_frag::getShader(); gpu::ShaderPointer vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2616d08600..e962c2901f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1946,8 +1946,8 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const static std::once_flag once; std::call_once(once, [&] { auto state = std::make_shared(); - auto VS = gpu::Shader::createVertex(std::string(glowLine_vert)); - auto PS = gpu::Shader::createPixel(std::string(glowLine_frag)); + auto VS = glowLine_vert::getShader(); + auto PS = glowLine_frag::getShader(); auto program = gpu::Shader::createProgram(VS, PS); state->setCullMode(gpu::State::CULL_NONE); state->setDepthTest(true, false, gpu::LESS_EQUAL); @@ -2002,8 +2002,8 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { - auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); - auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); + auto vs = standardTransformPNTC_vert::getShader(); + auto ps = standardDrawTexture_frag::getShader(); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); @@ -2033,8 +2033,8 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { void GeometryCache::useGridPipeline(gpu::Batch& batch, GridBuffer gridBuffer, bool isLayered) { if (!_gridPipeline) { - auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); - auto ps = gpu::Shader::createPixel(std::string(grid_frag)); + auto vs = standardTransformPNTC_vert::getShader(); + auto ps = grid_frag::getShader(); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); _gridSlot = program->getUniformBuffers().findLocation("gridBuffer"); @@ -2117,12 +2117,9 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } -static void buildWebShader(const std::string& vertShaderText, const std::string& fragShaderText, bool blendEnable, +static void buildWebShader(const gpu::ShaderPointer& vertShader, const gpu::ShaderPointer& fragShader, bool blendEnable, gpu::ShaderPointer& shaderPointerOut, gpu::PipelinePointer& pipelinePointerOut) { - auto VS = gpu::Shader::createVertex(vertShaderText); - auto PS = gpu::Shader::createPixel(fragShaderText); - - shaderPointerOut = gpu::Shader::createProgram(VS, PS); + shaderPointerOut = gpu::Shader::createProgram(vertShader, fragShader); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*shaderPointerOut, slotBindings); @@ -2145,8 +2142,8 @@ void GeometryCache::bindWebBrowserProgram(gpu::Batch& batch, bool transparent) { gpu::PipelinePointer GeometryCache::getWebBrowserProgram(bool transparent) { static std::once_flag once; std::call_once(once, [&]() { - buildWebShader(simple_vert, simple_opaque_web_browser_frag, false, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipelineNoAA); - buildWebShader(simple_vert, simple_transparent_web_browser_frag, true, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipelineNoAA); + buildWebShader(simple_vert::getShader(), simple_opaque_web_browser_frag::getShader(), false, _simpleOpaqueWebBrowserShader, _simpleOpaqueWebBrowserPipelineNoAA); + buildWebShader(simple_vert::getShader(), simple_transparent_web_browser_frag::getShader(), true, _simpleTransparentWebBrowserShader, _simpleTransparentWebBrowserPipelineNoAA); }); return transparent ? _simpleTransparentWebBrowserPipelineNoAA : _simpleOpaqueWebBrowserPipelineNoAA; @@ -2175,9 +2172,9 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp if (!fading) { static std::once_flag once; std::call_once(once, [&]() { - auto VS = gpu::Shader::createVertex(std::string(simple_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); - auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); + auto VS = simple_vert::getShader(); + auto PS = simple_textured_frag::getShader(); + auto PSUnlit = simple_textured_unlit_frag::getShader(); _simpleShader = gpu::Shader::createProgram(VS, PS); _unlitShader = gpu::Shader::createProgram(VS, PSUnlit); @@ -2190,9 +2187,9 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool transp } else { static std::once_flag once; std::call_once(once, [&]() { - auto VS = gpu::Shader::createVertex(std::string(simple_fade_vert)); - auto PS = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); - auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); + auto VS = simple_fade_vert::getShader(); + auto PS = simple_textured_fade_frag::getShader(); + auto PSUnlit = simple_textured_unlit_fade_frag::getShader(); _simpleFadeShader = gpu::Shader::createProgram(VS, PS); _unlitFadeShader = gpu::Shader::createProgram(VS, PSUnlit); diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index fee1f4a568..9501a74d52 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -130,8 +130,8 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c fillState->setColorWriteMask(false, false, false, false); fillState->setCullMode(gpu::State::CULL_FRONT); - auto vs = gpu::Shader::createVertex(std::string(Highlight_aabox_vert)); - auto ps = gpu::Shader::createPixel(std::string(nop_frag)); + auto vs = Highlight_aabox_vert::getShader(); + auto ps = nop_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -313,7 +313,7 @@ const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightSt state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(Highlight_frag)); + auto ps = Highlight_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -325,7 +325,7 @@ const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightSt _pipeline = gpu::Pipeline::create(program, state); - ps = gpu::Shader::createPixel(std::string(Highlight_filled_frag)); + ps = Highlight_filled_frag::getShader(); program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram(*program, slotBindings); _pipelineFilled = gpu::Pipeline::create(program, state); @@ -385,8 +385,7 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons } void DebugHighlight::initializePipelines() { - static const std::string VERTEX_SHADER{ debug_deferred_buffer_vert }; - static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag }; + static const std::string FRAGMENT_SHADER{ debug_deferred_buffer_frag::getSource() }; static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER); Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, @@ -396,7 +395,7 @@ void DebugHighlight::initializePipelines() { state->setDepthTest(gpu::State::DepthTest(false, false)); state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); - const auto vs = gpu::Shader::createVertex(VERTEX_SHADER); + const auto vs = debug_deferred_buffer_vert::getShader(); // Depth shader { @@ -553,14 +552,14 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const #include "model_shadow_frag.h" void DrawHighlightTask::initMaskPipelines(render::ShapePlumber& shapePlumber, gpu::StatePointer state) { - auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelVertex = model_shadow_vert::getShader(); + auto modelPixel = model_shadow_frag::getShader(); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withoutSkinned(), modelProgram, state); - auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); + auto skinVertex = skin_model_shadow_vert::getShader(); gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, modelPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withSkinned(), diff --git a/libraries/render-utils/src/LightClusters.cpp b/libraries/render-utils/src/LightClusters.cpp index d6ac7fd2e2..ea02edb601 100644 --- a/libraries/render-utils/src/LightClusters.cpp +++ b/libraries/render-utils/src/LightClusters.cpp @@ -605,8 +605,8 @@ void DebugLightClusters::configure(const Config& config) { const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() { if (!_drawClusterGrid) { - auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawGrid_vert)); - auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawGrid_frag)); + auto vs = lightClusters_drawGrid_vert::getShader(); + auto ps = lightClusters_drawGrid_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -635,7 +635,7 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() if (!_drawClusterFromDepth) { // auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawGrid_vert)); auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterFromDepth_frag)); + auto ps = lightClusters_drawClusterFromDepth_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -665,7 +665,7 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterContentPipeline() { if (!_drawClusterContent) { // auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawClusterContent_vert)); auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterContent_frag)); + auto ps = lightClusters_drawClusterContent_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 16e739f432..1eeac7f449 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -125,7 +125,7 @@ void Draw::run(const RenderContextPointer& renderContext, const gpu::PipelinePointer Stencil::getPipeline() { if (!_stencilPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(nop_frag); + auto ps = nop_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram(*program); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 7f644add72..76e5cbc72a 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -117,16 +117,16 @@ void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* a void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args); void initOverlay3DPipelines(ShapePlumber& plumber, bool depthTest) { - auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); - auto vertexModel = gpu::Shader::createVertex(std::string(model_vert)); - auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag)); - auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag)); - auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag)); - auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag)); - auto pixelModel = gpu::Shader::createPixel(std::string(overlay3D_model_frag)); - auto pixelModelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_frag)); - auto pixelModelUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_unlit_frag)); - auto pixelModelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_model_translucent_unlit_frag)); + auto vertex = overlay3D_vert::getShader(); + auto vertexModel = model_vert::getShader(); + auto pixel = overlay3D_frag::getShader(); + auto pixelTranslucent = overlay3D_translucent_frag::getShader(); + auto pixelUnlit = overlay3D_unlit_frag::getShader(); + auto pixelTranslucentUnlit = overlay3D_translucent_unlit_frag::getShader(); + auto pixelModel = overlay3D_model_frag::getShader(); + auto pixelModelTranslucent = overlay3D_model_translucent_frag::getShader(); + auto pixelModelUnlit = overlay3D_model_unlit_frag::getShader(); + auto pixelModelTranslucentUnlit = overlay3D_model_translucent_unlit_frag::getShader(); auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel); auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); @@ -183,60 +183,60 @@ void initOverlay3DPipelines(ShapePlumber& plumber, bool depthTest) { void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter) { // Vertex shaders - auto simpleVertex = gpu::Shader::createVertex(std::string(simple_vert)); - auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); - auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); - auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); - auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); - auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); - auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); - auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - auto modelLightmapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_fade_vert)); - auto modelLightmapNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_fade_vert)); - auto skinModelFadeVertex = gpu::Shader::createVertex(std::string(skin_model_fade_vert)); - auto skinModelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_fade_vert)); + auto simpleVertex = simple_vert::getShader(); + auto modelVertex = model_vert::getShader(); + auto modelNormalMapVertex = model_normal_map_vert::getShader(); + auto modelLightmapVertex = model_lightmap_vert::getShader(); + auto modelLightmapNormalMapVertex = model_lightmap_normal_map_vert::getShader(); + auto modelShadowVertex = model_shadow_vert::getShader(); + auto skinModelVertex = skin_model_vert::getShader(); + auto skinModelNormalMapVertex = skin_model_normal_map_vert::getShader(); + auto skinModelShadowVertex = skin_model_shadow_vert::getShader(); + auto modelLightmapFadeVertex = model_lightmap_fade_vert::getShader(); + auto modelLightmapNormalMapFadeVertex = model_lightmap_normal_map_fade_vert::getShader(); + auto skinModelFadeVertex = skin_model_fade_vert::getShader(); + auto skinModelNormalMapFadeVertex = skin_model_normal_map_fade_vert::getShader(); - auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_fade_vert)); - auto modelNormalMapFadeVertex = gpu::Shader::createVertex(std::string(model_normal_map_fade_vert)); - auto simpleFadeVertex = gpu::Shader::createVertex(std::string(simple_fade_vert)); - auto modelShadowFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); - auto skinModelShadowFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); + auto modelFadeVertex = model_fade_vert::getShader(); + auto modelNormalMapFadeVertex = model_normal_map_fade_vert::getShader(); + auto simpleFadeVertex = simple_fade_vert::getShader(); + auto modelShadowFadeVertex = model_shadow_fade_vert::getShader(); + auto skinModelShadowFadeVertex = skin_model_shadow_fade_vert::getShader(); // Pixel shaders - auto simplePixel = gpu::Shader::createPixel(std::string(simple_textured_frag)); - auto simpleUnlitPixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag)); - auto simpleTranslucentPixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_frag)); - auto simpleTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_frag)); - auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); - auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); - auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); - auto modelTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_frag)); - auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); - auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); - auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); - auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); - auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); - auto modelLightmapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_fade_frag)); - auto modelLightmapNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_fade_frag)); - auto modelLightmapSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_fade_frag)); - auto modelLightmapNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_fade_frag)); + auto simplePixel = simple_textured_frag::getShader(); + auto simpleUnlitPixel = simple_textured_unlit_frag::getShader(); + auto simpleTranslucentPixel = simple_transparent_textured_frag::getShader(); + auto simpleTranslucentUnlitPixel = simple_transparent_textured_unlit_frag::getShader(); + auto modelPixel = model_frag::getShader(); + auto modelUnlitPixel = model_unlit_frag::getShader(); + auto modelNormalMapPixel = model_normal_map_frag::getShader(); + auto modelSpecularMapPixel = model_specular_map_frag::getShader(); + auto modelNormalSpecularMapPixel = model_normal_specular_map_frag::getShader(); + auto modelTranslucentPixel = model_translucent_frag::getShader(); + auto modelTranslucentUnlitPixel = model_translucent_unlit_frag::getShader(); + auto modelShadowPixel = model_shadow_frag::getShader(); + auto modelLightmapPixel = model_lightmap_frag::getShader(); + auto modelLightmapNormalMapPixel = model_lightmap_normal_map_frag::getShader(); + auto modelLightmapSpecularMapPixel = model_lightmap_specular_map_frag::getShader(); + auto modelLightmapNormalSpecularMapPixel = model_lightmap_normal_specular_map_frag::getShader(); + auto modelLightmapFadePixel = model_lightmap_fade_frag::getShader(); + auto modelLightmapNormalMapFadePixel = model_lightmap_normal_map_fade_frag::getShader(); + auto modelLightmapSpecularMapFadePixel = model_lightmap_specular_map_fade_frag::getShader(); + auto modelLightmapNormalSpecularMapFadePixel = model_lightmap_normal_specular_map_fade_frag::getShader(); - auto modelFadePixel = gpu::Shader::createPixel(std::string(model_fade_frag)); - auto modelUnlitFadePixel = gpu::Shader::createPixel(std::string(model_unlit_fade_frag)); - auto modelNormalMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_map_fade_frag)); - auto modelSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_specular_map_fade_frag)); - auto modelNormalSpecularMapFadePixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_fade_frag)); - auto modelShadowFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); - auto modelTranslucentFadePixel = gpu::Shader::createPixel(std::string(model_translucent_fade_frag)); - auto modelTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_fade_frag)); - auto simpleFadePixel = gpu::Shader::createPixel(std::string(simple_textured_fade_frag)); - auto simpleUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_textured_unlit_fade_frag)); - auto simpleTranslucentFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_fade_frag)); - auto simpleTranslucentUnlitFadePixel = gpu::Shader::createPixel(std::string(simple_transparent_textured_unlit_fade_frag)); + auto modelFadePixel = model_fade_frag::getShader(); + auto modelUnlitFadePixel = model_unlit_fade_frag::getShader(); + auto modelNormalMapFadePixel = model_normal_map_fade_frag::getShader(); + auto modelSpecularMapFadePixel = model_specular_map_fade_frag::getShader(); + auto modelNormalSpecularMapFadePixel = model_normal_specular_map_fade_frag::getShader(); + auto modelShadowFadePixel = model_shadow_fade_frag::getShader(); + auto modelTranslucentFadePixel = model_translucent_fade_frag::getShader(); + auto modelTranslucentUnlitFadePixel = model_translucent_unlit_fade_frag::getShader(); + auto simpleFadePixel = simple_textured_fade_frag::getShader(); + auto simpleUnlitFadePixel = simple_textured_unlit_fade_frag::getShader(); + auto simpleTranslucentFadePixel = simple_transparent_textured_fade_frag::getShader(); + auto simpleTranslucentUnlitFadePixel = simple_transparent_textured_unlit_fade_frag::getShader(); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, _4, _5); @@ -438,17 +438,17 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip void initForwardPipelines(render::ShapePlumber& plumber) { // Vertex shaders - auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); - auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); - auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); - auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto modelVertex = model_vert::getShader(); + auto modelNormalMapVertex = model_normal_map_vert::getShader(); + auto skinModelVertex = skin_model_vert::getShader(); + auto skinModelNormalMapVertex = skin_model_normal_map_vert::getShader(); // Pixel shaders - auto modelPixel = gpu::Shader::createPixel(std::string(forward_model_frag)); - auto modelUnlitPixel = gpu::Shader::createPixel(std::string(forward_model_unlit_frag)); - auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_map_frag)); - auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_specular_map_frag)); - auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(forward_model_normal_specular_map_frag)); + auto modelPixel = forward_model_frag::getShader(); + auto modelUnlitPixel = forward_model_unlit_frag::getShader(); + auto modelNormalMapPixel = forward_model_normal_map_frag::getShader(); + auto modelSpecularMapPixel = forward_model_specular_map_frag::getShader(); + auto modelNormalSpecularMapPixel = forward_model_normal_specular_map_frag::getShader(); using Key = render::ShapeKey; auto addPipeline = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, nullptr, nullptr); @@ -574,29 +574,29 @@ void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderAr } void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { - auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); - auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelVertex = model_shadow_vert::getShader(); + auto modelPixel = model_shadow_frag::getShader(); gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withoutSkinned().withoutFade(), modelProgram, state); - auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); - auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag)); + auto skinVertex = skin_model_shadow_vert::getShader(); + auto skinPixel = skin_model_shadow_frag::getShader(); gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withSkinned().withoutFade(), skinProgram, state); - auto modelFadeVertex = gpu::Shader::createVertex(std::string(model_shadow_fade_vert)); - auto modelFadePixel = gpu::Shader::createPixel(std::string(model_shadow_fade_frag)); + auto modelFadeVertex = model_shadow_fade_vert::getShader(); + auto modelFadePixel = model_shadow_fade_frag::getShader(); gpu::ShaderPointer modelFadeProgram = gpu::Shader::createProgram(modelFadeVertex, modelFadePixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withoutSkinned().withFade(), modelFadeProgram, state); - auto skinFadeVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_fade_vert)); - auto skinFadePixel = gpu::Shader::createPixel(std::string(skin_model_shadow_fade_frag)); + auto skinFadeVertex = skin_model_shadow_fade_vert::getShader(); + auto skinFadePixel = skin_model_shadow_fade_frag::getShader(); gpu::ShaderPointer skinFadeProgram = gpu::Shader::createProgram(skinFadeVertex, skinFadePixel); shapePlumber.addPipeline( ShapeKey::Filter::Builder().withSkinned().withFade(), diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index 80c97cf29f..48beda78bc 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -60,7 +60,7 @@ gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() { gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() { if (!_paintStencilPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(stencil_drawMask_frag); + auto ps = stencil_drawMask_frag::getShader(); auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 1786898e57..d6ec73da85 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -308,7 +308,7 @@ void diffuseProfileGPU(gpu::TexturePointer& profileMap, RenderArgs* args) { gpu::PipelinePointer makePipeline; { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(subsurfaceScattering_makeProfile_frag)); + auto ps = subsurfaceScattering_makeProfile_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -344,7 +344,7 @@ void diffuseScatterGPU(const gpu::TexturePointer& profileMap, gpu::TexturePointe gpu::PipelinePointer makePipeline; { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(subsurfaceScattering_makeLUT_frag)); + auto ps = subsurfaceScattering_makeLUT_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -382,7 +382,7 @@ void computeSpecularBeckmannGPU(gpu::TexturePointer& beckmannMap, RenderArgs* ar gpu::PipelinePointer makePipeline; { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(subsurfaceScattering_makeSpecularBeckmann_frag)); + auto ps = subsurfaceScattering_makeSpecularBeckmann_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -457,7 +457,7 @@ void DebugSubsurfaceScattering::configure(const Config& config) { gpu::PipelinePointer DebugSubsurfaceScattering::getScatteringPipeline() { if (!_scatteringPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(subsurfaceScattering_drawScattering_frag)); + auto ps = subsurfaceScattering_drawScattering_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index af6ff09082..afed9ee8fd 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -212,7 +212,7 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() { if (!_linearDepthPipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeLinearDepth_frag); + auto ps = surfaceGeometry_makeLinearDepth_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -239,7 +239,7 @@ const gpu::PipelinePointer& LinearDepthPass::getLinearDepthPipeline() { const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline() { if (!_downsamplePipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_downsampleDepthNormal_frag); + auto ps = surfaceGeometry_downsampleDepthNormal_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -540,7 +540,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext, const gpu::PipelinePointer& SurfaceGeometryPass::getCurvaturePipeline() { if (!_curvaturePipeline) { auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(surfaceGeometry_makeCurvature_frag); + auto ps = surfaceGeometry_makeCurvature_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/ToneMappingEffect.cpp b/libraries/render-utils/src/ToneMappingEffect.cpp index 6cb9541dae..e1abefd681 100644 --- a/libraries/render-utils/src/ToneMappingEffect.cpp +++ b/libraries/render-utils/src/ToneMappingEffect.cpp @@ -28,7 +28,7 @@ ToneMappingEffect::ToneMappingEffect() { } void ToneMappingEffect::init() { - auto blitPS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(toneMapping_frag)); + auto blitPS = toneMapping_frag::getShader(); auto blitVS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS(); auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(blitVS, blitPS)); diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index c0d01c2eaf..19a0419a5f 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -78,7 +78,7 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { if (!_keyLightPipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(zone_drawKeyLight_frag)); + auto ps = zone_drawKeyLight_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -99,7 +99,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() { if (!_ambientPipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(zone_drawAmbient_frag)); + auto ps = zone_drawAmbient_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -120,7 +120,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() { const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() { if (!_backgroundPipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(zone_drawSkybox_frag)); + auto ps = zone_drawSkybox_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 8449c58c7c..bcd14a4fbc 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -223,9 +223,9 @@ void Font::setupGPU() { // Setup render pipeline { - auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert)); - auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag)); - auto pixelShaderTransparent = gpu::Shader::createPixel(std::string(sdf_text3D_transparent_frag)); + auto vertexShader = sdf_text3D_vert::getShader(); + auto pixelShader = sdf_text3D_frag::getShader(); + auto pixelShaderTransparent = sdf_text3D_transparent_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::ShaderPointer programTransparent = gpu::Shader::createProgram(vertexShader, pixelShaderTransparent); diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 2be6f8fad2..0625179a6d 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -210,7 +210,7 @@ BlurGaussian::BlurGaussian(bool generateOutputFramebuffer, unsigned int downsamp gpu::PipelinePointer BlurGaussian::getBlurVPipeline() { if (!_blurVPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(blurGaussianV_frag)); + auto ps = blurGaussianV_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -232,7 +232,7 @@ gpu::PipelinePointer BlurGaussian::getBlurVPipeline() { gpu::PipelinePointer BlurGaussian::getBlurHPipeline() { if (!_blurHPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(blurGaussianH_frag)); + auto ps = blurGaussianH_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -324,7 +324,7 @@ BlurGaussianDepthAware::BlurGaussianDepthAware(bool generateOutputFramebuffer, c gpu::PipelinePointer BlurGaussianDepthAware::getBlurVPipeline() { if (!_blurVPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(blurGaussianDepthAwareV_frag)); + auto ps = blurGaussianDepthAwareV_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -347,7 +347,7 @@ gpu::PipelinePointer BlurGaussianDepthAware::getBlurVPipeline() { gpu::PipelinePointer BlurGaussianDepthAware::getBlurHPipeline() { if (!_blurHPipeline) { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::Shader::createPixel(std::string(blurGaussianDepthAwareH_frag)); + auto ps = blurGaussianDepthAwareH_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 36663a454a..f1e85dbb71 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -34,8 +34,8 @@ using namespace render; const gpu::PipelinePointer DrawSceneOctree::getDrawCellBoundsPipeline() { if (!_drawCellBoundsPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawCellBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawCellBounds_frag)); + auto vs = drawCellBounds_vert::getShader(); + auto ps = drawCellBounds_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -59,7 +59,7 @@ const gpu::PipelinePointer DrawSceneOctree::getDrawCellBoundsPipeline() { const gpu::PipelinePointer DrawSceneOctree::getDrawLODReticlePipeline() { if (!_drawLODReticlePipeline) { auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS(); - auto ps = gpu::Shader::createPixel(std::string(drawLODReticle_frag)); + auto ps = drawLODReticle_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -162,8 +162,8 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS const gpu::PipelinePointer DrawItemSelection::getDrawItemBoundPipeline() { if (!_drawItemBoundPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + auto vs = drawItemBounds_vert::getShader(); + auto ps = drawItemBounds_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 148e104453..a11e9b1a88 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -35,8 +35,8 @@ void DrawStatusConfig::dirtyHelper() { const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { if (!_drawItemBoundsPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + auto vs = drawItemBounds_vert::getShader(); + auto ps = drawItemBounds_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -63,8 +63,8 @@ const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { if (!_drawItemStatusPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemStatus_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemStatus_frag)); + auto vs = drawItemStatus_vert::getShader(); + auto ps = drawItemStatus_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index a60bf91062..88d38d1c66 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -155,8 +155,8 @@ void DrawLight::run(const RenderContextPointer& renderContext, const ItemBounds& const gpu::PipelinePointer DrawBounds::getPipeline() { if (!_boundsPipeline) { - auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); - auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + auto vs = drawItemBounds_vert::getShader(); + auto ps = drawItemBounds_frag::getShader(); gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index de37c505a6..83ada05fbd 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -23,65 +23,65 @@ #include -#include "simple_vert.h" -#include "simple_frag.h" -#include "simple_textured_frag.h" -#include "simple_textured_unlit_frag.h" +#include "render-utils/simple_vert.h" +#include "render-utils/simple_frag.h" +#include "render-utils/simple_textured_frag.h" +#include "render-utils/simple_textured_unlit_frag.h" -#include "deferred_light_vert.h" -#include "deferred_light_point_vert.h" -#include "deferred_light_spot_vert.h" +#include "render-utils/deferred_light_vert.h" +#include "render-utils/deferred_light_point_vert.h" +#include "render-utils/deferred_light_spot_vert.h" -#include "directional_ambient_light_frag.h" -#include "directional_skybox_light_frag.h" +#include "render-utils/directional_ambient_light_frag.h" +#include "render-utils/directional_skybox_light_frag.h" -#include "standardTransformPNTC_vert.h" -#include "standardDrawTexture_frag.h" +#include "render-utils/standardTransformPNTC_vert.h" +#include "render-utils/standardDrawTexture_frag.h" -#include "model_vert.h" -#include "model_shadow_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_shadow_vert.h" -#include "skin_model_normal_map_vert.h" +#include "render-utils/model_vert.h" +#include "render-utils/model_shadow_vert.h" +#include "render-utils/model_normal_map_vert.h" +#include "render-utils/model_lightmap_vert.h" +#include "render-utils/model_lightmap_normal_map_vert.h" +#include "render-utils/skin_model_vert.h" +#include "render-utils/skin_model_shadow_vert.h" +#include "render-utils/skin_model_normal_map_vert.h" -#include "model_frag.h" -#include "model_shadow_frag.h" -#include "model_normal_map_frag.h" -#include "model_normal_specular_map_frag.h" -#include "model_specular_map_frag.h" -#include "model_lightmap_frag.h" -#include "model_lightmap_normal_map_frag.h" -#include "model_lightmap_normal_specular_map_frag.h" -#include "model_lightmap_specular_map_frag.h" -#include "model_translucent_frag.h" +#include "render-utils/model_frag.h" +#include "render-utils/model_shadow_frag.h" +#include "render-utils/model_normal_map_frag.h" +#include "render-utils/model_normal_specular_map_frag.h" +#include "render-utils/model_specular_map_frag.h" +#include "render-utils/model_lightmap_frag.h" +#include "render-utils/model_lightmap_normal_map_frag.h" +#include "render-utils/model_lightmap_normal_specular_map_frag.h" +#include "render-utils/model_lightmap_specular_map_frag.h" +#include "render-utils/model_translucent_frag.h" -#include "textured_particle_frag.h" -#include "textured_particle_vert.h" +#include "entities-renderer/textured_particle_frag.h" +#include "entities-renderer/textured_particle_vert.h" -#include "overlay3D_vert.h" -#include "overlay3D_frag.h" +#include "render-utils/overlay3D_vert.h" +#include "render-utils/overlay3D_frag.h" -#include "skybox_vert.h" -#include "skybox_frag.h" +#include "model/skybox_vert.h" +#include "model/skybox_frag.h" -#include "DrawTransformUnitQuad_vert.h" -#include "DrawTexcoordRectTransformUnitQuad_vert.h" -#include "DrawViewportQuadTransformTexcoord_vert.h" -#include "DrawTexture_frag.h" -#include "DrawTextureOpaque_frag.h" -#include "DrawColoredTexture_frag.h" +#include "gpu/DrawTransformUnitQuad_vert.h" +#include "gpu/DrawTexcoordRectTransformUnitQuad_vert.h" +#include "gpu/DrawViewportQuadTransformTexcoord_vert.h" +#include "gpu/DrawTexture_frag.h" +#include "gpu/DrawTextureOpaque_frag.h" +#include "gpu/DrawColoredTexture_frag.h" -#include "sdf_text3D_vert.h" -#include "sdf_text3D_frag.h" +#include "render-utils/sdf_text3D_vert.h" +#include "render-utils/sdf_text3D_frag.h" -#include "paintStroke_vert.h" -#include "paintStroke_frag.h" +#include "entities-renderer/paintStroke_vert.h" +#include "entities-renderer/paintStroke_frag.h" -#include "polyvox_vert.h" -#include "polyvox_frag.h" +#include "entities-renderer/polyvox_vert.h" +#include "entities-renderer/polyvox_frag.h" // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { @@ -159,54 +159,54 @@ void QTestWindow::draw() { static std::once_flag once; std::call_once(once, [&]{ - testShaderBuild(sdf_text3D_vert, sdf_text3D_frag.h"; + testShaderBuild(sdf_text3D_vert::getSource(), sdf_text3D_frag::getSource()); - testShaderBuild(DrawTransformUnitQuad_vert, DrawTexture_frag.h"; - testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert, DrawTexture_frag.h"; - testShaderBuild(DrawViewportQuadTransformTexcoord_vert, DrawTexture_frag.h"; - testShaderBuild(DrawTransformUnitQuad_vert, DrawTextureOpaque_frag.h"; - testShaderBuild(DrawTransformUnitQuad_vert, DrawColoredTexture_frag.h"; + testShaderBuild(DrawTransformUnitQuad_vert::getSource(), DrawTexture_frag::getSource()); + testShaderBuild(DrawTexcoordRectTransformUnitQuad_vert::getSource(), DrawTexture_frag::getSource()); + testShaderBuild(DrawViewportQuadTransformTexcoord_vert::getSource(), DrawTexture_frag::getSource()); + testShaderBuild(DrawTransformUnitQuad_vert::getSource(), DrawTextureOpaque_frag::getSource()); + testShaderBuild(DrawTransformUnitQuad_vert::getSource(), DrawColoredTexture_frag::getSource()); - testShaderBuild(skybox_vert, skybox_frag.h"; - testShaderBuild(simple_vert, simple_frag.h"; - testShaderBuild(simple_vert, simple_textured_frag.h"; - testShaderBuild(simple_vert, simple_textured_unlit_frag.h"; - testShaderBuild(deferred_light_vert, directional_ambient_light_frag.h"; - testShaderBuild(deferred_light_vert, directional_skybox_light_frag.h"; - testShaderBuild(standardTransformPNTC_vert, standardDrawTexture_frag.h"; - testShaderBuild(standardTransformPNTC_vert, DrawTextureOpaque_frag.h"; + testShaderBuild(skybox_vert::getSource(), skybox_frag::getSource()); + testShaderBuild(simple_vert::getSource(), simple_frag::getSource()); + testShaderBuild(simple_vert::getSource(), simple_textured_frag::getSource()); + testShaderBuild(simple_vert::getSource(), simple_textured_unlit_frag::getSource()); + testShaderBuild(deferred_light_vert::getSource(), directional_ambient_light_frag::getSource()); + testShaderBuild(deferred_light_vert::getSource(), directional_skybox_light_frag::getSource()); + testShaderBuild(standardTransformPNTC_vert::getSource(), standardDrawTexture_frag::getSource()); + testShaderBuild(standardTransformPNTC_vert::getSource(), DrawTextureOpaque_frag::getSource()); - testShaderBuild(model_vert, model_frag.h"; - testShaderBuild(model_normal_map_vert, model_normal_map_frag.h"; - testShaderBuild(model_vert, model_specular_map_frag.h"; - testShaderBuild(model_normal_map_vert, model_normal_specular_map_frag.h"; - testShaderBuild(model_vert, model_translucent_frag.h"; - testShaderBuild(model_normal_map_vert, model_translucent_frag.h"; - testShaderBuild(model_lightmap_vert, model_lightmap_frag.h"; - testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_map_frag.h"; - testShaderBuild(model_lightmap_vert, model_lightmap_specular_map_frag.h"; - testShaderBuild(model_lightmap_normal_map_vert, model_lightmap_normal_specular_map_frag.h"; + testShaderBuild(model_vert::getSource(), model_frag::getSource()); + testShaderBuild(model_normal_map_vert::getSource(), model_normal_map_frag::getSource()); + testShaderBuild(model_vert::getSource(), model_specular_map_frag::getSource()); + testShaderBuild(model_normal_map_vert::getSource(), model_normal_specular_map_frag::getSource()); + testShaderBuild(model_vert::getSource(), model_translucent_frag::getSource()); + testShaderBuild(model_normal_map_vert::getSource(), model_translucent_frag::getSource()); + testShaderBuild(model_lightmap_vert::getSource(), model_lightmap_frag::getSource()); + testShaderBuild(model_lightmap_normal_map_vert::getSource(), model_lightmap_normal_map_frag::getSource()); + testShaderBuild(model_lightmap_vert::getSource(), model_lightmap_specular_map_frag::getSource()); + testShaderBuild(model_lightmap_normal_map_vert::getSource(), model_lightmap_normal_specular_map_frag::getSource()); - testShaderBuild(skin_model_vert, model_frag.h"; - testShaderBuild(skin_model_normal_map_vert, model_normal_map_frag.h"; - testShaderBuild(skin_model_vert, model_specular_map_frag.h"; - testShaderBuild(skin_model_normal_map_vert, model_normal_specular_map_frag.h"; - testShaderBuild(skin_model_vert, model_translucent_frag.h"; - testShaderBuild(skin_model_normal_map_vert, model_translucent_frag.h"; + testShaderBuild(skin_model_vert::getSource(), model_frag::getSource()); + testShaderBuild(skin_model_normal_map_vert::getSource(), model_normal_map_frag::getSource()); + testShaderBuild(skin_model_vert::getSource(), model_specular_map_frag::getSource()); + testShaderBuild(skin_model_normal_map_vert::getSource(), model_normal_specular_map_frag::getSource()); + testShaderBuild(skin_model_vert::getSource(), model_translucent_frag::getSource()); + testShaderBuild(skin_model_normal_map_vert::getSource(), model_translucent_frag::getSource()); - testShaderBuild(model_shadow_vert, model_shadow_frag.h"; - testShaderBuild(textured_particle_vert, textured_particle_frag.h"; + testShaderBuild(model_shadow_vert::getSource(), model_shadow_frag::getSource()); + testShaderBuild(textured_particle_vert::getSource(), textured_particle_frag::getSource()); /* FIXME: Bring back the ssao shader tests - testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag.h"; - testShaderBuild(gaussian_blur_horizontal_vert, gaussian_blur_frag.h"; - testShaderBuild(ambient_occlusion_vert, ambient_occlusion_frag.h"; - testShaderBuild(ambient_occlusion_vert, occlusion_blend_frag.h"; + testShaderBuild(gaussian_blur_vert::getSource()ical_vert::getSource(), gaussian_blur_frag::getSource()); + testShaderBuild(gaussian_blur_horizontal_vert::getSource(), gaussian_blur_frag::getSource()); + testShaderBuild(ambient_occlusion_vert::getSource(), ambient_occlusion_frag::getSource()); + testShaderBuild(ambient_occlusion_vert::getSource(), occlusion_blend_frag::getSource()); */ - testShaderBuild(overlay3D_vert, overlay3D_frag.h"; + testShaderBuild(overlay3D_vert::getSource(), overlay3D_frag::getSource()); - testShaderBuild(paintStroke_vert,paintStroke_frag.h"; - testShaderBuild(polyvox_vert, polyvox_frag.h"; + testShaderBuild(paintStroke_vert::getSource(),paintStroke_frag::getSource()); + testShaderBuild(polyvox_vert::getSource(), polyvox_frag::getSource()); }); _context.swapBuffers(this); diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index 2092bc0ea2..a7d12d677d 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -184,7 +184,7 @@ int main (int argc, char** argv) { srcStream.open(srcFilename, std::fstream::in); if (!srcStream.is_open()) { cerr << "Failed to open source file <" << srcFilename << ">" << endl; - return 0; + return 1; } auto scribe = std::make_shared(srcFilename, config); @@ -194,7 +194,7 @@ int main (int argc, char** argv) { int numErrors = scribe->scribe(destStringStream, srcStream, vars); if (numErrors) { cerr << "Scribe " << srcFilename << "> failed: " << numErrors << " errors." << endl; - return 0; + return 1; }; @@ -279,7 +279,7 @@ int main (int argc, char** argv) { headerFile << headerStringStream.str(); } else { cerr << "Scribe output file <" << headerFileName << "> failed to open." << endl; - return 0; + return 1; } } else { cerr << sourceStringStream.str(); @@ -310,7 +310,7 @@ int main (int argc, char** argv) { sourceFile.open(sourceFileName, std::fstream::out); if (!sourceFile.is_open()) { cerr << "Scribe output file <" << sourceFileName << "> failed to open." << endl; - return 0; + return 1; } sourceFile << sourceStringStream.str(); } else { @@ -323,7 +323,7 @@ int main (int argc, char** argv) { destFileStream.open(destFilename, std::fstream::out); if (!destFileStream.is_open()) { cerr << "Scribe output file <" << destFilename << "> failed to open." << endl; - return 0; + return 1; } destFileStream << destStringStream.str(); From 7b420d48e2cf1972d9398ee0032901dc9257cd39 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 17 Jan 2018 10:59:48 +0100 Subject: [PATCH 030/272] Generated shader files are now grouped in a sub-filter group in the project --- cmake/macros/AutoScribeShader.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index c92f7a3ffe..32b0bc3a2e 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -132,7 +132,7 @@ macro(AUTOSCRIBE_SHADER_LIB) if (WIN32) source_group("Shaders" FILES ${SHADER_INCLUDE_FILES}) source_group("Shaders" FILES ${SHADER_SOURCE_FILES}) - source_group("Shaders" FILES ${AUTOSCRIBE_SHADER_SRC}) + source_group("Shaders\\generated" FILES ${AUTOSCRIBE_SHADER_SRC}) endif() list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${SHADER_INCLUDE_FILES}) From 54690219e3a22846af3a6ff17353a6eda76a3df4 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 17 Jan 2018 11:12:37 +0100 Subject: [PATCH 031/272] Changed the way shader type is sent to Scribe --- cmake/macros/AutoScribeShader.cmake | 8 ++++---- tools/scribe/src/main.cpp | 29 ++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 32b0bc3a2e..313de1437d 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -54,13 +54,13 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) # Target dependant Custom rule on the SHADER_FILE if (APPLE) set(GLPROFILE MAC_GL) - set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (ANDROID) set(GLPROFILE LINUX_GL) - set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) # for an android build, we can't use the scribe that cmake would normally produce as a target, # since it's unrunnable by the cross-compiling build machine @@ -80,13 +80,13 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (UNIX) set(GLPROFILE LINUX_GL) - set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) else () set(GLPROFILE PC_GL) - set(SCRIBE_ARGS -c++ -${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) endif() diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index a7d12d677d..83c2fe287a 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -41,6 +41,7 @@ int main (int argc, char** argv) { GRAB_VAR_VALUE, GRAB_INCLUDE_PATH, GRAB_TARGET_NAME, + GRAB_SHADER_TYPE, EXIT, } mode = READY; @@ -78,15 +79,8 @@ int main (int argc, char** argv) { } else if (inputs.back() == "-c++") { makeCPlusPlus = true; mode = READY; - } else if (inputs.back() == "-vert") { - type = VERTEX; - mode = READY; - } else if (inputs.back() == "-frag") { - type = FRAGMENT; - mode = READY; - } else if (inputs.back() == "-geom") { - type = GEOMETRY; - mode = READY; + } else if (inputs.back() == "-T") { + mode = GRAB_SHADER_TYPE; } else { // just grabbed the source filename, stop parameter parsing srcFilename = inputs.back(); @@ -127,6 +121,21 @@ int main (int argc, char** argv) { } break; + case GRAB_SHADER_TYPE: + { + if (inputs.back() == "frag") { + type = FRAGMENT; + } else if (inputs.back() == "geom") { + type = GEOMETRY; + } else if (inputs.back() == "vert") { + type = VERTEX; + } else { + cerr << "Unrecognized shader type. Supported is vert, frag or geom" << endl; + } + mode = READY; + } + break; + case EXIT: { // THis shouldn't happen } @@ -145,6 +154,8 @@ int main (int argc, char** argv) { cerr << " -listVars : Will list the vars name and value in the standard output." << endl; cerr << " -showParseTree : Draw the tree obtained while parsing the source" << endl; cerr << " -c++ : Generate a c++ source file containing the output file stream stored as a char[] variable" << endl; + cerr << " -T vert/frag/geom : define the type of the shader. Defaults to VERTEX if not specified." << endl; + cerr << " This is necessary if the -c++ option is used." << endl; return 0; } From 157a229a4fd57c571a4c05b656bb6ab9efa09342 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 17 Jan 2018 15:09:32 +0100 Subject: [PATCH 032/272] Tried to add GLSL validation in scribe. Issues with determining the correct version... --- tools/scribe/src/main.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index 83c2fe287a..9bdcccbfa7 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -56,6 +56,7 @@ int main (int argc, char** argv) { static const char* shaderCreateString[] = { "Vertex", "Pixel", "Geometry" }; + std::string shaderStage{ "vert" }; for (int ii = 1; (mode != EXIT) && (ii < argc); ii++) { inputs.push_back(argv[ii]); @@ -124,10 +125,13 @@ int main (int argc, char** argv) { case GRAB_SHADER_TYPE: { if (inputs.back() == "frag") { + shaderStage = inputs.back(); type = FRAGMENT; } else if (inputs.back() == "geom") { + shaderStage = inputs.back(); type = GEOMETRY; } else if (inputs.back() == "vert") { + shaderStage = inputs.back(); type = VERTEX; } else { cerr << "Unrecognized shader type. Supported is vert, frag or geom" << endl; @@ -218,6 +222,36 @@ int main (int argc, char** argv) { scribe->displayTree(cerr, level); } + // This would be nice to implement but not sure how to handle GLSL version +#if 0 + // Check if we need to validate the code + auto validatorPath = getenv("SCRIBE_VALIDATOR"); + if (validatorPath) { + // Create temporary file with shader code + char tempFileNameStub[L_tmpnam]; + tmpnam(tempFileNameStub); + std::string tempFileName{ tempFileNameStub }; + tempFileName += "."; + tempFileName += shaderStage; + std::ofstream tempStream(tempFileName); + if (tempStream.is_open()) { + tempStream << destStringStream.str(); + tempStream.close(); + std::string validationCommand{ validatorPath }; + validationCommand += " "; + validationCommand += tempFileName; + cout << validationCommand << endl; + auto returnCode = system(validationCommand.c_str()); + if (returnCode != 0) { + cerr << "Scribe shader " << targetName << " validation error." << endl; + } + //remove(tempFileName.c_str()); + } else { + cerr << "Scribe is unable to write shader " << targetName << " to temporary file for validation." << endl; + } + } +#endif + if (makeCPlusPlus) { // Because there is a maximum size for literal strings declared in source we need to partition the // full source string stream into pages that seems to be around that value... From 604817bb59ee3fac1211bd2e743e1107def4556e Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 17 Jan 2018 19:21:58 +0100 Subject: [PATCH 033/272] Forgot to fix output custom command on all other platforms than Windows --- cmake/macros/AutoScribeShader.cmake | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 313de1437d..f15930a7c2 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -56,8 +56,7 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) set(GLPROFILE MAC_GL) set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) - add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) - add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (ANDROID) set(GLPROFILE LINUX_GL) set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) @@ -76,14 +75,12 @@ function(AUTOSCRIBE_SHADER SHADER_FILE) ") endif () - add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS}) - add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} COMMAND ${NATIVE_SCRIBE} ${SCRIBE_ARGS} DEPENDS ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) elseif (UNIX) set(GLPROFILE LINUX_GL) set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) - add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe) - add_custom_command(OUTPUT ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) + add_custom_command(OUTPUT ${SHADER_TARGET_HEADER} ${SHADER_TARGET_SOURCE} COMMAND scribe ${SCRIBE_ARGS} DEPENDS scribe ${SHADER_INCLUDE_FILES} ${SHADER_FILE}) else () set(GLPROFILE PC_GL) set(SCRIBE_ARGS -c++ -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) From 514eea5477e5aa73a01fb2e1a610f52787a63dff Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 17 Jan 2018 17:02:10 -0800 Subject: [PATCH 034/272] CR changes --- libraries/fbx/src/FBX.h | 2 +- libraries/fbx/src/OBJReader.cpp | 32 +++++++++++--------------------- libraries/fbx/src/OBJReader.h | 3 +-- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 0e85891398..56cda9d137 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -179,7 +179,7 @@ public: float emissiveIntensity{ 1.0f }; float ambientFactor{ 1.0f }; - float bumpMultiplier{ 1.0f }; // TODO: to be implemented + float bumpMultiplier { 1.0f }; // TODO: to be implemented QString materialID; QString name; diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 008b51b0be..8624efdd56 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -389,10 +389,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file QString parser = textureLine; while (parser.length() > 0) { if (parser.startsWith("-blend")) { // -blendu/-blendv - parser.remove(0, 11); // remove through "-blendu on " or "-blendu off" - if (parser[0] == ' ') { // extra character for space after off - parser.remove(0, 1); - } + int removeLength = parser[10] == 'f' ? 12 : 11; + parser.remove(0, removeLength); // remove through "-blendu on " or "-blendu off" #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -blendu/-blendv"; #endif @@ -407,18 +405,14 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -boost"; #endif } else if (parser.startsWith("-cc")) { - parser.remove(0, 7); // remove through "-cc on " or "-cc off" - if (parser[0] == ' ') { // extra character for space after off - parser.remove(0, 1); - } + int removeLength = parser[6] == 'f' ? 8 : 7; + parser.remove(0, removeLength); // remove through "-cc on " or "-cc off" #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -cc"; #endif } else if (parser.startsWith("-clamp")) { - parser.remove(0, 10); // remove through "-clamp on " or "-clamp off" - if (parser[0] == ' ') { // extra character for space after off - parser.remove(0, 1); - } + int removeLength = parser[9] == 'f' ? 11 : 10; + parser.remove(0, removeLength); // remove through "-clamp on " or "-clamp off" #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: Ignoring texture option -clamp"; #endif @@ -941,18 +935,17 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool applyRoughness = false; bool applyNonMetallic = false; bool fresnelOn = false; - bool fresnelOff = false; // Illumination model reference http://paulbourke.net/dataformats/mtl/ switch (objMaterial.illuminationModel) { case 0: // Color on and Ambient off - // We don't support ambient - do nothing? + // We don't support ambient = do nothing? break; case 1: // Color on and Ambient on - // We don't support ambient - do nothing? + // We don't support ambient = do nothing? break; case 2: // Highlight on - // Change specular intensity? + // Change specular intensity = do nothing for now? break; case 3: // Reflection on and Ray trace on applyShininess = true; @@ -969,7 +962,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, applyTransparency = true; applyNonMetallic = true; applyShininess = true; - fresnelOff = true; break; case 7: // Transparency: Refraction on and Reflection: Fresnel on and Ray trace on applyTransparency = true; @@ -990,8 +982,8 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, break; } - if (applyTransparency && fbxMaterial.opacity <= ILLUMINATION_MODEL_MIN_OPACITY) { - fbxMaterial.opacity = ILLUMINATION_MODEL_MIN_OPACITY; + if (applyTransparency) { + fbxMaterial.opacity = std::max(fbxMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY); } if (applyShininess) { modelMaterial->setRoughness(ILLUMINATION_MODEL_APPLY_SHININESS); @@ -1003,8 +995,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, } if (fresnelOn) { modelMaterial->setFresnel(glm::vec3(1.0f)); - } else if (fresnelOff) { - modelMaterial->setFresnel(glm::vec3(0.0f)); } modelMaterial->setOpacity(fbxMaterial.opacity); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 44382e3603..9083a69340 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -50,8 +50,7 @@ private: class OBJMaterialTextureOptions { public: - float bumpMultiplier; - OBJMaterialTextureOptions() : bumpMultiplier(1.0f) {} + float bumpMultiplier { 1.0f }; } ; // Materials and references to material names can come in any order, and different mesh parts can refer to the same material. From 26bf78fb5dbb58baf3f4251ca852518c29ef4660 Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 17 Jan 2018 18:30:31 -0800 Subject: [PATCH 035/272] first pass new entity selection edit tools wip --- .../system/libraries/entitySelectionTool.js | 4248 ++++------------- 1 file changed, 964 insertions(+), 3284 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index b8ba146757..220a7b7c70 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1,9 +1,10 @@ // -// entitySelectionToolClass.js +// entitySelectionTool.js // examples // // Created by Brad hefta-Gaub on 10/1/14. // Modified by Daniela Fontes * @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017 +// Modified by David Back on 1/9/2018 // Copyright 2014 High Fidelity, Inc. // // This script implements a class useful for building tools for editing entities. @@ -21,12 +22,6 @@ SPACE_WORLD = "world"; Script.include("./controllers.js"); -function objectTranslationPlanePoint(position, dimensions) { - var newPosition = { x: position.x, y: position.y, z: position.z }; - newPosition.y -= dimensions.y / 2.0; - return newPosition; -} - SelectionManager = (function() { var that = {}; @@ -53,10 +48,6 @@ SelectionManager = (function() { print("ERROR: entitySelectionTool.handleEntitySelectionToolUpdates - got malformed message: " + message); } - // if (message === 'callUpdate') { - // that._update(); - // } - if (messageParsed.method === "selectEntity") { if (wantDebug) { print("setting selection to " + messageParsed.entityID); @@ -235,20 +226,49 @@ function getRelativeCenterPosition(dimensions, registrationPoint) { SelectionDisplay = (function() { var that = {}; - var MINIMUM_DIMENSION = 0.001; + var COLOR_GREEN = { red:0, green:255, blue:0 }; + var COLOR_BLUE = { red:0, green:0, blue:255 }; + var COLOR_RED = { red:255, green:0, blue:0 }; - var GRABBER_DISTANCE_TO_SIZE_RATIO = 0.0075; + var GRABBER_TRANSLATE_ARROW_CONE_OFFSET = 0.3625; + var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 0.3; + var GRABBER_STRETCH_SPHERE_OFFSET = 0.2; + var GRABBER_SCALE_CUBE_OFFSET = 0.2; + + var GRABBER_SCALE_CUBE_IDLE_COLOR = { red:120, green:120, blue:120 }; + var GRABBER_SCALE_CUBE_SELECTED_COLOR = { red:0, green:0, blue:0 }; + var GRABBER_SCALE_EDGE_COLOR = { red:120, green:120, blue:120 }; + + var SCALE_MINIMUM_DIMENSION = 0.02; // These are multipliers for sizing the rotation degrees display while rotating an entity - var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.2; + var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.0; var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6; var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18; var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14; - var ROTATE_ARROW_WEST_NORTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-north.svg"; - var ROTATE_ARROW_WEST_SOUTH_URL = HIFI_PUBLIC_BUCKET + "images/rotate-arrow-west-south.svg"; + var TRANSLATE_DIRECTION = { + X : 0, + Y : 1, + Z : 2 + } - var showExtendedStretchHandles = false; + var ROTATE_DIRECTION = { + PITCH : 0, + YAW : 1, + ROLL : 2 + } + + var SCALE_DIRECTION = { + LBN : 0, + RBN : 1, + LBF : 2, + RBF : 3, + LTN : 4, + RTN : 5, + LTF : 6, + RTF : 7 + } var spaceMode = SPACE_LOCAL; var overlayNames = []; @@ -259,185 +279,95 @@ SelectionDisplay = (function() { getControllerWorldLocation(Controller.Standard.RightHand, true) ]; - var handleHoverColor = { - red: 224, - green: 67, - blue: 36 - }; - var handleHoverAlpha = 1.0; - - var innerSnapAngle = 22.5; // the angle which we snap to on the inner rotation tool - var innerRadius; - var outerRadius; - var yawHandleRotation; - var pitchHandleRotation; - var rollHandleRotation; - var yawCenter; - var pitchCenter; - var rollCenter; var rotZero; var rotationNormal; + var worldRotationX; + var worldRotationY; + var worldRotationZ; - var handleColor = { - red: 255, - green: 255, - blue: 255 - }; - var handleAlpha = 0.7; + var activeTool = null; + var grabberTools = {}; - var highlightedHandleColor = { - red: 183, - green: 64, - blue: 44 - }; - var highlightedHandleAlpha = 0.9; - - var previousHandle = false; - var previousHandleColor; - var previousHandleAlpha; - - var grabberSizeCorner = 0.025; // These get resized by updateHandleSizes(). - var grabberSizeEdge = 0.015; - var grabberSizeFace = 0.025; - var grabberAlpha = 1; - var grabberColorCorner = { - red: 120, - green: 120, - blue: 120 - }; - var grabberColorEdge = { - red: 0, - green: 0, - blue: 0 - }; - var grabberColorFace = { - red: 120, - green: 120, - blue: 120 - }; - var grabberColorCloner = { - red: 0, - green: 155, - blue: 0 - }; - var grabberLineWidth = 0.5; - var grabberSolid = true; - var grabberMoveUpPosition = Vec3.ZERO; - - var lightOverlayColor = { - red: 255, - green: 153, - blue: 0 - }; - - var grabberPropertiesCorner = { - position: Vec3.ZERO, - size: grabberSizeCorner, - color: grabberColorCorner, - alpha: 1, - solid: grabberSolid, + var grabberPropertiesTranslateArrowCones = { + shape: "Cone", + dimensions: { x:0.05, y:0.05, z:0.05 }, + solid: true, visible: false, - dashed: false, - drawInFront: true, - borderSize: 1.4 + ignoreRayIntersection: false, + drawInFront: true }; - - var grabberPropertiesEdge = { - position: Vec3.ZERO, - size: grabberSizeEdge, - color: grabberColorEdge, - alpha: 1, - solid: grabberSolid, + var grabberPropertiesTranslateArrowCylinders = { + shape: "Cylinder", + dimensions: { x:0.01, y:0.075, z:0.01 }, + solid: true, visible: false, - dashed: false, - drawInFront: true, - borderSize: 1.4 + ignoreRayIntersection: false, + drawInFront: true }; + var grabberTranslateXCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); + var grabberTranslateXCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); + Overlays.editOverlay(grabberTranslateXCone, { color : COLOR_RED }); + Overlays.editOverlay(grabberTranslateXCylinder, { color : COLOR_RED }); + var grabberTranslateYCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); + var grabberTranslateYCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); + Overlays.editOverlay(grabberTranslateYCone, { color : COLOR_GREEN }); + Overlays.editOverlay(grabberTranslateYCylinder, { color : COLOR_GREEN }); + var grabberTranslateZCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); + var grabberTranslateZCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); + Overlays.editOverlay(grabberTranslateZCone, { color : COLOR_BLUE }); + Overlays.editOverlay(grabberTranslateZCylinder, { color : COLOR_BLUE }); - var grabberPropertiesFace = { - position: Vec3.ZERO, - size: grabberSizeFace, - color: grabberColorFace, + var grabberPropertiesRotateRings = { + size: 0.5, alpha: 1, - solid: grabberSolid, + innerRadius: 0.9, + startAt: 0, + endAt: 360, + majorTickMarksAngle: 5, + majorTickMarksLength: 0.1, visible: false, - dashed: false, - drawInFront: true, - borderSize: 1.4 + ignoreRayIntersection: false, + drawInFront: true }; + var grabberRotatePitchRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); + Overlays.editOverlay(grabberRotatePitchRing, { + color : COLOR_RED, + majorTickMarksColor: COLOR_RED, + }); + var grabberRotateYawRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); + Overlays.editOverlay(grabberRotateYawRing, { + color : COLOR_GREEN, + majorTickMarksColor: COLOR_GREEN, + }); + var grabberRotateRollRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); + Overlays.editOverlay(grabberRotateRollRing, { + color : COLOR_BLUE, + majorTickMarksColor: COLOR_BLUE, + }); - var grabberPropertiesCloner = { - position: Vec3.ZERO, - size: grabberSizeCorner, - color: grabberColorCloner, + var grabberRotateCurrentRing = Overlays.addOverlay("circle3d", { + size: 0.5, alpha: 1, - solid: grabberSolid, + color: { red: 224, green: 67, blue: 36 }, + solid: true, + innerRadius: 0.9, visible: false, - dashed: false, - drawInFront: true, - borderSize: 1.4 - }; - - var spotLightLineProperties = { - color: lightOverlayColor - }; - - var highlightBox = Overlays.addOverlay("cube", { - position: Vec3.ZERO, - size: 1, - color: { - red: 90, - green: 90, - blue: 90 - }, - alpha: 1, - solid: false, - visible: false, - dashed: true, - ignoreRayIntersection: true, // this never ray intersects + ignoreRayIntersection: true, drawInFront: true }); - var selectionBox = Overlays.addOverlay("cube", { - position: Vec3.ZERO, - size: 1, - color: { - red: 255, - green: 0, - blue: 0 - }, - alpha: 1, - solid: false, - visible: false, - dashed: false - }); - - var selectionBoxes = []; - var rotationDegreesDisplay = Overlays.addOverlay("text3d", { - position: Vec3.ZERO, text: "", - color: { - red: 0, - green: 0, - blue: 0 - }, - backgroundColor: { - red: 255, - green: 255, - blue: 255 - }, + color: { red: 0, green: 0, blue: 0 }, + backgroundColor: { red: 255, green: 255, blue: 255 }, alpha: 0.7, backgroundAlpha: 0.7, visible: false, isFacingAvatar: true, drawInFront: true, ignoreRayIntersection: true, - dimensions: { - x: 0, - y: 0 - }, + dimensions: { x: 0, y: 0 }, lineHeight: 0.0, topMargin: 0, rightMargin: 0, @@ -445,461 +375,152 @@ SelectionDisplay = (function() { leftMargin: 0 }); - var grabberMoveUp = Overlays.addOverlay("image3d", { - url: HIFI_PUBLIC_BUCKET + "images/up-arrow.svg", - position: Vec3.ZERO, - color: handleColor, - alpha: handleAlpha, + var grabberPropertiesStretchSpheres = { + shape: "Sphere", + dimensions: { x:0.02, y:0.02, z:0.02 }, + solid: true, visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: true, + ignoreRayIntersection: false, drawInFront: true - }); - - // var normalLine = Overlays.addOverlay("line3d", { - // visible: true, - // start: { x: 0, y: 0, z: 0 }, - // end: { x: 0, y: 0, z: 0 }, - // color: { red: 255, green: 255, blue: 0 }, - // ignoreRayIntersection: true, - // }); - - var grabberLBN = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberRBN = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberLBF = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberRBF = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberLTN = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberRTN = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberLTF = Overlays.addOverlay("cube", grabberPropertiesCorner); - var grabberRTF = Overlays.addOverlay("cube", grabberPropertiesCorner); - - var grabberTOP = Overlays.addOverlay("cube", grabberPropertiesFace); - var grabberBOTTOM = Overlays.addOverlay("cube", grabberPropertiesFace); - var grabberLEFT = Overlays.addOverlay("cube", grabberPropertiesFace); - var grabberRIGHT = Overlays.addOverlay("cube", grabberPropertiesFace); - var grabberNEAR = Overlays.addOverlay("cube", grabberPropertiesFace); - var grabberFAR = Overlays.addOverlay("cube", grabberPropertiesFace); - - var grabberEdgeTR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeTL = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeTF = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeTN = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeBR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeBL = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeBF = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeBN = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeNR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeNL = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeFR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberEdgeFL = Overlays.addOverlay("cube", grabberPropertiesEdge); - - var grabberSpotLightCircle = Overlays.addOverlay("circle3d", { - color: lightOverlayColor, - isSolid: false, - visible: false - }); - var grabberSpotLightLineT = Overlays.addOverlay("line3d", spotLightLineProperties); - var grabberSpotLightLineB = Overlays.addOverlay("line3d", spotLightLineProperties); - var grabberSpotLightLineL = Overlays.addOverlay("line3d", spotLightLineProperties); - var grabberSpotLightLineR = Overlays.addOverlay("line3d", spotLightLineProperties); - - var grabberSpotLightCenter = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberSpotLightRadius = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberSpotLightL = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberSpotLightR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberSpotLightT = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberSpotLightB = Overlays.addOverlay("cube", grabberPropertiesEdge); - - var spotLightGrabberHandles = [ - grabberSpotLightCircle, grabberSpotLightCenter, grabberSpotLightRadius, - grabberSpotLightLineT, grabberSpotLightLineB, grabberSpotLightLineL, grabberSpotLightLineR, - grabberSpotLightT, grabberSpotLightB, grabberSpotLightL, grabberSpotLightR - ]; - - var grabberPointLightCircleX = Overlays.addOverlay("circle3d", { - rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - color: lightOverlayColor, - isSolid: false, - visible: false - }); - var grabberPointLightCircleY = Overlays.addOverlay("circle3d", { - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - color: lightOverlayColor, - isSolid: false, - visible: false - }); - var grabberPointLightCircleZ = Overlays.addOverlay("circle3d", { - rotation: Quat.fromPitchYawRollDegrees(0, 0, 0), - color: lightOverlayColor, - isSolid: false, - visible: false - }); - var grabberPointLightT = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberPointLightB = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberPointLightL = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberPointLightR = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberPointLightF = Overlays.addOverlay("cube", grabberPropertiesEdge); - var grabberPointLightN = Overlays.addOverlay("cube", grabberPropertiesEdge); - - var pointLightGrabberHandles = [ - grabberPointLightCircleX, grabberPointLightCircleY, grabberPointLightCircleZ, - grabberPointLightT, grabberPointLightB, grabberPointLightL, - grabberPointLightR, grabberPointLightF, grabberPointLightN - ]; - - var grabberCloner = Overlays.addOverlay("cube", grabberPropertiesCloner); - - var stretchHandles = [ - grabberLBN, - grabberRBN, - grabberLBF, - grabberRBF, - grabberLTN, - grabberRTN, - grabberLTF, - grabberRTF, - grabberTOP, - grabberBOTTOM, - grabberLEFT, - grabberRIGHT, - grabberNEAR, - grabberFAR, - grabberEdgeTR, - grabberEdgeTL, - grabberEdgeTF, - grabberEdgeTN, - grabberEdgeBR, - grabberEdgeBL, - grabberEdgeBF, - grabberEdgeBN, - grabberEdgeNR, - grabberEdgeNL, - grabberEdgeFR, - grabberEdgeFL, - - grabberSpotLightLineT, - grabberSpotLightLineB, - grabberSpotLightLineL, - grabberSpotLightLineR, - - grabberSpotLightCenter, - grabberSpotLightRadius, - grabberSpotLightL, - grabberSpotLightR, - grabberSpotLightT, - grabberSpotLightB, - - grabberPointLightT, - grabberPointLightB, - grabberPointLightL, - grabberPointLightR, - grabberPointLightF, - grabberPointLightN, - - grabberCloner - ]; - - - var baseOverlayAngles = { - x: 0, - y: 0, - z: 0 }; - var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles); - var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", { - position: { - x: 1, - y: 0, - z: 0 - }, - color: { - red: 51, - green: 152, - blue: 203 - }, + var grabberStretchXSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); + Overlays.editOverlay(grabberStretchXSphere, { color : COLOR_RED }); + var grabberStretchYSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); + Overlays.editOverlay(grabberStretchYSphere, { color : COLOR_GREEN }); + var grabberStretchZSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); + Overlays.editOverlay(grabberStretchZSphere, { color : COLOR_BLUE }); + + var grabberPropertiesStretchPanel = { + shape: "Quad", alpha: 0.5, + dimensions: { x:GRABBER_SCALE_CUBE_OFFSET * 2, y:GRABBER_SCALE_CUBE_OFFSET * 2, z:0.01 }, solid: true, visible: false, - width: 300, - height: 200, - rotation: baseOverlayRotation, - ignoreRayIntersection: true // always ignore this - }); + ignoreRayIntersection: true, + drawInFront: true, + } + var grabberStretchXPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); + Overlays.editOverlay(grabberStretchXPanel, { color : COLOR_RED }); + var grabberStretchYPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); + Overlays.editOverlay(grabberStretchYPanel, { color : COLOR_GREEN }); + var grabberStretchZPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); + Overlays.editOverlay(grabberStretchZPanel, { color : COLOR_BLUE }); - var yawOverlayAngles = { - x: 90, - y: 0, - z: 0 + var grabberPropertiesScaleCubes = { + size: 0.025, + color: GRABBER_SCALE_CUBE_IDLE_COLOR, + solid: true, + visible: false, + ignoreRayIntersection: false, + drawInFront: true, + borderSize: 1.4 }; - var yawOverlayRotation = Quat.fromVec3Degrees(yawOverlayAngles); - var pitchOverlayAngles = { - x: 0, - y: 90, - z: 0 - }; - var pitchOverlayRotation = Quat.fromVec3Degrees(pitchOverlayAngles); - var rollOverlayAngles = { - x: 0, - y: 180, - z: 0 - }; - var rollOverlayRotation = Quat.fromVec3Degrees(rollOverlayAngles); + var grabberScaleLBNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, -y, -z) + var grabberScaleRBNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, -y, z) + var grabberScaleLBFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, -y, -z) + var grabberScaleRBFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, -y, z) + var grabberScaleLTNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, y, -z) + var grabberScaleRTNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, y, z) + var grabberScaleLTFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, y, -z) + var grabberScaleRTFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, y, z) - var xRailOverlay = Overlays.addOverlay("line3d", { + var grabberPropertiesScaleEdge = { + color: GRABBER_SCALE_EDGE_COLOR, visible: false, - start: Vec3.ZERO, - end: Vec3.ZERO, - color: { - red: 255, - green: 0, - blue: 0 - }, - ignoreRayIntersection: true // always ignore this - }); - var yRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - start: Vec3.ZERO, - end: Vec3.ZERO, - color: { - red: 0, - green: 255, - blue: 0 - }, - ignoreRayIntersection: true // always ignore this - }); - var zRailOverlay = Overlays.addOverlay("line3d", { - visible: false, - start: Vec3.ZERO, - end: Vec3.ZERO, - color: { - red: 0, - green: 0, - blue: 255 - }, - ignoreRayIntersection: true // always ignore this - }); - - var rotateZeroOverlay = Overlays.addOverlay("line3d", { - visible: false, - start: Vec3.ZERO, - end: Vec3.ZERO, - color: { - red: 255, - green: 0, - blue: 0 - }, - ignoreRayIntersection: true // always ignore this - }); - - var rotateCurrentOverlay = Overlays.addOverlay("line3d", { - visible: false, - start: Vec3.ZERO, - end: Vec3.ZERO, - color: { - red: 0, - green: 0, - blue: 255 - }, - ignoreRayIntersection: true // always ignore this - }); - - - var rotateOverlayInner = Overlays.addOverlay("circle3d", { - position: Vec3.ZERO, - size: 1, - color: { - red: 51, - green: 152, - blue: 203 - }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, - hasTickMarks: true, - majorTickMarksAngle: innerSnapAngle, - minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, - minorTickMarksLength: 0, - majorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - }, - minorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - }, - ignoreRayIntersection: true // always ignore this - }); - - var rotateOverlayOuter = Overlays.addOverlay("circle3d", { - position: Vec3.ZERO, - size: 1, - color: { - red: 51, - green: 152, - blue: 203 - }, - alpha: 0.2, - solid: true, - visible: false, - rotation: yawOverlayRotation, - - hasTickMarks: true, - majorTickMarksAngle: 45.0, - minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, - minorTickMarksLength: 0.1, - majorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - }, - minorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - }, - ignoreRayIntersection: true // always ignore this - }); - - var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { - position: Vec3.ZERO, - size: 1, - color: { - red: 224, - green: 67, - blue: 36 - }, - alpha: 0.8, - solid: true, - visible: false, - rotation: yawOverlayRotation, - ignoreRayIntersection: true, // always ignore this - hasTickMarks: true, - majorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - }, - minorTickMarksColor: { - red: 0, - green: 0, - blue: 0 - } - }); - - var yawHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: Vec3.ZERO, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true - }); - - - var pitchHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: Vec3.ZERO, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true - }); - - - var rollHandle = Overlays.addOverlay("image3d", { - url: ROTATE_ARROW_WEST_NORTH_URL, - position: Vec3.ZERO, - color: handleColor, - alpha: handleAlpha, - visible: false, - size: 0.1, - scale: 0.1, - isFacingAvatar: false, - drawInFront: true - }); + ignoreRayIntersection: true, + drawInFront: true, + lineWidth: 0.2 + } + var grabberScaleTREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleTLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleTFEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleTNEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleBREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleBLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleBFEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleBNEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleNREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleNLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleFREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberScaleFLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); var allOverlays = [ - highlightBox, - selectionBox, - grabberMoveUp, - yawHandle, - pitchHandle, - rollHandle, - rotateOverlayInner, - rotateOverlayOuter, - rotateOverlayCurrent, - rotateZeroOverlay, - rotateCurrentOverlay, + grabberTranslateXCone, + grabberTranslateXCylinder, + grabberTranslateYCone, + grabberTranslateYCylinder, + grabberTranslateZCone, + grabberTranslateZCylinder, + grabberRotatePitchRing, + grabberRotateYawRing, + grabberRotateRollRing, + grabberRotateCurrentRing, rotationDegreesDisplay, - xRailOverlay, - yRailOverlay, - zRailOverlay, - baseOfEntityProjectionOverlay, - grabberSpotLightCircle, - grabberPointLightCircleX, - grabberPointLightCircleY, - grabberPointLightCircleZ + grabberStretchXSphere, + grabberStretchYSphere, + grabberStretchZSphere, + grabberStretchXPanel, + grabberStretchYPanel, + grabberStretchZPanel, + grabberScaleLBNCube, + grabberScaleRBNCube, + grabberScaleLBFCube, + grabberScaleRBFCube, + grabberScaleLTNCube, + grabberScaleRTNCube, + grabberScaleLTFCube, + grabberScaleRTFCube, + grabberScaleTREdge, + grabberScaleTLEdge, + grabberScaleTFEdge, + grabberScaleTNEdge, + grabberScaleBREdge, + grabberScaleBLEdge, + grabberScaleBFEdge, + grabberScaleBNEdge, + grabberScaleNREdge, + grabberScaleNLEdge, + grabberScaleFREdge, + grabberScaleFLEdge + ]; - ].concat(stretchHandles); - - overlayNames[highlightBox] = "highlightBox"; - overlayNames[selectionBox] = "selectionBox"; - overlayNames[baseOfEntityProjectionOverlay] = "baseOfEntityProjectionOverlay"; - overlayNames[grabberMoveUp] = "grabberMoveUp"; - overlayNames[grabberLBN] = "grabberLBN"; - overlayNames[grabberLBF] = "grabberLBF"; - overlayNames[grabberRBN] = "grabberRBN"; - overlayNames[grabberRBF] = "grabberRBF"; - overlayNames[grabberLTN] = "grabberLTN"; - overlayNames[grabberLTF] = "grabberLTF"; - overlayNames[grabberRTN] = "grabberRTN"; - overlayNames[grabberRTF] = "grabberRTF"; - - overlayNames[grabberTOP] = "grabberTOP"; - overlayNames[grabberBOTTOM] = "grabberBOTTOM"; - overlayNames[grabberLEFT] = "grabberLEFT"; - overlayNames[grabberRIGHT] = "grabberRIGHT"; - overlayNames[grabberNEAR] = "grabberNEAR"; - overlayNames[grabberFAR] = "grabberFAR"; - - overlayNames[grabberEdgeTR] = "grabberEdgeTR"; - overlayNames[grabberEdgeTL] = "grabberEdgeTL"; - overlayNames[grabberEdgeTF] = "grabberEdgeTF"; - overlayNames[grabberEdgeTN] = "grabberEdgeTN"; - overlayNames[grabberEdgeBR] = "grabberEdgeBR"; - overlayNames[grabberEdgeBL] = "grabberEdgeBL"; - overlayNames[grabberEdgeBF] = "grabberEdgeBF"; - overlayNames[grabberEdgeBN] = "grabberEdgeBN"; - overlayNames[grabberEdgeNR] = "grabberEdgeNR"; - overlayNames[grabberEdgeNL] = "grabberEdgeNL"; - overlayNames[grabberEdgeFR] = "grabberEdgeFR"; - overlayNames[grabberEdgeFL] = "grabberEdgeFL"; - - overlayNames[yawHandle] = "yawHandle"; - overlayNames[pitchHandle] = "pitchHandle"; - overlayNames[rollHandle] = "rollHandle"; - - overlayNames[rotateOverlayInner] = "rotateOverlayInner"; - overlayNames[rotateOverlayOuter] = "rotateOverlayOuter"; - overlayNames[rotateOverlayCurrent] = "rotateOverlayCurrent"; - - overlayNames[rotateZeroOverlay] = "rotateZeroOverlay"; - overlayNames[rotateCurrentOverlay] = "rotateCurrentOverlay"; - overlayNames[grabberCloner] = "grabberCloner"; - var activeTool = null; - var grabberTools = {}; + overlayNames[grabberTranslateXCone] = "grabberTranslateXCone"; + overlayNames[grabberTranslateXCylinder] = "grabberTranslateXCylinder"; + overlayNames[grabberTranslateYCone] = "grabberTranslateYCone"; + overlayNames[grabberTranslateYCylinder] = "grabberTranslateYCylinder"; + overlayNames[grabberTranslateZCone] = "grabberTranslateZCone"; + overlayNames[grabberTranslateZCylinder] = "grabberTranslateZCylinder"; + overlayNames[grabberRotatePitchRing] = "grabberRotatePitchRing"; + overlayNames[grabberRotateYawRing] = "grabberRotateYawRing"; + overlayNames[grabberRotateRollRing] = "grabberRotateRollRing"; + overlayNames[grabberRotateCurrentRing] = "grabberRotateCurrentRing"; + overlayNames[rotationDegreesDisplay] = "rotationDegreesDisplay"; + overlayNames[grabberStretchXSphere] = "grabberStretchXSphere"; + overlayNames[grabberStretchYSphere] = "grabberStretchYSphere"; + overlayNames[grabberStretchZSphere] = "grabberStretchZSphere"; + overlayNames[grabberStretchXPanel] = "grabberStretchXPanel"; + overlayNames[grabberStretchYPanel] = "grabberStretchYPanel"; + overlayNames[grabberStretchZPanel] = "grabberStretchZPanel"; + overlayNames[grabberScaleLBNCube] = "grabberScaleLBNCube"; + overlayNames[grabberScaleRBNCube] = "grabberScaleRBNCube"; + overlayNames[grabberScaleLBFCube] = "grabberScaleLBFCube"; + overlayNames[grabberScaleRBFCube] = "grabberScaleRBFCube"; + overlayNames[grabberScaleLTNCube] = "grabberScaleLTNCube"; + overlayNames[grabberScaleRTNCube] = "grabberScaleRTNCube"; + overlayNames[grabberScaleLTFCube] = "grabberScaleLTFCube"; + overlayNames[grabberScaleRTFCube] = "grabberScaleRTFCube"; + overlayNames[grabberScaleTREdge] = "grabberScaleTREdge"; + overlayNames[grabberScaleTLEdge] = "grabberScaleTLEdge"; + overlayNames[grabberScaleTFEdge] = "grabberScaleTFEdge"; + overlayNames[grabberScaleTNEdge] = "grabberScaleTNEdge"; + overlayNames[grabberScaleBREdge] = "grabberScaleBREdge"; + overlayNames[grabberScaleBLEdge] = "grabberScaleBLEdge"; + overlayNames[grabberScaleBFEdge] = "grabberScaleBFEdge"; + overlayNames[grabberScaleBNEdge] = "grabberScaleBNEdge"; + overlayNames[grabberScaleNREdge] = "grabberScaleNREdge"; + overlayNames[grabberScaleNLEdge] = "grabberScaleNLEdge"; + overlayNames[grabberScaleFREdge] = "grabberScaleFREdge"; + overlayNames[grabberScaleFLEdge] = "grabberScaleFLEdge"; // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. @@ -932,7 +553,6 @@ SelectionDisplay = (function() { that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand)); that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand)); - function controllerComputePickRay() { var controllerPose = getControllerWorldLocation(activeHand, true); if (controllerPose.valid && that.triggered) { @@ -942,2352 +562,389 @@ SelectionDisplay = (function() { return {origin: controllerPosition, direction: controllerDirection}; } } + function generalComputePickRay(x, y) { return controllerComputePickRay() || Camera.computePickRay(x, y); } + function addGrabberTool(overlay, tool) { grabberTools[overlay] = tool; return tool; } - // @param: toolHandle: The overlayID associated with the tool - // that correlates to the tool you wish to query. - // @note: If toolHandle is null or undefined then activeTool - // will be checked against those values as opposed to - // the tool registered under toolHandle. Null & Undefined - // are treated as separate values. - // @return: bool - Indicates if the activeTool is that queried. - function isActiveTool(toolHandle) { - if (!toolHandle) { - // Allow isActiveTool(null) and similar to return true if there's - // no active tool - return (activeTool === toolHandle); - } - - if (!grabberTools.hasOwnProperty(toolHandle)) { - print("WARNING: entitySelectionTool.isActiveTool - Encountered unknown grabberToolHandle: " + toolHandle + ". Tools should be egistered via addGrabberTool."); - // EARLY EXIT - return false; - } - - return (activeTool === grabberTools[ toolHandle ]); - } - - // @return string - The mode of the currently active tool; - // otherwise, "UNKNOWN" if there's no active tool. - function getMode() { - return (activeTool ? activeTool.mode : "UNKNOWN"); - } - - - that.cleanup = function() { - for (var i = 0; i < allOverlays.length; i++) { - Overlays.deleteOverlay(allOverlays[i]); - } - for (var j = 0; j < selectionBoxes.length; j++) { - Overlays.deleteOverlay(selectionBoxes[j]); - } - }; - - that.highlightSelectable = function(entityID) { - var properties = Entities.getEntityProperties(entityID); - Overlays.editOverlay(highlightBox, { - visible: true, - position: properties.boundingBox.center, - dimensions: properties.dimensions, - rotation: properties.rotation - }); - }; - - that.unhighlightSelectable = function(entityID) { - Overlays.editOverlay(highlightBox, { - visible: false - }); - }; - - that.select = function(entityID, event) { - var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - - lastCameraPosition = Camera.getPosition(); - lastCameraOrientation = Camera.getOrientation(); - - if (event !== false) { - pickRay = generalComputePickRay(event.x, event.y); - - var wantDebug = false; - if (wantDebug) { - print("select() with EVENT...... "); - print(" event.y:" + event.y); - Vec3.print(" current position:", properties.position); - } - - - } - - Overlays.editOverlay(highlightBox, { - visible: false - }); - - that.updateHandles(); - }; - - // Function: Calculate New Bound Extremes - // uses dot product to discover new top and bottom on the new referential (max and min) - that.calculateNewBoundExtremes = function(boundPointList, referenceVector) { - - if (boundPointList.length < 2) { - return [null, null]; - } - - var refMax = boundPointList[0]; - var refMin = boundPointList[1]; - - var dotMax = Vec3.dot(boundPointList[0], referenceVector); - var dotMin = Vec3.dot(boundPointList[1], referenceVector); - - if (dotMin > dotMax) { - dotMax = dotMin; - dotMin = Vec3.dot(boundPointList[0], referenceVector); - refMax = boundPointList[1]; - refMin = boundPointList[0]; - } - - for (var i = 2; i < boundPointList.length ; i++) { - var dotAux = Vec3.dot(boundPointList[i], referenceVector); - if (dotAux > dotMax) { - dotMax = dotAux; - refMax = boundPointList[i]; - } else if (dotAux < dotMin) { - dotMin = dotAux; - refMin = boundPointList[i]; - } - } - return [refMin, refMax]; - } - - // Function: Project Bounding Box Points - // Projects all 6 bounding box points: Top, Bottom, Left, Right, Near, Far (assumes center 0,0,0) onto - // one of the basis of the new avatar referencial - // dimensions - dimensions of the AABB (axis aligned bounding box) on the standard basis - // [1, 0, 0], [0, 1, 0], [0, 0, 1] - // v - projection vector - // rotateHandleOffset - offset for the rotation handle gizmo position - that.projectBoundingBoxPoints = function(dimensions, v, rotateHandleOffset) { - var projT_v = Vec3.dot(Vec3.multiply((dimensions.y / 2) + rotateHandleOffset, Vec3.UNIT_Y), v); - projT_v = Vec3.multiply(projT_v, v); - - var projB_v = Vec3.dot(Vec3.multiply(-(dimensions.y / 2) - rotateHandleOffset, Vec3.UNIT_Y), v); - projB_v = Vec3.multiply(projB_v, v); - - var projL_v = Vec3.dot(Vec3.multiply((dimensions.x / 2) + rotateHandleOffset, Vec3.UNIT_X), v); - projL_v = Vec3.multiply(projL_v, v); - - var projR_v = Vec3.dot(Vec3.multiply(-1.0 * (dimensions.x / 2) - 1.0 * rotateHandleOffset, Vec3.UNIT_X), v); - projR_v = Vec3.multiply(projR_v, v); - - var projN_v = Vec3.dot(Vec3.multiply((dimensions.z / 2) + rotateHandleOffset, Vec3.FRONT), v); - projN_v = Vec3.multiply(projN_v, v); - - var projF_v = Vec3.dot(Vec3.multiply(-1.0 * (dimensions.z / 2) - 1.0 * rotateHandleOffset, Vec3.FRONT), v); - projF_v = Vec3.multiply(projF_v, v); - - var projList = [projT_v, projB_v, projL_v, projR_v, projN_v, projF_v]; - - return that.calculateNewBoundExtremes(projList, v); - }; - - // FUNCTION: UPDATE ROTATION HANDLES - that.updateRotationHandles = function() { - var diagonal = (Vec3.length(SelectionManager.worldDimensions) / 2) * 1.1; - var halfDimensions = Vec3.multiply(SelectionManager.worldDimensions, 0.5); - var innerActive = false; - var innerAlpha = 0.2; - var outerAlpha = 0.2; - if (innerActive) { - innerAlpha = 0.5; - } else { - outerAlpha = 0.5; - } - // prev 0.05 - var rotateHandleOffset = 0.05; - - var boundsCenter, objectCenter; - - var dimensions, rotation; - if (spaceMode === SPACE_LOCAL) { - rotation = SelectionManager.localRotation; - } else { - rotation = SelectionManager.worldRotation; - } - objectCenter = SelectionManager.worldPosition; - dimensions = SelectionManager.worldDimensions; - var position = objectCenter; - - boundsCenter = objectCenter; - - var yawCorner; - var pitchCorner; - var rollCorner; - - var cameraPosition = Camera.getPosition(); - var look = Vec3.normalize(Vec3.subtract(cameraPosition, objectCenter)); - - // place yaw, pitch and roll rotations on the avatar referential - - var avatarReferential = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({ - x: 0, - y: 180, - z: 0 - })); - var upVector = Quat.getUp(avatarReferential); - var rightVector = Vec3.multiply(-1, Quat.getRight(avatarReferential)); - var frontVector = Quat.getFront(avatarReferential); - - // project all 6 bounding box points: Top, Bottom, Left, Right, Near, Far (assumes center 0,0,0) - // onto the new avatar referential - - // UP - var projUP = that.projectBoundingBoxPoints(dimensions, upVector, rotateHandleOffset); - // RIGHT - var projRIGHT = that.projectBoundingBoxPoints(dimensions, rightVector, rotateHandleOffset); - // FRONT - var projFRONT = that.projectBoundingBoxPoints(dimensions, frontVector, rotateHandleOffset); - - // YAW - yawCenter = Vec3.sum(boundsCenter, projUP[0]); - yawCorner = Vec3.sum(boundsCenter, Vec3.sum(Vec3.sum(projUP[0], projRIGHT[1]), projFRONT[1])); - - yawHandleRotation = Quat.lookAt( - yawCorner, - Vec3.sum(yawCorner, upVector), - Vec3.subtract(yawCenter,yawCorner)); - yawHandleRotation = Quat.multiply(Quat.angleAxis(45, upVector), yawHandleRotation); - - // PTCH - pitchCorner = Vec3.sum(boundsCenter, Vec3.sum(Vec3.sum(projUP[1], projRIGHT[0]), projFRONT[1])); - pitchCenter = Vec3.sum(boundsCenter, projRIGHT[0]); - - pitchHandleRotation = Quat.lookAt( - pitchCorner, - Vec3.sum(pitchCorner, rightVector), - Vec3.subtract(pitchCenter,pitchCorner)); - pitchHandleRotation = Quat.multiply(Quat.angleAxis(45, rightVector), pitchHandleRotation); - - // ROLL - rollCorner = Vec3.sum(boundsCenter, Vec3.sum(Vec3.sum(projUP[1], projRIGHT[1]), projFRONT[0])); - rollCenter = Vec3.sum(boundsCenter, projFRONT[0]); - - rollHandleRotation = Quat.lookAt( - rollCorner, - Vec3.sum(rollCorner, frontVector), - Vec3.subtract(rollCenter,rollCorner)); - rollHandleRotation = Quat.multiply(Quat.angleAxis(45, frontVector), rollHandleRotation); - - - var rotateHandlesVisible = true; - var rotationOverlaysVisible = false; - // note: Commented out as these are currently unused here; however, - // leaving them around as they document intent of state as it - // relates to modes that may be useful later. - // var translateHandlesVisible = true; - // var selectionBoxVisible = true; - var isPointLight = false; - if (SelectionManager.selections.length === 1) { - var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - isPointLight = (properties.type === "Light") && !properties.isSpotlight; - } - - if (isActiveTool(yawHandle) || isActiveTool(pitchHandle) || - isActiveTool(rollHandle) || isActiveTool(selectionBox) || isActiveTool(grabberCloner)) { - rotationOverlaysVisible = true; - rotateHandlesVisible = false; - // translateHandlesVisible = false; - // selectionBoxVisible = false; - } else if (isActiveTool(grabberMoveUp) || isPointLight) { - rotateHandlesVisible = false; - } else if (activeTool) { - // every other mode is a stretch mode... - rotateHandlesVisible = false; - // translateHandlesVisible = false; - } - - Overlays.editOverlay(rotateZeroOverlay, { - visible: rotationOverlaysVisible - }); - Overlays.editOverlay(rotateCurrentOverlay, { - visible: rotationOverlaysVisible - }); - - Overlays.editOverlay(yawHandle, { - visible: rotateHandlesVisible, - position: yawCorner, - rotation: yawHandleRotation - }); - Overlays.editOverlay(pitchHandle, { - visible: rotateHandlesVisible, - position: pitchCorner, - rotation: pitchHandleRotation - }); - Overlays.editOverlay(rollHandle, { - visible: rotateHandlesVisible, - position: rollCorner, - rotation: rollHandleRotation - }); - - - }; - - // FUNCTION: UPDATE HANDLE SIZES - that.updateHandleSizes = function() { - if (SelectionManager.hasSelection()) { - var diff = Vec3.subtract(SelectionManager.worldPosition, Camera.getPosition()); - var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 5; - var dimensions = SelectionManager.worldDimensions; - var avgDimension = (dimensions.x + dimensions.y + dimensions.z) / 3; - grabberSize = Math.min(grabberSize, avgDimension / 10); - - for (var i = 0; i < stretchHandles.length; i++) { - Overlays.editOverlay(stretchHandles[i], { - size: grabberSize - }); - } - var handleSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 7; - handleSize = Math.min(handleSize, avgDimension / 3); - - Overlays.editOverlay(yawHandle, { - scale: handleSize - }); - Overlays.editOverlay(pitchHandle, { - scale: handleSize - }); - Overlays.editOverlay(rollHandle, { - scale: handleSize - }); - var upDiff = Vec3.multiply(( - Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3), - Quat.getUp(MyAvatar.orientation) - ); - var pos = Vec3.sum(grabberMoveUpPosition, upDiff); - Overlays.editOverlay(grabberMoveUp, { - position: pos, - scale: handleSize / 1.25 - }); - } - }; - Script.update.connect(that.updateHandleSizes); - - // FUNCTION: SET SPACE MODE - that.setSpaceMode = function(newSpaceMode) { - var wantDebug = false; - if (wantDebug) { - print("======> SetSpaceMode called. ========"); - } - - if (spaceMode !== newSpaceMode) { - if (wantDebug) { - print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode); - } - spaceMode = newSpaceMode; - that.updateHandles(); - } else if (wantDebug) { - print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " + spaceMode + " DesiredMode: " + newSpaceMode); - } - if (wantDebug) { - print("====== SetSpaceMode called. <========"); - } - }; - - // FUNCTION: TOGGLE SPACE MODE - that.toggleSpaceMode = function() { - var wantDebug = false; - if (wantDebug) { - print("========> ToggleSpaceMode called. ========="); - } - if ((spaceMode === SPACE_WORLD) && (SelectionManager.selections.length > 1)) { - if (wantDebug) { - print("Local space editing is not available with multiple selections"); - } - return; - } - if (wantDebug) { - print("PreToggle: " + spaceMode); - } - spaceMode = (spaceMode === SPACE_LOCAL) ? SPACE_WORLD : SPACE_LOCAL; - that.updateHandles(); - if (wantDebug) { - print("PostToggle: " + spaceMode); - print("======== ToggleSpaceMode called. <========="); - } - }; - - // FUNCTION: UNSELECT ALL - // TODO?: Needs implementation - that.unselectAll = function() {}; - - // FUNCTION: UPDATE HANDLES - that.updateHandles = function() { - var wantDebug = false; - if (wantDebug) { - print("======> Update Handles ======="); - print(" Selections Count: " + SelectionManager.selections.length); - print(" SpaceMode: " + spaceMode); - print(" DisplayMode: " + getMode()); - } - if (SelectionManager.selections.length === 0) { - that.setOverlaysVisible(false); - return; - } - - // print(" Triggering updateRotationHandles"); - that.updateRotationHandles(); - - var rotation, dimensions, position, registrationPoint; - - if (spaceMode === SPACE_LOCAL) { - rotation = SelectionManager.localRotation; - dimensions = SelectionManager.localDimensions; - position = SelectionManager.localPosition; - registrationPoint = SelectionManager.localRegistrationPoint; - } else { - rotation = Quat.IDENTITY; - dimensions = SelectionManager.worldDimensions; - position = SelectionManager.worldPosition; - registrationPoint = SelectionManager.worldRegistrationPoint; - } - - var registrationPointDimensions = { - x: dimensions.x * registrationPoint.x, - y: dimensions.y * registrationPoint.y, - z: dimensions.z * registrationPoint.z - }; - - // Center of entity, relative to registration point - var center = getRelativeCenterPosition(dimensions, registrationPoint); - - // Distances in world coordinates relative to the registration point - var left = -registrationPointDimensions.x; - var right = dimensions.x - registrationPointDimensions.x; - var bottom = -registrationPointDimensions.y; - var top = dimensions.y - registrationPointDimensions.y; - var near = -registrationPointDimensions.z; - var far = dimensions.z - registrationPointDimensions.z; - var front = far; - - var worldTop = SelectionManager.worldDimensions.y / 2; - - var LBN = { - x: left, - y: bottom, - z: near - }; - var RBN = { - x: right, - y: bottom, - z: near - }; - var LBF = { - x: left, - y: bottom, - z: far - }; - var RBF = { - x: right, - y: bottom, - z: far - }; - var LTN = { - x: left, - y: top, - z: near - }; - var RTN = { - x: right, - y: top, - z: near - }; - var LTF = { - x: left, - y: top, - z: far - }; - var RTF = { - x: right, - y: top, - z: far - }; - - var TOP = { - x: center.x, - y: top, - z: center.z - }; - var BOTTOM = { - x: center.x, - y: bottom, - z: center.z - }; - var LEFT = { - x: left, - y: center.y, - z: center.z - }; - var RIGHT = { - x: right, - y: center.y, - z: center.z - }; - var NEAR = { - x: center.x, - y: center.y, - z: near - }; - var FAR = { - x: center.x, - y: center.y, - z: far - }; - - var EdgeTR = { - x: right, - y: top, - z: center.z - }; - var EdgeTL = { - x: left, - y: top, - z: center.z - }; - var EdgeTF = { - x: center.x, - y: top, - z: front - }; - var EdgeTN = { - x: center.x, - y: top, - z: near - }; - var EdgeBR = { - x: right, - y: bottom, - z: center.z - }; - var EdgeBL = { - x: left, - y: bottom, - z: center.z - }; - var EdgeBF = { - x: center.x, - y: bottom, - z: front - }; - var EdgeBN = { - x: center.x, - y: bottom, - z: near - }; - var EdgeNR = { - x: right, - y: center.y, - z: near - }; - var EdgeNL = { - x: left, - y: center.y, - z: near - }; - var EdgeFR = { - x: right, - y: center.y, - z: front - }; - var EdgeFL = { - x: left, - y: center.y, - z: front - }; - - LBN = Vec3.multiplyQbyV(rotation, LBN); - RBN = Vec3.multiplyQbyV(rotation, RBN); - LBF = Vec3.multiplyQbyV(rotation, LBF); - RBF = Vec3.multiplyQbyV(rotation, RBF); - LTN = Vec3.multiplyQbyV(rotation, LTN); - RTN = Vec3.multiplyQbyV(rotation, RTN); - LTF = Vec3.multiplyQbyV(rotation, LTF); - RTF = Vec3.multiplyQbyV(rotation, RTF); - - TOP = Vec3.multiplyQbyV(rotation, TOP); - BOTTOM = Vec3.multiplyQbyV(rotation, BOTTOM); - LEFT = Vec3.multiplyQbyV(rotation, LEFT); - RIGHT = Vec3.multiplyQbyV(rotation, RIGHT); - NEAR = Vec3.multiplyQbyV(rotation, NEAR); - FAR = Vec3.multiplyQbyV(rotation, FAR); - - EdgeTR = Vec3.multiplyQbyV(rotation, EdgeTR); - EdgeTL = Vec3.multiplyQbyV(rotation, EdgeTL); - EdgeTF = Vec3.multiplyQbyV(rotation, EdgeTF); - EdgeTN = Vec3.multiplyQbyV(rotation, EdgeTN); - EdgeBR = Vec3.multiplyQbyV(rotation, EdgeBR); - EdgeBL = Vec3.multiplyQbyV(rotation, EdgeBL); - EdgeBF = Vec3.multiplyQbyV(rotation, EdgeBF); - EdgeBN = Vec3.multiplyQbyV(rotation, EdgeBN); - EdgeNR = Vec3.multiplyQbyV(rotation, EdgeNR); - EdgeNL = Vec3.multiplyQbyV(rotation, EdgeNL); - EdgeFR = Vec3.multiplyQbyV(rotation, EdgeFR); - EdgeFL = Vec3.multiplyQbyV(rotation, EdgeFL); - - LBN = Vec3.sum(position, LBN); - RBN = Vec3.sum(position, RBN); - LBF = Vec3.sum(position, LBF); - RBF = Vec3.sum(position, RBF); - LTN = Vec3.sum(position, LTN); - RTN = Vec3.sum(position, RTN); - LTF = Vec3.sum(position, LTF); - RTF = Vec3.sum(position, RTF); - - TOP = Vec3.sum(position, TOP); - BOTTOM = Vec3.sum(position, BOTTOM); - LEFT = Vec3.sum(position, LEFT); - RIGHT = Vec3.sum(position, RIGHT); - NEAR = Vec3.sum(position, NEAR); - FAR = Vec3.sum(position, FAR); - - EdgeTR = Vec3.sum(position, EdgeTR); - EdgeTL = Vec3.sum(position, EdgeTL); - EdgeTF = Vec3.sum(position, EdgeTF); - EdgeTN = Vec3.sum(position, EdgeTN); - EdgeBR = Vec3.sum(position, EdgeBR); - EdgeBL = Vec3.sum(position, EdgeBL); - EdgeBF = Vec3.sum(position, EdgeBF); - EdgeBN = Vec3.sum(position, EdgeBN); - EdgeNR = Vec3.sum(position, EdgeNR); - EdgeNL = Vec3.sum(position, EdgeNL); - EdgeFR = Vec3.sum(position, EdgeFR); - EdgeFL = Vec3.sum(position, EdgeFL); - - var inModeRotate = (isActiveTool(yawHandle) || isActiveTool(pitchHandle) || isActiveTool(rollHandle)); - var inModeTranslate = (isActiveTool(selectionBox) || isActiveTool(grabberCloner) || isActiveTool(grabberMoveUp)); - var stretchHandlesVisible = !(inModeRotate || inModeTranslate) && (spaceMode === SPACE_LOCAL); - var extendedStretchHandlesVisible = (stretchHandlesVisible && showExtendedStretchHandles); - var cloneHandleVisible = !(inModeRotate || inModeTranslate); - if (wantDebug) { - print(" Set Non-Light Grabbers Visible - Norm: " + stretchHandlesVisible + " Ext: " + extendedStretchHandlesVisible); - } - var isSingleSelection = (SelectionManager.selections.length === 1); - - if (isSingleSelection) { - var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - var isLightSelection = (properties.type === "Light"); - if (isLightSelection) { - if (wantDebug) { - print(" Light Selection revoking Non-Light Grabbers Visibility!"); - } - stretchHandlesVisible = false; - extendedStretchHandlesVisible = false; - cloneHandleVisible = false; - if (properties.isSpotlight) { - that.setPointLightHandlesVisible(false); - - var distance = (properties.dimensions.z / 2) * Math.sin(properties.cutoff * (Math.PI / 180)); - var showEdgeSpotGrabbers = !(inModeTranslate || inModeRotate); - Overlays.editOverlay(grabberSpotLightCenter, { - position: position, - visible: false - }); - Overlays.editOverlay(grabberSpotLightRadius, { - position: NEAR, - rotation: rotation, - visible: showEdgeSpotGrabbers - }); - - Overlays.editOverlay(grabberSpotLightL, { - position: EdgeNL, - rotation: rotation, - visible: showEdgeSpotGrabbers - }); - Overlays.editOverlay(grabberSpotLightR, { - position: EdgeNR, - rotation: rotation, - visible: showEdgeSpotGrabbers - }); - Overlays.editOverlay(grabberSpotLightT, { - position: EdgeTN, - rotation: rotation, - visible: showEdgeSpotGrabbers - }); - Overlays.editOverlay(grabberSpotLightB, { - position: EdgeBN, - rotation: rotation, - visible: showEdgeSpotGrabbers - }); - Overlays.editOverlay(grabberSpotLightCircle, { - position: NEAR, - dimensions: { - x: distance, - y: distance, - z: 1 - }, - rotation: rotation, - visible: true - }); - - Overlays.editOverlay(grabberSpotLightLineT, { - start: position, - end: EdgeTN, - visible: true - }); - Overlays.editOverlay(grabberSpotLightLineB, { - start: position, - end: EdgeBN, - visible: true - }); - Overlays.editOverlay(grabberSpotLightLineR, { - start: position, - end: EdgeNR, - visible: true - }); - Overlays.editOverlay(grabberSpotLightLineL, { - start: position, - end: EdgeNL, - visible: true - }); - - } else { // ..it's a PointLight - that.setSpotLightHandlesVisible(false); - - var showEdgePointGrabbers = !inModeTranslate; - Overlays.editOverlay(grabberPointLightT, { - position: TOP, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightB, { - position: BOTTOM, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightL, { - position: LEFT, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightR, { - position: RIGHT, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightF, { - position: FAR, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightN, { - position: NEAR, - rotation: rotation, - visible: showEdgePointGrabbers - }); - Overlays.editOverlay(grabberPointLightCircleX, { - position: position, - rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, 90, 0)), - dimensions: { - x: properties.dimensions.z / 2.0, - y: properties.dimensions.z / 2.0, - z: 1 - }, - visible: true - }); - Overlays.editOverlay(grabberPointLightCircleY, { - position: position, - rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)), - dimensions: { - x: properties.dimensions.z / 2.0, - y: properties.dimensions.z / 2.0, - z: 1 - }, - visible: true - }); - Overlays.editOverlay(grabberPointLightCircleZ, { - position: position, - rotation: rotation, - dimensions: { - x: properties.dimensions.z / 2.0, - y: properties.dimensions.z / 2.0, - z: 1 - }, - visible: true - }); - } - } else { // ..it's not a light at all - that.setSpotLightHandlesVisible(false); - that.setPointLightHandlesVisible(false); - } - }// end of isSingleSelection - - - Overlays.editOverlay(grabberLBN, { - visible: stretchHandlesVisible, - rotation: rotation, - position: LBN - }); - Overlays.editOverlay(grabberRBN, { - visible: stretchHandlesVisible, - rotation: rotation, - position: RBN - }); - Overlays.editOverlay(grabberLBF, { - visible: stretchHandlesVisible, - rotation: rotation, - position: LBF - }); - Overlays.editOverlay(grabberRBF, { - visible: stretchHandlesVisible, - rotation: rotation, - position: RBF - }); - - Overlays.editOverlay(grabberLTN, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: LTN - }); - Overlays.editOverlay(grabberRTN, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: RTN - }); - Overlays.editOverlay(grabberLTF, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: LTF - }); - Overlays.editOverlay(grabberRTF, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: RTF - }); - - Overlays.editOverlay(grabberTOP, { - visible: stretchHandlesVisible, - rotation: rotation, - position: TOP - }); - Overlays.editOverlay(grabberBOTTOM, { - visible: stretchHandlesVisible, - rotation: rotation, - position: BOTTOM - }); - Overlays.editOverlay(grabberLEFT, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: LEFT - }); - Overlays.editOverlay(grabberRIGHT, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: RIGHT - }); - Overlays.editOverlay(grabberNEAR, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: NEAR - }); - Overlays.editOverlay(grabberFAR, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: FAR - }); - - Overlays.editOverlay(grabberCloner, { - visible: cloneHandleVisible, - rotation: rotation, - position: EdgeTR - }); - - var selectionBoxPosition = Vec3.multiplyQbyV(rotation, center); - selectionBoxPosition = Vec3.sum(position, selectionBoxPosition); - Overlays.editOverlay(selectionBox, { - position: selectionBoxPosition, - dimensions: dimensions, - rotation: rotation, - visible: !inModeRotate - }); - - // Create more selection box overlays if we don't have enough - var overlaysNeeded = SelectionManager.selections.length - selectionBoxes.length; - for (var i = 0; i < overlaysNeeded; i++) { - selectionBoxes.push( - Overlays.addOverlay("cube", { - position: { - x: 0, - y: 0, - z: 0 - }, - size: 1, - color: { - red: 255, - green: 153, - blue: 0 - }, - alpha: 1, - solid: false, - visible: false, - dashed: false, - ignoreRayIntersection: true - })); - } - - i = 0; - // Only show individual selections boxes if there is more than 1 selection - if (SelectionManager.selections.length > 1) { - for (; i < SelectionManager.selections.length; i++) { - var props = Entities.getEntityProperties(SelectionManager.selections[i]); - - // Adjust overlay position to take registrationPoint into account - // centeredRP = registrationPoint with range [-0.5, 0.5] - var centeredRP = Vec3.subtract(props.registrationPoint, { - x: 0.5, - y: 0.5, - z: 0.5 - }); - var offset = vec3Mult(props.dimensions, centeredRP); - offset = Vec3.multiply(-1, offset); - offset = Vec3.multiplyQbyV(props.rotation, offset); - var curBoxPosition = Vec3.sum(props.position, offset); - - var color = {red: 255, green: 128, blue: 0}; - if (i >= SelectionManager.selections.length - 1) { - color = {red: 255, green: 255, blue: 64}; - } - - Overlays.editOverlay(selectionBoxes[i], { - position: curBoxPosition, - color: color, - rotation: props.rotation, - dimensions: props.dimensions, - visible: true - }); - } - } - // Hide any remaining selection boxes - for (; i < selectionBoxes.length; i++) { - Overlays.editOverlay(selectionBoxes[i], { - visible: false - }); - } - - Overlays.editOverlay(grabberEdgeTR, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeTR - }); - Overlays.editOverlay(grabberEdgeTL, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeTL - }); - Overlays.editOverlay(grabberEdgeTF, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeTF - }); - Overlays.editOverlay(grabberEdgeTN, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeTN - }); - Overlays.editOverlay(grabberEdgeBR, { - visible: stretchHandlesVisible, - rotation: rotation, - position: EdgeBR - }); - Overlays.editOverlay(grabberEdgeBL, { - visible: stretchHandlesVisible, - rotation: rotation, - position: EdgeBL - }); - Overlays.editOverlay(grabberEdgeBF, { - visible: stretchHandlesVisible, - rotation: rotation, - position: EdgeBF - }); - Overlays.editOverlay(grabberEdgeBN, { - visible: stretchHandlesVisible, - rotation: rotation, - position: EdgeBN - }); - Overlays.editOverlay(grabberEdgeNR, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeNR - }); - Overlays.editOverlay(grabberEdgeNL, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeNL - }); - Overlays.editOverlay(grabberEdgeFR, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeFR - }); - Overlays.editOverlay(grabberEdgeFL, { - visible: extendedStretchHandlesVisible, - rotation: rotation, - position: EdgeFL - }); - - var grabberMoveUpOffset = 0.1; - var upVec = Quat.getUp(MyAvatar.orientation); - grabberMoveUpPosition = { - x: position.x + (grabberMoveUpOffset + worldTop) * upVec.x , - y: position.y+ (grabberMoveUpOffset + worldTop) * upVec.y, - z: position.z + (grabberMoveUpOffset + worldTop) * upVec.z - }; - Overlays.editOverlay(grabberMoveUp, { - visible: (!activeTool) || isActiveTool(grabberMoveUp) - }); - - Overlays.editOverlay(baseOfEntityProjectionOverlay, { - visible: !inModeRotate, - solid: true, - position: { - x: SelectionManager.worldPosition.x, - y: grid.getOrigin().y, - z: SelectionManager.worldPosition.z - }, - dimensions: { - x: SelectionManager.worldDimensions.x, - y: SelectionManager.worldDimensions.z - }, - rotation: Quat.fromPitchYawRollDegrees(90, 0, 0) - }); - - if (wantDebug) { - print("====== Update Handles <======="); - } - - }; - - function helperSetOverlaysVisibility(handleArray, isVisible) { - var numHandles = handleArray.length; - var visibilityUpdate = { visible: isVisible }; - for (var handleIndex = 0; handleIndex < numHandles; ++handleIndex) { - Overlays.editOverlay(handleArray[ handleIndex ], visibilityUpdate); - } - } - - // FUNCTION: SET OVERLAYS VISIBLE - that.setOverlaysVisible = function(isVisible) { - helperSetOverlaysVisibility(allOverlays, isVisible); - helperSetOverlaysVisibility(selectionBoxes, isVisible); - }; - - // FUNCTION: SET ROTATION HANDLES VISIBLE - that.setRotationHandlesVisible = function(isVisible) { - var visibilityUpdate = { visible: isVisible }; - Overlays.editOverlay(yawHandle, visibilityUpdate); - Overlays.editOverlay(pitchHandle, visibilityUpdate); - Overlays.editOverlay(rollHandle, visibilityUpdate); - }; - - // FUNCTION: SET STRETCH HANDLES VISIBLE - that.setStretchHandlesVisible = function(isVisible) { - helperSetOverlaysVisibility(stretchHandles, isVisible); - }; - - // FUNCTION: SET GRABBER MOVE UP VISIBLE - that.setGrabberMoveUpVisible = function(isVisible) { - Overlays.editOverlay(grabberMoveUp, { visible: isVisible }); - }; - - // FUNCTION: SET GRABBER TOOLS UP VISIBLE - that.setGrabberToolsVisible = function(isVisible) { - var visibilityUpdate = { visible: isVisible }; - for (var toolKey in grabberTools) { - if (!grabberTools.hasOwnProperty(toolKey)) { - // EARLY ITERATION EXIT--(On to the next one) - continue; - } - - Overlays.editOverlay(toolKey, visibilityUpdate); - } - }; - - // FUNCTION: SET POINT LIGHT HANDLES VISIBLE - that.setPointLightHandlesVisible = function(isVisible) { - helperSetOverlaysVisibility(pointLightGrabberHandles, isVisible); - }; - - // FUNCTION: SET SPOT LIGHT HANDLES VISIBLE - that.setSpotLightHandlesVisible = function(isVisible) { - helperSetOverlaysVisibility(spotLightGrabberHandles, isVisible); - }; - - // FUNCTION: UNSELECT - // TODO?: Needs implementation - that.unselect = function(entityID) {}; - - var initialXZPick = null; - var isConstrained = false; - var constrainMajorOnly = false; - var startPosition = null; - var duplicatedEntityIDs = null; - - // TOOL DEFINITION: TRANSLATE XZ TOOL - var translateXZTool = addGrabberTool(selectionBox,{ - mode: 'TRANSLATE_XZ', - pickPlanePosition: { x: 0, y: 0, z: 0 }, - greatestDimension: 0.0, - startingDistance: 0.0, - startingElevation: 0.0, - onBegin: function(event, pickRay, pickResult, doClone) { - var wantDebug = false; - if (wantDebug) { - print("================== TRANSLATE_XZ(Beg) -> ======================="); - Vec3.print(" pickRay", pickRay); - Vec3.print(" pickRay.origin", pickRay.origin); - Vec3.print(" pickResult.intersection", pickResult.intersection); - } - - SelectionManager.saveProperties(); - that.setRotationHandlesVisible(false); - that.setStretchHandlesVisible(false); - that.setGrabberMoveUpVisible(false); - - startPosition = SelectionManager.worldPosition; - - translateXZTool.pickPlanePosition = pickResult.intersection; - translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); - translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); - translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); - if (wantDebug) { - print(" longest dimension: " + translateXZTool.greatestDimension); - print(" starting distance: " + translateXZTool.startingDistance); - print(" starting elevation: " + translateXZTool.startingElevation); - } - - initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { - x: 0, - y: 1, - z: 0 - }); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt || doClone) { - duplicatedEntityIDs = []; - for (var otherEntityID in SelectionManager.savedProperties) { - var properties = SelectionManager.savedProperties[otherEntityID]; - if (!properties.locked) { - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties - }); - } - } - } else { - duplicatedEntityIDs = null; - } - - isConstrained = false; - if (wantDebug) { - print("================== TRANSLATE_XZ(End) <- ======================="); - } - }, - onEnd: function(event, reason) { - pushCommandForSelections(duplicatedEntityIDs); - - Overlays.editOverlay(xRailOverlay, { - visible: false - }); - Overlays.editOverlay(zRailOverlay, { - visible: false - }); - }, - elevation: function(origin, intersection) { - return (origin.y - intersection.y) / Vec3.distance(origin, intersection); - }, - onMove: function(event) { - var wantDebug = false; - pickRay = generalComputePickRay(event.x, event.y); - - var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { - x: 0, - y: 1, - z: 0 - }); - - // If the pick ray doesn't hit the pick plane in this direction, do nothing. - // this will happen when someone drags across the horizon from the side they started on. - if (!pick) { - if (wantDebug) { - print(" "+ translateXZTool.mode + "Pick ray does not intersect XZ plane."); - } - - // EARLY EXIT--(Invalid ray detected.) - return; - } - - var vector = Vec3.subtract(pick, initialXZPick); - - // If the mouse is too close to the horizon of the pick plane, stop moving - var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it - var elevation = translateXZTool.elevation(pickRay.origin, pick); - if (wantDebug) { - print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); - } - if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || - (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { - if (wantDebug) { - print(" "+ translateXZTool.mode + " - too close to horizon!"); - } - - // EARLY EXIT--(Don't proceed past the reached limit.) - return; - } - - // If the angular size of the object is too small, stop moving - var MIN_ANGULAR_SIZE = 0.01; // Radians - if (translateXZTool.greatestDimension > 0) { - var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); - if (wantDebug) { - print("Angular size = " + angularSize); - } - if (angularSize < MIN_ANGULAR_SIZE) { - return; - } - } - - // If shifted, constrain to one axis - if (event.isShifted) { - if (Math.abs(vector.x) > Math.abs(vector.z)) { - vector.z = 0; - } else { - vector.x = 0; - } - if (!isConstrained) { - Overlays.editOverlay(xRailOverlay, { - visible: true - }); - var xStart = Vec3.sum(startPosition, { - x: -10000, - y: 0, - z: 0 - }); - var xEnd = Vec3.sum(startPosition, { - x: 10000, - y: 0, - z: 0 - }); - var zStart = Vec3.sum(startPosition, { - x: 0, - y: 0, - z: -10000 - }); - var zEnd = Vec3.sum(startPosition, { - x: 0, - y: 0, - z: 10000 - }); - Overlays.editOverlay(xRailOverlay, { - start: xStart, - end: xEnd, - visible: true - }); - Overlays.editOverlay(zRailOverlay, { - start: zStart, - end: zEnd, - visible: true - }); - isConstrained = true; - } - } else { - if (isConstrained) { - Overlays.editOverlay(xRailOverlay, { - visible: false - }); - Overlays.editOverlay(zRailOverlay, { - visible: false - }); - isConstrained = false; - } - } - - constrainMajorOnly = event.isControl; - var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, SelectionManager.worldDimensions)); - vector = Vec3.subtract( - grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), - cornerPosition); - - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; - if (!properties) { - continue; - } - var newPosition = Vec3.sum(properties.position, { - x: vector.x, - y: 0, - z: vector.z - }); - Entities.editEntity(SelectionManager.selections[i], { - position: newPosition - }); - - if (wantDebug) { - print("translateXZ... "); - Vec3.print(" vector:", vector); - Vec3.print(" newPosition:", properties.position); - Vec3.print(" newPosition:", newPosition); - } - } - - SelectionManager._update(); - } - }); - - // GRABBER TOOL: GRABBER MOVE UP - var lastXYPick = null; - var upDownPickNormal = null; - addGrabberTool(grabberMoveUp, { - mode: "TRANSLATE_UP_DOWN", - onBegin: function(event, pickRay, pickResult) { - upDownPickNormal = Quat.getForward(lastCameraOrientation); - lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); - - SelectionManager.saveProperties(); - that.setGrabberMoveUpVisible(true); - that.setStretchHandlesVisible(false); - that.setRotationHandlesVisible(false); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt) { - duplicatedEntityIDs = []; - for (var otherEntityID in SelectionManager.savedProperties) { - var properties = SelectionManager.savedProperties[otherEntityID]; - if (!properties.locked) { - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties - }); - } - } - } else { - duplicatedEntityIDs = null; - } - }, - onEnd: function(event, reason) { - pushCommandForSelections(duplicatedEntityIDs); - }, - onMove: function(event) { - pickRay = generalComputePickRay(event.x, event.y); - - // translate mode left/right based on view toward entity - var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); - - var vector = Vec3.subtract(newIntersection, lastXYPick); - - // project vector onto avatar up vector - // we want the avatar referential not the camera. - var avatarUpVector = Quat.getUp(MyAvatar.orientation); - var dotVectorUp = Vec3.dot(vector, avatarUpVector); - vector = Vec3.multiply(dotVectorUp, avatarUpVector); - - - vector = grid.snapToGrid(vector); - - - - var wantDebug = false; - if (wantDebug) { - print("translateUpDown... "); - print(" event.y:" + event.y); - Vec3.print(" newIntersection:", newIntersection); - Vec3.print(" vector:", vector); - // Vec3.print(" newPosition:", newPosition); - } - for (var i = 0; i < SelectionManager.selections.length; i++) { - var id = SelectionManager.selections[i]; - var properties = SelectionManager.savedProperties[id]; - - var original = properties.position; - var newPosition = Vec3.sum(properties.position, vector); - - Entities.editEntity(id, { - position: newPosition - }); - } - - SelectionManager._update(); - } - }); - - // GRABBER TOOL: GRABBER CLONER - addGrabberTool(grabberCloner, { - mode: "CLONE", - onBegin: function(event, pickRay, pickResult) { - var doClone = true; - translateXZTool.onBegin(event,pickRay,pickResult,doClone); - }, - elevation: function (event) { - translateXZTool.elevation(event); - }, - - onEnd: function (event) { - translateXZTool.onEnd(event); - }, - - onMove: function (event) { - translateXZTool.onMove(event); - } - }); - - - // FUNCTION: VEC 3 MULT - var vec3Mult = function(v1, v2) { - return { - x: v1.x * v2.x, - y: v1.y * v2.y, - z: v1.z * v2.z - }; - }; - - // FUNCTION: MAKE STRETCH TOOL - // stretchMode - name of mode - // direction - direction to stretch in - // pivot - point to use as a pivot - // offset - the position of the overlay tool relative to the selections center position - // @return: tool obj - var makeStretchTool = function(stretchMode, direction, pivot, offset, customOnMove) { - // directionFor3DStretch - direction and pivot for 3D stretch - // distanceFor3DStretch - distance from the intersection point and the handController - // used to increase the scale taking into account the distance to the object - // DISTANCE_INFLUENCE_THRESHOLD - constant that holds the minimum distance where the - // distance to the object will influence the stretch/resize/scale - var directionFor3DStretch = getDirectionsFor3DStretch(stretchMode); - var distanceFor3DStretch = 0; - var DISTANCE_INFLUENCE_THRESHOLD = 1.2; - - - var signs = { - x: direction.x < 0 ? -1 : (direction.x > 0 ? 1 : 0), - y: direction.y < 0 ? -1 : (direction.y > 0 ? 1 : 0), - z: direction.z < 0 ? -1 : (direction.z > 0 ? 1 : 0) - }; - - var mask = { - x: Math.abs(direction.x) > 0 ? 1 : 0, - y: Math.abs(direction.y) > 0 ? 1 : 0, - z: Math.abs(direction.z) > 0 ? 1 : 0 - }; - - - var numDimensions = mask.x + mask.y + mask.z; - - var planeNormal = null; + function addGrabberTranslateTool(overlay, mode, direction) { + var pickNormal = null; var lastPick = null; - var lastPick3D = null; - var initialPosition = null; - var initialDimensions = null; - var initialIntersection = null; - var initialProperties = null; - var registrationPoint = null; - var deltaPivot = null; - var deltaPivot3D = null; - var pickRayPosition = null; - var pickRayPosition3D = null; - var rotation = null; - - var onBegin = function(event, pickRay, pickResult) { - var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - initialProperties = properties; - rotation = (spaceMode === SPACE_LOCAL) ? properties.rotation : Quat.IDENTITY; - - if (spaceMode === SPACE_LOCAL) { - rotation = SelectionManager.localRotation; - initialPosition = SelectionManager.localPosition; - initialDimensions = SelectionManager.localDimensions; - registrationPoint = SelectionManager.localRegistrationPoint; - } else { - rotation = SelectionManager.worldRotation; - initialPosition = SelectionManager.worldPosition; - initialDimensions = SelectionManager.worldDimensions; - registrationPoint = SelectionManager.worldRegistrationPoint; - } - - // Modify range of registrationPoint to be [-0.5, 0.5] - var centeredRP = Vec3.subtract(registrationPoint, { - x: 0.5, - y: 0.5, - z: 0.5 - }); - - // Scale pivot to be in the same range as registrationPoint - var scaledPivot = Vec3.multiply(0.5, pivot); - deltaPivot = Vec3.subtract(centeredRP, scaledPivot); - - var scaledOffset = Vec3.multiply(0.5, offset); - - // Offset from the registration point - offsetRP = Vec3.subtract(scaledOffset, centeredRP); - - // Scaled offset in world coordinates - var scaledOffsetWorld = vec3Mult(initialDimensions, offsetRP); - - pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); - - if (directionFor3DStretch) { - // pivot, offset and pickPlanePosition for 3D manipulation - var scaledPivot3D = Vec3.multiply(0.5, Vec3.multiply(1.0, directionFor3DStretch)); - deltaPivot3D = Vec3.subtract(centeredRP, scaledPivot3D); - - var scaledOffsetWorld3D = vec3Mult(initialDimensions, - Vec3.subtract(Vec3.multiply(0.5, Vec3.multiply(-1.0, directionFor3DStretch)), centeredRP)); - - pickRayPosition3D = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); - } - var start = null; - var end = null; - if ((numDimensions === 1) && mask.x) { - start = Vec3.multiplyQbyV(rotation, { - x: -10000, - y: 0, - z: 0 - }); - start = Vec3.sum(start, properties.position); - end = Vec3.multiplyQbyV(rotation, { - x: 10000, - y: 0, - z: 0 - }); - end = Vec3.sum(end, properties.position); - Overlays.editOverlay(xRailOverlay, { - start: start, - end: end, - visible: true - }); - } - if ((numDimensions === 1) && mask.y) { - start = Vec3.multiplyQbyV(rotation, { - x: 0, - y: -10000, - z: 0 - }); - start = Vec3.sum(start, properties.position); - end = Vec3.multiplyQbyV(rotation, { - x: 0, - y: 10000, - z: 0 - }); - end = Vec3.sum(end, properties.position); - Overlays.editOverlay(yRailOverlay, { - start: start, - end: end, - visible: true - }); - } - if ((numDimensions === 1) && mask.z) { - start = Vec3.multiplyQbyV(rotation, { - x: 0, - y: 0, - z: -10000 - }); - start = Vec3.sum(start, properties.position); - end = Vec3.multiplyQbyV(rotation, { - x: 0, - y: 0, - z: 10000 - }); - end = Vec3.sum(end, properties.position); - Overlays.editOverlay(zRailOverlay, { - start: start, - end: end, - visible: true - }); - } - if (numDimensions === 1) { - if (mask.x === 1) { - planeNormal = { - x: 0, - y: 1, - z: 0 - }; - } else if (mask.y === 1) { - planeNormal = { - x: 1, - y: 0, - z: 0 - }; - } else { - planeNormal = { - x: 0, - y: 1, - z: 0 - }; + var projectionVector = null; + addGrabberTool(overlay, { + mode: mode, + onBegin: function(event, pickRay, pickResult) { + if (direction === TRANSLATE_DIRECTION.X) { + pickNormal = { x:0, y:0, z:1 }; + } else if (direction === TRANSLATE_DIRECTION.Y) { + pickNormal = { x:1, y:0, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Z) { + pickNormal = { x:0, y:1, z:0 }; } - } else if (numDimensions === 2) { - if (mask.x === 0) { - planeNormal = { - x: 1, - y: 0, - z: 0 - }; - } else if (mask.y === 0) { - planeNormal = { - x: 0, - y: 1, - z: 0 - }; - } else { - planeNormal = { - x: 0, - y: 0, - z: 1 - }; - } - } - - planeNormal = Vec3.multiplyQbyV(rotation, planeNormal); - lastPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); - - var planeNormal3D = { - x: 0, - y: 0, - z: 0 - }; - if (directionFor3DStretch) { - lastPick3D = rayPlaneIntersection(pickRay, - pickRayPosition3D, - planeNormal3D); - distanceFor3DStretch = Vec3.length(Vec3.subtract(pickRayPosition3D, pickRay.origin)); - } - - SelectionManager.saveProperties(); - }; - var onEnd = function(event, reason) { - Overlays.editOverlay(xRailOverlay, { - visible: false - }); - Overlays.editOverlay(yRailOverlay, { - visible: false - }); - Overlays.editOverlay(zRailOverlay, { - visible: false - }); + var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + pickNormal = Vec3.multiplyQbyV(rotation, pickNormal); - pushCommandForSelections(); - }; + lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + + SelectionManager.saveProperties(); - var onMove = function(event) { - var proportional = (spaceMode === SPACE_WORLD) || event.isShifted || isActiveTool(grabberSpotLightRadius); - - var position, dimensions, rotation; - if (spaceMode === SPACE_LOCAL) { - position = SelectionManager.localPosition; - dimensions = SelectionManager.localDimensions; - rotation = SelectionManager.localRotation; - } else { - position = SelectionManager.worldPosition; - dimensions = SelectionManager.worldDimensions; - rotation = SelectionManager.worldRotation; - } - - var localDeltaPivot = deltaPivot; - var localSigns = signs; - - var pickRay = generalComputePickRay(event.x, event.y); - - // Are we using handControllers or Mouse - only relevant for 3D tools - var controllerPose = getControllerWorldLocation(activeHand, true); - var vector = null; - if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() && - controllerPose.valid && that.triggered && directionFor3DStretch) { - localDeltaPivot = deltaPivot3D; - - newPick = pickRay.origin; - - vector = Vec3.subtract(newPick, lastPick3D); - - vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); - - if (distanceFor3DStretch > DISTANCE_INFLUENCE_THRESHOLD) { - // Range of Motion - vector = Vec3.multiply(distanceFor3DStretch , vector); - } - - localSigns = directionFor3DStretch; - - } else { - newPick = rayPlaneIntersection(pickRay, - pickRayPosition, - planeNormal); - vector = Vec3.subtract(newPick, lastPick); - - vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); - - vector = vec3Mult(mask, vector); - - } - - if (customOnMove) { - var change = Vec3.multiply(-1, vec3Mult(localSigns, vector)); - customOnMove(vector, change); - } else { - vector = grid.snapToSpacing(vector); - - var changeInDimensions = Vec3.multiply(-1, vec3Mult(localSigns, vector)); - var newDimensions; - if (proportional) { - var absX = Math.abs(changeInDimensions.x); - var absY = Math.abs(changeInDimensions.y); - var absZ = Math.abs(changeInDimensions.z); - var pctChange = 0; - if (absX > absY && absX > absZ) { - pctChange = changeInDimensions.x / initialProperties.dimensions.x; - pctChange = changeInDimensions.x / initialDimensions.x; - } else if (absY > absZ) { - pctChange = changeInDimensions.y / initialProperties.dimensions.y; - pctChange = changeInDimensions.y / initialDimensions.y; - } else { - pctChange = changeInDimensions.z / initialProperties.dimensions.z; - pctChange = changeInDimensions.z / initialDimensions.z; + that.setGrabberTranslateXVisible(direction === TRANSLATE_DIRECTION.X); + that.setGrabberTranslateYVisible(direction === TRANSLATE_DIRECTION.Y); + that.setGrabberTranslateZVisible(direction === TRANSLATE_DIRECTION.Z); + that.setGrabberRotateVisible(false); + that.setGrabberStretchVisible(false); + that.setGrabberScaleVisible(false); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties + }); + } } - pctChange += 1.0; - newDimensions = Vec3.multiply(pctChange, initialDimensions); } else { - newDimensions = Vec3.sum(initialDimensions, changeInDimensions); + duplicatedEntityIDs = null; + } + }, + onEnd: function(event, reason) { + pushCommandForSelections(duplicatedEntityIDs); + }, + onMove: function(event) { + pickRay = generalComputePickRay(event.x, event.y); + + // translate mode left/right based on view toward entity + var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + var vector = Vec3.subtract(newIntersection, lastPick); + + if (direction === TRANSLATE_DIRECTION.X) { + projectionVector = { x:1, y:0, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Y) { + projectionVector = { x:0, y:1, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Z) { + projectionVector = { x:0, y:0, z:1 }; } - newDimensions.x = Math.max(newDimensions.x, MINIMUM_DIMENSION); - newDimensions.y = Math.max(newDimensions.y, MINIMUM_DIMENSION); - newDimensions.z = Math.max(newDimensions.z, MINIMUM_DIMENSION); - - var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(localDeltaPivot, changeInDimensions)); - var newPosition = Vec3.sum(initialPosition, changeInPosition); + var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + projectionVector = Vec3.multiplyQbyV(rotation, projectionVector); + var dotVector = Vec3.dot(vector, projectionVector); + vector = Vec3.multiply(dotVector, projectionVector); + vector = grid.snapToGrid(vector); + + var wantDebug = false; + if (wantDebug) { + print("translateUpDown... "); + print(" event.y:" + event.y); + Vec3.print(" newIntersection:", newIntersection); + Vec3.print(" vector:", vector); + // Vec3.print(" newPosition:", newPosition); + } + for (var i = 0; i < SelectionManager.selections.length; i++) { - Entities.editEntity(SelectionManager.selections[i], { - position: newPosition, + var id = SelectionManager.selections[i]; + var properties = SelectionManager.savedProperties[id]; + var newPosition = Vec3.sum(properties.position, vector); + Entities.editEntity(id, { position: newPosition }); + } + + SelectionManager._update(); + } + }); + } + + function addGrabberStretchTool(overlay, mode, direction) { + var pickNormal = null; + var lastPick = null; + var projectionVector = null; + var stretchPanel = null; + addGrabberTool(overlay, { + mode: mode, + onBegin: function(event, pickRay, pickResult) { + if (direction === TRANSLATE_DIRECTION.X) { + stretchPanel = grabberStretchXPanel; + pickNormal = { x:0, y:0, z:1 }; + } else if (direction === TRANSLATE_DIRECTION.Y) { + stretchPanel = grabberStretchYPanel; + pickNormal = { x:1, y:0, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Z) { + stretchPanel = grabberStretchZPanel; + pickNormal = { x:0, y:1, z:0 }; + } + + Overlays.editOverlay(stretchPanel, { visible:true }); + + var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + pickNormal = Vec3.multiplyQbyV(rotation, pickNormal); + + lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + + SelectionManager.saveProperties(); + + that.setGrabberTranslateVisible(false); + that.setGrabberRotateVisible(false); + that.setGrabberStretchXVisible(direction === TRANSLATE_DIRECTION.X); + that.setGrabberStretchYVisible(direction === TRANSLATE_DIRECTION.Y); + that.setGrabberStretchZVisible(direction === TRANSLATE_DIRECTION.Z); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties + }); + } + } + } else { + duplicatedEntityIDs = null; + } + }, + onEnd: function(event, reason) { + Overlays.editOverlay(stretchPanel, { visible:false }); + pushCommandForSelections(duplicatedEntityIDs); + }, + onMove: function(event) { + pickRay = generalComputePickRay(event.x, event.y); + + // translate mode left/right based on view toward entity + var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + var vector = Vec3.subtract(newIntersection, lastPick); + + if (direction === TRANSLATE_DIRECTION.X) { + projectionVector = { x:1, y:0, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Y) { + projectionVector = { x:0, y:1, z:0 }; + } else if (direction === TRANSLATE_DIRECTION.Z) { + projectionVector = { x:0, y:0, z:1 }; + } + + var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + projectionVector = Vec3.multiplyQbyV(rotation, projectionVector); + + var dotVector = Vec3.dot(vector, projectionVector); + vector = Vec3.multiply(dotVector, projectionVector); + vector = grid.snapToGrid(vector); + + var wantDebug = false; + if (wantDebug) { + print("translateUpDown... "); + print(" event.y:" + event.y); + Vec3.print(" newIntersection:", newIntersection); + Vec3.print(" vector:", vector); + // Vec3.print(" newPosition:", newPosition); + } + + for (var i = 0; i < SelectionManager.selections.length; i++) { + var id = SelectionManager.selections[i]; + var properties = SelectionManager.savedProperties[id]; + var newPosition = Vec3.sum(properties.position, vector); + var difference = Vec3.subtract(newPosition, SelectionManager.worldPosition); + var halfDifference = Vec3.multiply(difference, 0.5); + var quarterDifference = Vec3.multiply(halfDifference, 0.5); + var newDimensions = properties.dimensions; + var actualNewPosition = properties.position; + + if (direction == TRANSLATE_DIRECTION.X) { + newDimensions.x += halfDifference.x; + actualNewPosition.x += quarterDifference.x; + } else if (direction == TRANSLATE_DIRECTION.Y) { + newDimensions.y += halfDifference.y; + actualNewPosition.y += quarterDifference.y; + } else if (direction == TRANSLATE_DIRECTION.Z) { + newDimensions.z += halfDifference.z; + actualNewPosition.z += quarterDifference.z; + } + + Entities.editEntity(id, { + position: actualNewPosition, dimensions: newDimensions }); } - + + SelectionManager._update(); + } + }); + } + + function addGrabberScaleTool(overlay, mode, direction) { + var pickNormal = null; + var lastPick = null; + var selectedGrabber = null; + addGrabberTool(overlay, { + mode: mode, + onBegin: function(event, pickRay, pickResult) { + pickNormal = { x:-1, y:1, z:-1 }; + + if (direction === SCALE_DIRECTION.LBN) { + selectedGrabber = grabberScaleLBNCube; + } else if (direction === SCALE_DIRECTION.RBN) { + selectedGrabber = grabberScaleRBNCube; + } else if (direction === SCALE_DIRECTION.LBF) { + selectedGrabber = grabberScaleLBFCube; + } else if (direction === SCALE_DIRECTION.RBF) { + selectedGrabber = grabberScaleRBFCube; + } else if (direction === SCALE_DIRECTION.LTN) { + selectedGrabber = grabberScaleLTNCube; + } else if (direction === SCALE_DIRECTION.RTN) { + selectedGrabber = grabberScaleRTNCube; + } else if (direction === SCALE_DIRECTION.LTF) { + selectedGrabber = grabberScaleLTFCube; + } else if (direction === SCALE_DIRECTION.RTF) { + selectedGrabber = grabberScaleRTFCube; + } + Overlays.editOverlay(selectedGrabber, { color: GRABBER_SCALE_CUBE_SELECTED_COLOR }); + + lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + + SelectionManager.saveProperties(); + + that.setGrabberTranslateVisible(false); + that.setGrabberRotateVisible(false); + that.setGrabberStretchVisible(false); + that.setGrabberScaleVisible(true); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties + }); + } + } + } else { + duplicatedEntityIDs = null; + } + }, + onEnd: function(event, reason) { + Overlays.editOverlay(selectedGrabber, { color: GRABBER_SCALE_CUBE_IDLE_COLOR }); + pushCommandForSelections(duplicatedEntityIDs); + }, + onMove: function(event) { + pickRay = generalComputePickRay(event.x, event.y); + + // translate mode left/right based on view toward entity + var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); + var vector = Vec3.subtract(newIntersection, lastPick); + + var projectionVector; + if (direction === SCALE_DIRECTION.LBN) { + projectionVector = { x:-1, y:-1, z:-1 }; + } else if (direction === SCALE_DIRECTION.RBN) { + projectionVector = { x:-1, y:-1, z:1 }; + } else if (direction === SCALE_DIRECTION.LBF) { + projectionVector = { x:1, y:-1, z:-1 }; + } else if (direction === SCALE_DIRECTION.RBF) { + projectionVector = { x:1, y:-1, z:1 }; + } else if (direction === SCALE_DIRECTION.LTN) { + projectionVector = { x:-1, y:1, z:-1 }; + } else if (direction === SCALE_DIRECTION.RTN) { + projectionVector = { x:-1, y:1, z:1 }; + } else if (direction === SCALE_DIRECTION.LTF) { + projectionVector = { x:1, y:1, z:-1 }; + } else if (direction === SCALE_DIRECTION.RTF) { + projectionVector = { x:1, y:1, z:1 }; + } + + var dotVector = Vec3.dot(vector, projectionVector); + vector = Vec3.multiply(dotVector, projectionVector); + vector = grid.snapToGrid(vector); var wantDebug = false; if (wantDebug) { - print(stretchMode); - // Vec3.print(" newIntersection:", newIntersection); + print("translateUpDown... "); + print(" event.y:" + event.y); + Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); - // Vec3.print(" oldPOS:", oldPOS); - // Vec3.print(" newPOS:", newPOS); - Vec3.print(" changeInDimensions:", changeInDimensions); - Vec3.print(" newDimensions:", newDimensions); - - Vec3.print(" changeInPosition:", changeInPosition); - Vec3.print(" newPosition:", newPosition); + // Vec3.print(" newPosition:", newPosition); } + + for (var i = 0; i < SelectionManager.selections.length; i++) { + var id = SelectionManager.selections[i]; + var properties = SelectionManager.savedProperties[id]; + var newPosition = Vec3.sum(properties.position, vector); + var difference = Vec3.subtract(newPosition, SelectionManager.worldPosition); + var differenceAvg = (difference.x + difference.y + difference.z) / 3; + var newDimensionsX = properties.dimensions.x + differenceAvg; + var newDimensionsY = properties.dimensions.y + differenceAvg; + var newDimensionsZ = properties.dimensions.z + differenceAvg; + if (newDimensionsX < SCALE_MINIMUM_DIMENSION) { + var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsX; + newDimensionsX += differenceBelow; + newDimensionsY += differenceBelow; + newDimensionsZ += differenceBelow; + } + if (newDimensionsY < SCALE_MINIMUM_DIMENSION) { + var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsY; + newDimensionsX += differenceBelow; + newDimensionsY += differenceBelow; + newDimensionsZ += differenceBelow; + } + if (newDimensionsZ < SCALE_MINIMUM_DIMENSION) { + var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsZ; + newDimensionsX += differenceBelow; + newDimensionsY += differenceBelow; + newDimensionsZ += differenceBelow; + } + Entities.editEntity(id, { dimensions: { x:newDimensionsX, y:newDimensionsY, z:newDimensionsZ }}); + } + + SelectionManager._update(); } - - SelectionManager._update(); - };// End of onMove def - - return { - mode: stretchMode, - onBegin: onBegin, - onMove: onMove, - onEnd: onEnd - }; - }; - - // Direction for the stretch tool when using hand controller - var directionsFor3DGrab = { - LBN: { - x: 1, - y: 1, - z: 1 - }, - RBN: { - x: -1, - y: 1, - z: 1 - }, - LBF: { - x: 1, - y: 1, - z: -1 - }, - RBF: { - x: -1, - y: 1, - z: -1 - }, - LTN: { - x: 1, - y: -1, - z: 1 - }, - RTN: { - x: -1, - y: -1, - z: 1 - }, - LTF: { - x: 1, - y: -1, - z: -1 - }, - RTF: { - x: -1, - y: -1, - z: -1 - } - }; - - // FUNCTION: GET DIRECTION FOR 3D STRETCH - // Returns a vector with directions for the stretch tool in 3D using hand controllers - function getDirectionsFor3DStretch(mode) { - if (mode === "STRETCH_LBN") { - return directionsFor3DGrab.LBN; - } else if (mode === "STRETCH_RBN") { - return directionsFor3DGrab.RBN; - } else if (mode === "STRETCH_LBF") { - return directionsFor3DGrab.LBF; - } else if (mode === "STRETCH_RBF") { - return directionsFor3DGrab.RBF; - } else if (mode === "STRETCH_LTN") { - return directionsFor3DGrab.LTN; - } else if (mode === "STRETCH_RTN") { - return directionsFor3DGrab.RTN; - } else if (mode === "STRETCH_LTF") { - return directionsFor3DGrab.LTF; - } else if (mode === "STRETCH_RTF") { - return directionsFor3DGrab.RTF; - } else { - return null; - } - } - - - // FUNCTION: ADD STRETCH TOOL - function addStretchTool(overlay, mode, pivot, direction, offset, handleMove) { - if (!pivot) { - pivot = direction; - } - var tool = makeStretchTool(mode, direction, pivot, offset, handleMove); - - return addGrabberTool(overlay, tool); - } - - // FUNCTION: CUTOFF STRETCH FUNC - function cutoffStretchFunc(vector, change) { - vector = change; - var wantDebug = false; - if (wantDebug) { - Vec3.print("Radius stretch: ", vector); - } - var length = vector.x + vector.y + vector.z; - var props = SelectionManager.savedProperties[SelectionManager.selections[0]]; - - var radius = props.dimensions.z / 2; - var originalCutoff = props.cutoff; - - var originalSize = radius * Math.tan(originalCutoff * (Math.PI / 180)); - var newSize = originalSize + length; - var cutoff = Math.atan2(newSize, radius) * 180 / Math.PI; - - Entities.editEntity(SelectionManager.selections[0], { - cutoff: cutoff }); - - SelectionManager._update(); } - // FUNCTION: RADIUS STRETCH FUNC - function radiusStretchFunc(vector, change) { - var props = SelectionManager.savedProperties[SelectionManager.selections[0]]; - - // Find the axis being adjusted - var size; - if (Math.abs(change.x) > 0) { - size = props.dimensions.x + change.x; - } else if (Math.abs(change.y) > 0) { - size = props.dimensions.y + change.y; - } else if (Math.abs(change.z) > 0) { - size = props.dimensions.z + change.z; - } - - var newDimensions = { - x: size, - y: size, - z: size - }; - - Entities.editEntity(SelectionManager.selections[0], { - dimensions: newDimensions - }); - - SelectionManager._update(); - } - - // STRETCH TOOL DEF SECTION - addStretchTool(grabberNEAR, "STRETCH_NEAR", { - x: 0, - y: 0, - z: 1 - }, { - x: 0, - y: 0, - z: 1 - }, { - x: 0, - y: 0, - z: -1 - }); - addStretchTool(grabberFAR, "STRETCH_FAR", { - x: 0, - y: 0, - z: -1 - }, { - x: 0, - y: 0, - z: -1 - }, { - x: 0, - y: 0, - z: 1 - }); - addStretchTool(grabberTOP, "STRETCH_TOP", { - x: 0, - y: -1, - z: 0 - }, { - x: 0, - y: -1, - z: 0 - }, { - x: 0, - y: 1, - z: 0 - }); - addStretchTool(grabberBOTTOM, "STRETCH_BOTTOM", { - x: 0, - y: 1, - z: 0 - }, { - x: 0, - y: 1, - z: 0 - }, { - x: 0, - y: -1, - z: 0 - }); - addStretchTool(grabberRIGHT, "STRETCH_RIGHT", { - x: -1, - y: 0, - z: 0 - }, { - x: -1, - y: 0, - z: 0 - }, { - x: 1, - y: 0, - z: 0 - }); - addStretchTool(grabberLEFT, "STRETCH_LEFT", { - x: 1, - y: 0, - z: 0 - }, { - x: 1, - y: 0, - z: 0 - }, { - x: -1, - y: 0, - z: 0 - }); - - addStretchTool(grabberSpotLightRadius, "STRETCH_RADIUS", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, { - x: 0, - y: 0, - z: -1 - }); - addStretchTool(grabberSpotLightT, "STRETCH_CUTOFF_T", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: -1, - z: 0 - }, { - x: 0, - y: 1, - z: 0 - }, cutoffStretchFunc); - addStretchTool(grabberSpotLightB, "STRETCH_CUTOFF_B", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: 1, - z: 0 - }, { - x: 0, - y: -1, - z: 0 - }, cutoffStretchFunc); - addStretchTool(grabberSpotLightL, "STRETCH_CUTOFF_L", { - x: 0, - y: 0, - z: 0 - }, { - x: 1, - y: 0, - z: 0 - }, { - x: -1, - y: 0, - z: 0 - }, cutoffStretchFunc); - addStretchTool(grabberSpotLightR, "STRETCH_CUTOFF_R", { - x: 0, - y: 0, - z: 0 - }, { - x: -1, - y: 0, - z: 0 - }, { - x: 1, - y: 0, - z: 0 - }, cutoffStretchFunc); - - addStretchTool(grabberPointLightT, "STRETCH_RADIUS_T", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: -1, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, radiusStretchFunc); - addStretchTool(grabberPointLightB, "STRETCH_RADIUS_B", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: 1, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, radiusStretchFunc); - addStretchTool(grabberPointLightL, "STRETCH_RADIUS_L", { - x: 0, - y: 0, - z: 0 - }, { - x: 1, - y: 0, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, radiusStretchFunc); - addStretchTool(grabberPointLightR, "STRETCH_RADIUS_R", { - x: 0, - y: 0, - z: 0 - }, { - x: -1, - y: 0, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, radiusStretchFunc); - addStretchTool(grabberPointLightF, "STRETCH_RADIUS_F", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: 0, - z: -1 - }, { - x: 0, - y: 0, - z: 1 - }, radiusStretchFunc); - addStretchTool(grabberPointLightN, "STRETCH_RADIUS_N", { - x: 0, - y: 0, - z: 0 - }, { - x: 0, - y: 0, - z: 1 - }, { - x: 0, - y: 0, - z: -1 - }, radiusStretchFunc); - - addStretchTool(grabberLBN, "STRETCH_LBN", null, { - x: 1, - y: 0, - z: 1 - }, { - x: -1, - y: -1, - z: -1 - }); - addStretchTool(grabberRBN, "STRETCH_RBN", null, { - x: -1, - y: 0, - z: 1 - }, { - x: 1, - y: -1, - z: -1 - }); - addStretchTool(grabberLBF, "STRETCH_LBF", null, { - x: 1, - y: 0, - z: -1 - }, { - x: -1, - y: -1, - z: 1 - }); - addStretchTool(grabberRBF, "STRETCH_RBF", null, { - x: -1, - y: 0, - z: -1 - }, { - x: 1, - y: -1, - z: 1 - }); - addStretchTool(grabberLTN, "STRETCH_LTN", null, { - x: 1, - y: 0, - z: 1 - }, { - x: -1, - y: 1, - z: -1 - }); - addStretchTool(grabberRTN, "STRETCH_RTN", null, { - x: -1, - y: 0, - z: 1 - }, { - x: 1, - y: 1, - z: -1 - }); - addStretchTool(grabberLTF, "STRETCH_LTF", null, { - x: 1, - y: 0, - z: -1 - }, { - x: -1, - y: 1, - z: 1 - }); - addStretchTool(grabberRTF, "STRETCH_RTF", null, { - x: -1, - y: 0, - z: -1 - }, { - x: 1, - y: 1, - z: 1 - }); - - addStretchTool(grabberEdgeTR, "STRETCH_EdgeTR", null, { - x: 1, - y: 1, - z: 0 - }, { - x: 1, - y: 1, - z: 0 - }); - addStretchTool(grabberEdgeTL, "STRETCH_EdgeTL", null, { - x: -1, - y: 1, - z: 0 - }, { - x: -1, - y: 1, - z: 0 - }); - addStretchTool(grabberEdgeTF, "STRETCH_EdgeTF", null, { - x: 0, - y: 1, - z: -1 - }, { - x: 0, - y: 1, - z: -1 - }); - addStretchTool(grabberEdgeTN, "STRETCH_EdgeTN", null, { - x: 0, - y: 1, - z: 1 - }, { - x: 0, - y: 1, - z: 1 - }); - addStretchTool(grabberEdgeBR, "STRETCH_EdgeBR", null, { - x: -1, - y: 0, - z: 0 - }, { - x: 1, - y: -1, - z: 0 - }); - addStretchTool(grabberEdgeBL, "STRETCH_EdgeBL", null, { - x: 1, - y: 0, - z: 0 - }, { - x: -1, - y: -1, - z: 0 - }); - addStretchTool(grabberEdgeBF, "STRETCH_EdgeBF", null, { - x: 0, - y: 0, - z: -1 - }, { - x: 0, - y: -1, - z: -1 - }); - addStretchTool(grabberEdgeBN, "STRETCH_EdgeBN", null, { - x: 0, - y: 0, - z: 1 - }, { - x: 0, - y: -1, - z: 1 - }); - addStretchTool(grabberEdgeNR, "STRETCH_EdgeNR", null, { - x: -1, - y: 0, - z: 1 - }, { - x: 1, - y: 0, - z: -1 - }); - addStretchTool(grabberEdgeNL, "STRETCH_EdgeNL", null, { - x: 1, - y: 0, - z: 1 - }, { - x: -1, - y: 0, - z: -1 - }); - addStretchTool(grabberEdgeFR, "STRETCH_EdgeFR", null, { - x: -1, - y: 0, - z: -1 - }, { - x: 1, - y: 0, - z: 1 - }); - addStretchTool(grabberEdgeFL, "STRETCH_EdgeFL", null, { - x: 1, - y: 0, - z: -1 - }, { - x: -1, - y: 0, - z: 1 - }); - // FUNCTION: UPDATE ROTATION DEGREES OVERLAY - function updateRotationDegreesOverlay(angleFromZero, handleRotation, centerPosition) { - var wantDebug = false; - if (wantDebug) { - print("---> updateRotationDegreesOverlay ---"); - print(" AngleFromZero: " + angleFromZero); - print(" HandleRotation - X: " + handleRotation.x + " Y: " + handleRotation.y + " Z: " + handleRotation.z); - print(" CenterPos - " + centerPosition.x + " Y: " + centerPosition.y + " Z: " + centerPosition.z); - } - + function updateRotationDegreesOverlay(angleFromZero, direction, centerPosition) { var angle = angleFromZero * (Math.PI / 180); var position = { - x: Math.cos(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, - y: Math.sin(angle) * outerRadius * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, + x: Math.cos(angle) * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, + y: Math.sin(angle) * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, z: 0 }; - if (wantDebug) { - print(" Angle: " + angle); - print(" InitialPos: " + position.x + ", " + position.y + ", " + position.z); - } - - position = Vec3.multiplyQbyV(handleRotation, position); + if (direction === ROTATE_DIRECTION.PITCH) + position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, -90, 0), position); + else if (direction === ROTATE_DIRECTION.YAW) + position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(90, 0, 0), position); + else if (direction === ROTATE_DIRECTION.ROLL) + position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 180, 0), position); position = Vec3.sum(centerPosition, position); var overlayProps = { position: position, dimensions: { - x: innerRadius * ROTATION_DISPLAY_SIZE_X_MULTIPLIER, - y: innerRadius * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER + x: ROTATION_DISPLAY_SIZE_X_MULTIPLIER, + y: ROTATION_DISPLAY_SIZE_Y_MULTIPLIER }, - lineHeight: innerRadius * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER, + lineHeight: ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER, text: normalizeDegrees(-angleFromZero) + "°" }; - if (wantDebug) { - print(" TranslatedPos: " + position.x + ", " + position.y + ", " + position.z); - print(" OverlayDim - X: " + overlayProps.dimensions.x + " Y: " + overlayProps.dimensions.y + " Z: " + overlayProps.dimensions.z); - print(" OverlayLineHeight: " + overlayProps.lineHeight); - print(" OverlayText: " + overlayProps.text); - } - Overlays.editOverlay(rotationDegreesDisplay, overlayProps); - if (wantDebug) { - print("<--- updateRotationDegreesOverlay ---"); - } } // FUNCTION DEF: updateSelectionsRotation @@ -3322,260 +979,422 @@ SelectionDisplay = (function() { } } - function helperRotationHandleOnBegin(event, pickRay, rotAroundAxis, rotCenter, handleRotation) { + function addGrabberRotateTool(overlay, mode, direction) { + var initialPosition = SelectionManager.worldPosition; + var selectedGrabber = null; + addGrabberTool(overlay, { + mode: mode, + onBegin: function(event, pickRay, pickResult) { + SelectionManager.saveProperties(); + + that.setGrabberTranslateVisible(false); + that.setGrabberRotatePitchVisible(direction === ROTATE_DIRECTION.PITCH); + that.setGrabberRotateYawVisible(direction === ROTATE_DIRECTION.YAW); + that.setGrabberRotateRollVisible(direction === ROTATE_DIRECTION.ROLL); + that.setGrabberStretchVisible(false); + that.setGrabberScaleVisible(false); + + initialPosition = SelectionManager.worldPosition; + + if (direction === ROTATE_DIRECTION.PITCH) { + rotationNormal = { x: 1, y: 0, z: 0 }; + selectedGrabber = grabberRotatePitchRing; + } else if (direction === ROTATE_DIRECTION.YAW) { + rotationNormal = { x: 0, y: 1, z: 0 }; + selectedGrabber = grabberRotateYawRing; + } else if (direction === ROTATE_DIRECTION.ROLL) { + rotationNormal = { x: 0, y: 0, z: 1 }; + selectedGrabber = grabberRotateRollRing; + } + + Overlays.editOverlay(selectedGrabber, { hasTickMarks: true }); + + var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + rotationNormal = Vec3.multiplyQbyV(rotation, rotationNormal); + + var rotCenter = SelectionManager.worldPosition; + + Overlays.editOverlay(rotationDegreesDisplay, { visible: true }); + Overlays.editOverlay(grabberRotateCurrentRing, { visible: true }); + updateRotationDegreesOverlay(0, direction, rotCenter); + + // editOverlays may not have committed rotation changes. + // Compute zero position based on where the overlay will be eventually. + var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); + // In case of a parallel ray, this will be null, which will cause early-out + // in the onMove helper. + rotZero = result; + }, + onEnd: function(event, reason) { + Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); + Overlays.editOverlay(selectedGrabber, { hasTickMarks: false }); + Overlays.editOverlay(grabberRotateCurrentRing, { visible: false }); + pushCommandForSelections(); + }, + onMove: function(event) { + if (!rotZero) { + print("ERROR: entitySelectionTool.handleRotationHandleOnMove - Invalid RotationZero Specified (missed rotation target plane?)"); + + // EARLY EXIT + return; + } + var pickRay = generalComputePickRay(event.x, event.y); + var rotCenter = SelectionManager.worldPosition; + var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); + if (result) { + var centerToZero = Vec3.subtract(rotZero, rotCenter); + var centerToIntersect = Vec3.subtract(result, rotCenter); + // Note: orientedAngle which wants normalized centerToZero and centerToIntersect + // handles that internally, so it's to pass unnormalized vectors here. + var angleFromZero = Math.floor((Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal))); + var rotChange = Quat.angleAxis(angleFromZero, rotationNormal); + updateSelectionsRotation(rotChange); + updateRotationDegreesOverlay(-angleFromZero, direction, rotCenter); + + var worldRotation; + if (direction === ROTATE_DIRECTION.PITCH) { + worldRotation = worldRotationY; + } else if (direction === ROTATE_DIRECTION.YAW) { + worldRotation = worldRotationZ; + } else if (direction === ROTATE_DIRECTION.ROLL) { + worldRotation = worldRotationX; + } + + var startAtCurrent = 0; + var endAtCurrent = angleFromZero; + if (angleFromZero < 0) { + startAtCurrent = 360 + angleFromZero; + endAtCurrent = 360; + } + Overlays.editOverlay(grabberRotateCurrentRing, { + position: rotCenter, + rotation: worldRotation, + startAt: startAtCurrent, + endAt: endAtCurrent + }); + } + } + }); + } + + // @param: toolHandle: The overlayID associated with the tool + // that correlates to the tool you wish to query. + // @note: If toolHandle is null or undefined then activeTool + // will be checked against those values as opposed to + // the tool registered under toolHandle. Null & Undefined + // are treated as separate values. + // @return: bool - Indicates if the activeTool is that queried. + function isActiveTool(toolHandle) { + if (!toolHandle) { + // Allow isActiveTool(null) and similar to return true if there's + // no active tool + return (activeTool === toolHandle); + } + + if (!grabberTools.hasOwnProperty(toolHandle)) { + print("WARNING: entitySelectionTool.isActiveTool - Encountered unknown grabberToolHandle: " + toolHandle + ". Tools should be registered via addGrabberTool."); + // EARLY EXIT + return false; + } + + return (activeTool === grabberTools[ toolHandle ]); + } + + // @return string - The mode of the currently active tool; + // otherwise, "UNKNOWN" if there's no active tool. + function getMode() { + return (activeTool ? activeTool.mode : "UNKNOWN"); + } + + that.cleanup = function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }; + + that.highlightSelectable = function(entityID) { + var properties = Entities.getEntityProperties(entityID); + }; + + that.unhighlightSelectable = function(entityID) { + }; + + that.select = function(entityID, event) { + var properties = Entities.getEntityProperties(SelectionManager.selections[0]); + + lastCameraPosition = Camera.getPosition(); + lastCameraOrientation = Camera.getOrientation(); + + if (event !== false) { + pickRay = generalComputePickRay(event.x, event.y); + + var wantDebug = false; + if (wantDebug) { + print("select() with EVENT...... "); + print(" event.y:" + event.y); + Vec3.print(" current position:", properties.position); + } + } + + /* + Overlays.editOverlay(highlightBox, { + visible: false + }); + */ + + that.updateHandles(); + }; + + // FUNCTION: UPDATE HANDLE POSITION ROTATION + that.updateHandlePositionRotation = function() { + if (SelectionManager.hasSelection()) { + var worldPosition = SelectionManager.worldPosition; + var worldRotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + + var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); + worldRotationX = Quat.multiply(worldRotation, localRotationX); + var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); + worldRotationY = Quat.multiply(worldRotation, localRotationY); + var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); + worldRotationZ = Quat.multiply(worldRotation, localRotationZ); + + var cylinderXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET, y:0, z:0 })); + Overlays.editOverlay(grabberTranslateXCylinder, { position: cylinderXPos, rotation:worldRotationX }); + var coneXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CONE_OFFSET, y:0, z:0 })); + Overlays.editOverlay(grabberTranslateXCone, { position: coneXPos, rotation:worldRotationX }); + var stretchXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_STRETCH_SPHERE_OFFSET, y:0, z:0 })); + Overlays.editOverlay(grabberStretchXSphere, { position: stretchXPos }); + Overlays.editOverlay(grabberStretchXPanel, { position: stretchXPos, rotation:worldRotationY }); + + var cylinderYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET, z:0 })); + Overlays.editOverlay(grabberTranslateYCylinder, { position: cylinderYPos, rotation:worldRotationY }); + var coneYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CONE_OFFSET, z:0 })); + Overlays.editOverlay(grabberTranslateYCone, { position: coneYPos, rotation:worldRotationY }); + var stretchYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET, z:0 })); + Overlays.editOverlay(grabberStretchYSphere, { position: stretchYPos }); + Overlays.editOverlay(grabberStretchYPanel, { position: stretchYPos, rotation:worldRotationZ }); + + var cylinderZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET })); + Overlays.editOverlay(grabberTranslateZCylinder, { position: cylinderZPos, rotation:worldRotationZ }); + var coneZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CONE_OFFSET })); + Overlays.editOverlay(grabberTranslateZCone, { position: coneZPos, rotation:worldRotationZ }); + var stretchZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET })); + Overlays.editOverlay(grabberStretchZSphere, { position: stretchZPos }); + Overlays.editOverlay(grabberStretchZPanel, { position: stretchZPos, rotation:worldRotationX }); + + if (!isActiveTool(grabberRotatePitchRing)) { + Overlays.editOverlay(grabberRotatePitchRing, { position: SelectionManager.worldPosition, rotation: worldRotationY }); + } + if (!isActiveTool(grabberRotateYawRing)) { + Overlays.editOverlay(grabberRotateYawRing, { position: SelectionManager.worldPosition, rotation: worldRotationZ }); + } + if (!isActiveTool(grabberRotateRollRing)) { + Overlays.editOverlay(grabberRotateRollRing, { position: SelectionManager.worldPosition, rotation: worldRotationX }); + } + + var grabberScaleLBNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleLBNCube, { position:grabberScaleLBNCubePos }); + var grabberScaleRBNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleRBNCube, { position:grabberScaleRBNCubePos }); + var grabberScaleLBFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleLBFCube, { position:grabberScaleLBFCubePos }); + var grabberScaleRBFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleRBFCube, { position:grabberScaleRBFCubePos }); + var grabberScaleLTNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleLTNCube, { position:grabberScaleLTNCubePos }); + var grabberScaleRTNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleRTNCube, { position:grabberScaleRTNCubePos }); + var grabberScaleLTFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleLTFCube, { position:grabberScaleLTFCubePos }); + var grabberScaleRTFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); + Overlays.editOverlay(grabberScaleRTFCube, { position:grabberScaleRTFCubePos }); + + Overlays.editOverlay(grabberScaleTREdge, { start: grabberScaleRTNCubePos, end:grabberScaleRTFCubePos }); + Overlays.editOverlay(grabberScaleTLEdge, { start: grabberScaleLTNCubePos, end:grabberScaleLTFCubePos }); + Overlays.editOverlay(grabberScaleTFEdge, { start: grabberScaleLTFCubePos, end:grabberScaleRTFCubePos }); + Overlays.editOverlay(grabberScaleTNEdge, { start: grabberScaleLTNCubePos, end:grabberScaleRTNCubePos }); + Overlays.editOverlay(grabberScaleBREdge, { start: grabberScaleRBNCubePos, end:grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleBLEdge, { start: grabberScaleLBNCubePos, end:grabberScaleLBFCubePos }); + Overlays.editOverlay(grabberScaleBFEdge, { start: grabberScaleLBFCubePos, end:grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleBNEdge, { start: grabberScaleLBNCubePos, end:grabberScaleRBNCubePos }); + Overlays.editOverlay(grabberScaleNREdge, { start: grabberScaleRTNCubePos, end:grabberScaleRBNCubePos }); + Overlays.editOverlay(grabberScaleNLEdge, { start: grabberScaleLTNCubePos, end:grabberScaleLBNCubePos }); + Overlays.editOverlay(grabberScaleFREdge, { start: grabberScaleRTFCubePos, end:grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleFLEdge, { start: grabberScaleLTFCubePos, end:grabberScaleLBFCubePos }); + } + }; + Script.update.connect(that.updateHandlePositionRotation); + + // FUNCTION: SET SPACE MODE + that.setSpaceMode = function(newSpaceMode) { var wantDebug = false; if (wantDebug) { - print("================== " + getMode() + "(rotation helper onBegin) -> ======================="); + print("======> SetSpaceMode called. ========"); } - SelectionManager.saveProperties(); - that.setRotationHandlesVisible(false); - that.setStretchHandlesVisible(false); - that.setGrabberMoveUpVisible(false); - - initialPosition = SelectionManager.worldPosition; - rotationNormal = { x: 0, y: 0, z: 0 }; - rotationNormal[rotAroundAxis] = 1; - //get the correct axis according to the avatar referencial - var avatarReferential = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({ - x: 0, - y: 0, - z: 0 - })); - rotationNormal = Vec3.multiplyQbyV(avatarReferential, rotationNormal); - - // Size the overlays to the current selection size - var diagonal = (Vec3.length(SelectionManager.worldDimensions) / 2) * 1.1; - var halfDimensions = Vec3.multiply(SelectionManager.worldDimensions, 0.5); - innerRadius = diagonal; - outerRadius = diagonal * 1.15; - var innerAlpha = 0.2; - var outerAlpha = 0.2; - Overlays.editOverlay(rotateOverlayInner, { - visible: true, - rotation: handleRotation, - position: rotCenter, - size: innerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: innerAlpha - }); - - Overlays.editOverlay(rotateOverlayOuter, { - visible: true, - rotation: handleRotation, - position: rotCenter, - size: outerRadius, - innerRadius: 0.9, - startAt: 0, - endAt: 360, - alpha: outerAlpha - }); - - Overlays.editOverlay(rotateOverlayCurrent, { - visible: true, - rotation: handleRotation, - position: rotCenter, - size: outerRadius, - startAt: 0, - endAt: 0, - innerRadius: 0.9 - }); - - Overlays.editOverlay(rotationDegreesDisplay, { - visible: true - }); - - updateRotationDegreesOverlay(0, handleRotation, rotCenter); - - // editOverlays may not have committed rotation changes. - // Compute zero position based on where the overlay will be eventually. - var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); - // In case of a parallel ray, this will be null, which will cause early-out - // in the onMove helper. - rotZero = result; - + if (spaceMode !== newSpaceMode) { + if (wantDebug) { + print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode); + } + spaceMode = newSpaceMode; + that.updateHandles(); + } else if (wantDebug) { + print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " + spaceMode + " DesiredMode: " + newSpaceMode); + } if (wantDebug) { - print("================== " + getMode() + "(rotation helper onBegin) <- ======================="); + print("====== SetSpaceMode called. <========"); } - }// End_Function(helperRotationHandleOnBegin) + }; - function helperRotationHandleOnMove(event, rotAroundAxis, rotCenter, handleRotation) { - - if (!rotZero) { - print("ERROR: entitySelectionTool.handleRotationHandleOnMove - Invalid RotationZero Specified (missed rotation target plane?)"); - - // EARLY EXIT + // FUNCTION: UPDATE HANDLES + that.updateHandles = function() { + var wantDebug = false; + if (wantDebug) { + print("======> Update Handles ======="); + print(" Selections Count: " + SelectionManager.selections.length); + print(" SpaceMode: " + spaceMode); + print(" DisplayMode: " + getMode()); + } + if (SelectionManager.selections.length === 0) { + that.setOverlaysVisible(false); return; } - var wantDebug = false; - if (wantDebug) { - print("================== "+ getMode() + "(rotation helper onMove) -> ======================="); - Vec3.print(" rotZero: ", rotZero); - } - var pickRay = generalComputePickRay(event.x, event.y); - Overlays.editOverlay(selectionBox, { - visible: false - }); - Overlays.editOverlay(baseOfEntityProjectionOverlay, { - visible: false - }); + var isSingleSelection = (SelectionManager.selections.length === 1); + if (isSingleSelection) { + }// end of isSingleSelection - var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); - if (result) { - var centerToZero = Vec3.subtract(rotZero, rotCenter); - var centerToIntersect = Vec3.subtract(result, rotCenter); - if (wantDebug) { - Vec3.print(" RotationNormal: ", rotationNormal); - Vec3.print(" rotZero: ", rotZero); - Vec3.print(" rotCenter: ", rotCenter); - Vec3.print(" intersect: ", result); - Vec3.print(" centerToZero: ", centerToZero); - Vec3.print(" centerToIntersect: ", centerToIntersect); - } - // Note: orientedAngle which wants normalized centerToZero and centerToIntersect - // handles that internally, so it's to pass unnormalized vectors here. - var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal); - - var distanceFromCenter = Vec3.length(centerToIntersect); - var snapToInner = distanceFromCenter < innerRadius; - var snapAngle = snapToInner ? innerSnapAngle : 1.0; - angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - - - var rotChange = Quat.angleAxis(angleFromZero, rotationNormal); - updateSelectionsRotation(rotChange); - //present angle in avatar referencial - angleFromZero = -angleFromZero; - updateRotationDegreesOverlay(angleFromZero, handleRotation, rotCenter); - - // update the rotation display accordingly... - var startAtCurrent = 0; - var endAtCurrent = angleFromZero; - var startAtRemainder = angleFromZero; - var endAtRemainder = 360; - if (angleFromZero < 0) { - startAtCurrent = 360 + angleFromZero; - endAtCurrent = 360; - startAtRemainder = 0; - endAtRemainder = startAtCurrent; - } - if (snapToInner) { - Overlays.editOverlay(rotateOverlayOuter, { - startAt: 0, - endAt: 360 - }); - Overlays.editOverlay(rotateOverlayInner, { - startAt: startAtRemainder, - endAt: endAtRemainder - }); - Overlays.editOverlay(rotateOverlayCurrent, { - startAt: startAtCurrent, - endAt: endAtCurrent, - size: innerRadius, - majorTickMarksAngle: innerSnapAngle, - minorTickMarksAngle: 0, - majorTickMarksLength: -0.25, - minorTickMarksLength: 0 - }); - } else { - Overlays.editOverlay(rotateOverlayInner, { - startAt: 0, - endAt: 360 - }); - Overlays.editOverlay(rotateOverlayOuter, { - startAt: startAtRemainder, - endAt: endAtRemainder - }); - Overlays.editOverlay(rotateOverlayCurrent, { - startAt: startAtCurrent, - endAt: endAtCurrent, - size: outerRadius, - majorTickMarksAngle: 45.0, - minorTickMarksAngle: 5, - majorTickMarksLength: 0.25, - minorTickMarksLength: 0.1 - }); - } - }// End_If(results.intersects) + that.setGrabberTranslateXVisible(!activeTool || isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder)); + that.setGrabberTranslateYVisible(!activeTool || isActiveTool(grabberTranslateYCone) || isActiveTool(grabberTranslateYCylinder)); + that.setGrabberTranslateZVisible(!activeTool || isActiveTool(grabberTranslateZCone) || isActiveTool(grabberTranslateZCylinder)); + that.setGrabberRotatePitchVisible(!activeTool || isActiveTool(grabberRotatePitchRing)); + that.setGrabberRotateYawVisible(!activeTool || isActiveTool(grabberRotateYawRing)); + that.setGrabberRotateRollVisible(!activeTool || isActiveTool(grabberRotateRollRing)); + that.setGrabberStretchXVisible(!activeTool || isActiveTool(grabberStretchXSphere)); + that.setGrabberStretchYVisible(!activeTool || isActiveTool(grabberStretchYSphere)); + that.setGrabberStretchZVisible(!activeTool || isActiveTool(grabberStretchZSphere)); + that.setGrabberScaleVisible(!activeTool || isActiveTool(grabberScaleLBNCube) || isActiveTool(grabberScaleRBNCube) || isActiveTool(grabberScaleLBFCube) || isActiveTool(grabberScaleRBFCube) + || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube)); if (wantDebug) { - print("================== "+ getMode() + "(rotation helper onMove) <- ======================="); + print("====== Update Handles <======="); } - }// End_Function(helperRotationHandleOnMove) + }; - function helperRotationHandleOnEnd() { - var wantDebug = false; - if (wantDebug) { - print("================== " + getMode() + "(onEnd) -> ======================="); + // FUNCTION: SET OVERLAYS VISIBLE + that.setOverlaysVisible = function(isVisible) { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.editOverlay(allOverlays[i], { visible: isVisible }); } - Overlays.editOverlay(rotateOverlayInner, { - visible: false - }); - Overlays.editOverlay(rotateOverlayOuter, { - visible: false - }); - Overlays.editOverlay(rotateOverlayCurrent, { - visible: false - }); - Overlays.editOverlay(rotationDegreesDisplay, { - visible: false - }); + }; - pushCommandForSelections(); + // FUNCTION: SET GRABBER TRANSLATE VISIBLE + that.setGrabberTranslateVisible = function(isVisible) { + that.setGrabberTranslateXVisible(isVisible); + that.setGrabberTranslateYVisible(isVisible); + that.setGrabberTranslateZVisible(isVisible); + }; - if (wantDebug) { - print("================== " + getMode() + "(onEnd) <- ======================="); - } - }// End_Function(helperRotationHandleOnEnd) + that.setGrabberTranslateXVisible = function(isVisible) { + Overlays.editOverlay(grabberTranslateXCone, { visible: isVisible }); + Overlays.editOverlay(grabberTranslateXCylinder, { visible: isVisible }); + }; + that.setGrabberTranslateYVisible = function(isVisible) { + Overlays.editOverlay(grabberTranslateYCone, { visible: isVisible }); + Overlays.editOverlay(grabberTranslateYCylinder, { visible: isVisible }); + }; - // YAW GRABBER TOOL DEFINITION - var initialPosition = SelectionManager.worldPosition; - addGrabberTool(yawHandle, { - mode: "ROTATE_YAW", - onBegin: function(event, pickRay, pickResult) { - helperRotationHandleOnBegin(event, pickRay, "y", yawCenter, yawHandleRotation); - }, - onEnd: function(event, reason) { - helperRotationHandleOnEnd(); - }, - onMove: function(event) { - helperRotationHandleOnMove(event, "y", yawCenter, yawHandleRotation); - } - }); + that.setGrabberTranslateZVisible = function(isVisible) { + Overlays.editOverlay(grabberTranslateZCone, { visible: isVisible }); + Overlays.editOverlay(grabberTranslateZCylinder, { visible: isVisible }); + }; + // FUNCTION: SET GRABBER ROTATION VISIBLE + that.setGrabberRotateVisible = function(isVisible) { + that.setGrabberRotatePitchVisible(isVisible); + that.setGrabberRotateYawVisible(isVisible); + that.setGrabberRotateRollVisible(isVisible); + }; - // PITCH GRABBER TOOL DEFINITION - addGrabberTool(pitchHandle, { - mode: "ROTATE_PITCH", - onBegin: function(event, pickRay, pickResult) { - helperRotationHandleOnBegin(event, pickRay, "x", pitchCenter, pitchHandleRotation); - }, - onEnd: function(event, reason) { - helperRotationHandleOnEnd(); - }, - onMove: function (event) { - helperRotationHandleOnMove(event, "x", pitchCenter, pitchHandleRotation); - } - }); + that.setGrabberRotatePitchVisible = function(isVisible) { + Overlays.editOverlay(grabberRotatePitchRing, { visible: isVisible }); + }; + that.setGrabberRotateYawVisible = function(isVisible) { + Overlays.editOverlay(grabberRotateYawRing, { visible: isVisible }); + }; - // ROLL GRABBER TOOL DEFINITION - addGrabberTool(rollHandle, { - mode: "ROTATE_ROLL", - onBegin: function(event, pickRay, pickResult) { - helperRotationHandleOnBegin(event, pickRay, "z", rollCenter, rollHandleRotation); - }, - onEnd: function (event, reason) { - helperRotationHandleOnEnd(); - }, - onMove: function(event) { - helperRotationHandleOnMove(event, "z", rollCenter, rollHandleRotation); - } - }); + that.setGrabberRotateRollVisible = function(isVisible) { + Overlays.editOverlay(grabberRotateRollRing, { visible: isVisible }); + }; + + // FUNCTION: SET GRABBER STRETCH VISIBLE + that.setGrabberStretchVisible = function(isVisible) { + that.setGrabberStretchXVisible(isVisible); + that.setGrabberStretchYVisible(isVisible); + that.setGrabberStretchZVisible(isVisible); + }; + + that.setGrabberStretchXVisible = function(isVisible) { + Overlays.editOverlay(grabberStretchXSphere, { visible: isVisible }); + }; + + that.setGrabberStretchYVisible = function(isVisible) { + Overlays.editOverlay(grabberStretchYSphere, { visible: isVisible }); + }; + + that.setGrabberStretchZVisible = function(isVisible) { + Overlays.editOverlay(grabberStretchZSphere, { visible: isVisible }); + }; + + // FUNCTION: SET GRABBER SCALE VISIBLE + that.setGrabberScaleVisible = function(isVisible) { + Overlays.editOverlay(grabberScaleLBNCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleRBNCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleLBFCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleRBFCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleLTNCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleRTNCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleLTFCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleRTFCube, { visible: isVisible }); + Overlays.editOverlay(grabberScaleTREdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleTLEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleTFEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleTNEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleBREdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleBLEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleBFEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleBNEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleNREdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleNLEdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleFREdge, { visible: isVisible }); + Overlays.editOverlay(grabberScaleFLEdge, { visible: isVisible }); + }; + + addGrabberTranslateTool(grabberTranslateXCone, "TRANSLATE_X", TRANSLATE_DIRECTION.X); + addGrabberTranslateTool(grabberTranslateXCylinder, "TRANSLATE_X", TRANSLATE_DIRECTION.X); + addGrabberTranslateTool(grabberTranslateYCone, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); + addGrabberTranslateTool(grabberTranslateYCylinder, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); + addGrabberTranslateTool(grabberTranslateZCone, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); + addGrabberTranslateTool(grabberTranslateZCylinder, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); + + addGrabberRotateTool(grabberRotatePitchRing, "ROTATE_PITCH", ROTATE_DIRECTION.PITCH); + addGrabberRotateTool(grabberRotateYawRing, "ROTATE_YAW", ROTATE_DIRECTION.YAW); + addGrabberRotateTool(grabberRotateRollRing, "ROTATE_ROLL", ROTATE_DIRECTION.ROLL); + + addGrabberStretchTool(grabberStretchXSphere, "STRETCH_X", TRANSLATE_DIRECTION.X); + addGrabberStretchTool(grabberStretchYSphere, "STRETCH_Y", TRANSLATE_DIRECTION.Y); + addGrabberStretchTool(grabberStretchZSphere, "STRETCH_Z", TRANSLATE_DIRECTION.Z); + + addGrabberScaleTool(grabberScaleLBNCube, "SCALE_LBN", SCALE_DIRECTION.LBN); + addGrabberScaleTool(grabberScaleRBNCube, "SCALE_RBN", SCALE_DIRECTION.RBN); + addGrabberScaleTool(grabberScaleLBFCube, "SCALE_LBF", SCALE_DIRECTION.LBF); + addGrabberScaleTool(grabberScaleRBFCube, "SCALE_RBF", SCALE_DIRECTION.RBF); + addGrabberScaleTool(grabberScaleLTNCube, "SCALE_LTN", SCALE_DIRECTION.LTN); + addGrabberScaleTool(grabberScaleRTNCube, "SCALE_RTN", SCALE_DIRECTION.RTN); + addGrabberScaleTool(grabberScaleLTFCube, "SCALE_LTF", SCALE_DIRECTION.LTF); + addGrabberScaleTool(grabberScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF); // FUNCTION: CHECK MOVE that.checkMove = function() { @@ -3587,7 +1406,7 @@ SelectionDisplay = (function() { if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) || !Quat.equal(Camera.getOrientation(), lastCameraOrientation)) { - that.updateRotationHandles(); + //that.updateRotationHandles(); } } }; @@ -3606,7 +1425,6 @@ SelectionDisplay = (function() { } }; - // FUNCTION DEF(s): Intersection Check Helpers function testRayIntersect(queryRay, overlayIncludes, overlayExcludes) { var wantDebug = false; @@ -3650,7 +1468,7 @@ 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 = [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]; for (var key in grabberTools) { if (grabberTools.hasOwnProperty(key)) { interactiveOverlays.push(key); @@ -3717,125 +1535,6 @@ SelectionDisplay = (function() { return true; } - // if no tool is active, then just look for handles to highlight... - var pickRay = generalComputePickRay(event.x, event.y); - var result = Overlays.findRayIntersection(pickRay); - var pickedColor; - var pickedAlpha; - var highlightNeeded = false; - - if (result.intersects) { - switch (result.overlayID) { - case yawHandle: - case pitchHandle: - case rollHandle: - pickedColor = handleColor; - pickedAlpha = handleAlpha; - highlightNeeded = true; - break; - - case grabberMoveUp: - pickedColor = handleColor; - pickedAlpha = handleAlpha; - highlightNeeded = true; - break; - - case grabberLBN: - case grabberLBF: - case grabberRBN: - case grabberRBF: - case grabberLTN: - case grabberLTF: - case grabberRTN: - case grabberRTF: - pickedColor = grabberColorCorner; - pickedAlpha = grabberAlpha; - highlightNeeded = true; - break; - - case grabberTOP: - case grabberBOTTOM: - case grabberLEFT: - case grabberRIGHT: - case grabberNEAR: - case grabberFAR: - pickedColor = grabberColorFace; - pickedAlpha = grabberAlpha; - highlightNeeded = true; - break; - - case grabberEdgeTR: - case grabberEdgeTL: - case grabberEdgeTF: - case grabberEdgeTN: - case grabberEdgeBR: - case grabberEdgeBL: - case grabberEdgeBF: - case grabberEdgeBN: - case grabberEdgeNR: - case grabberEdgeNL: - case grabberEdgeFR: - case grabberEdgeFL: - case grabberSpotLightRadius: - case grabberSpotLightT: - case grabberSpotLightB: - case grabberSpotLightL: - case grabberSpotLightR: - case grabberPointLightT: - case grabberPointLightB: - case grabberPointLightR: - case grabberPointLightL: - case grabberPointLightN: - case grabberPointLightF: - pickedColor = grabberColorEdge; - pickedAlpha = grabberAlpha; - highlightNeeded = true; - break; - - case grabberCloner: - pickedColor = grabberColorCloner; - pickedAlpha = grabberAlpha; - highlightNeeded = true; - break; - - default: - if (previousHandle) { - Overlays.editOverlay(previousHandle, { - color: previousHandleColor, - alpha: previousHandleAlpha - }); - previousHandle = false; - } - break; - } - - if (highlightNeeded) { - if (previousHandle) { - Overlays.editOverlay(previousHandle, { - color: previousHandleColor, - alpha: previousHandleAlpha - }); - previousHandle = false; - } - Overlays.editOverlay(result.overlayID, { - color: highlightedHandleColor, - alpha: highlightedHandleAlpha - }); - previousHandle = result.overlayID; - previousHandleColor = pickedColor; - previousHandleAlpha = pickedAlpha; - } - - } else { - if (previousHandle) { - Overlays.editOverlay(previousHandle, { - color: previousHandleColor, - alpha: previousHandleAlpha - }); - previousHandle = false; - } - } - if (wantDebug) { print("=============== eST::MouseMoveEvent END ======================="); } @@ -3859,23 +1558,6 @@ SelectionDisplay = (function() { print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd"); } } - - // hide our rotation overlays..., and show our handles - if (isActiveTool(yawHandle) || isActiveTool(pitchHandle) || isActiveTool(rollHandle)) { - if (wantDebug) { - print(" Triggering hide of RotateOverlays"); - } - Overlays.editOverlay(rotateOverlayInner, { - visible: false - }); - Overlays.editOverlay(rotateOverlayOuter, { - visible: false - }); - Overlays.editOverlay(rotateOverlayCurrent, { - visible: false - }); - - } showHandles = activeTool; // base on prior tool value activeTool = null; @@ -3900,7 +1582,5 @@ SelectionDisplay = (function() { // Controller.mouseMoveEvent.connect(that.mouseMoveEvent); Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); - return that; - }()); From 25f5eb6b4fc3288d23b193e274996f72153cdec5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 18 Jan 2018 15:08:13 -0800 Subject: [PATCH 036/272] 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 c4359de859a0cf0e1edd112ea828f807cbb7b99e Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 19 Jan 2018 18:20:36 -0800 Subject: [PATCH 037/272] entity edit tools wip update --- scripts/system/edit.js | 2 +- .../system/libraries/entitySelectionTool.js | 1269 ++++++++++++----- 2 files changed, 883 insertions(+), 388 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 87cd3e0faf..2b886d2540 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -65,7 +65,7 @@ gridTool.setVisible(false); var entityListTool = new EntityListTool(); selectionManager.addEventListener(function () { - selectionDisplay.updateHandles(); + selectionDisplay.updateGrabbers(); entityIconOverlayManager.updatePositions(); // Update particle explorer diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 220a7b7c70..253c67bfca 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -138,16 +138,16 @@ SelectionManager = (function() { that.localPosition = null; that.worldDimensions = null; that.worldPosition = null; + that.worldRotation = null; } else if (that.selections.length === 1) { properties = Entities.getEntityProperties(that.selections[0]); that.localDimensions = properties.dimensions; that.localPosition = properties.position; that.localRotation = properties.rotation; that.localRegistrationPoint = properties.registrationPoint; - - that.worldDimensions = properties.boundingBox.dimensions; - that.worldPosition = properties.boundingBox.center; - + that.worldDimensions = properties.dimensions; // properties.boundingbox.dimensions; + that.worldPosition = properties.position; + that.worldRotation = properties.rotation; SelectionDisplay.setSpaceMode(SPACE_LOCAL); } else { that.localRotation = null; @@ -194,7 +194,6 @@ SelectionManager = (function() { print("ERROR: entitySelectionTool.update got exception: " + JSON.stringify(e)); } } - }; return that; @@ -230,16 +229,23 @@ SelectionDisplay = (function() { var COLOR_BLUE = { red:0, green:0, blue:255 }; var COLOR_RED = { red:255, green:0, blue:0 }; - var GRABBER_TRANSLATE_ARROW_CONE_OFFSET = 0.3625; - var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 0.3; - var GRABBER_STRETCH_SPHERE_OFFSET = 0.2; - var GRABBER_SCALE_CUBE_OFFSET = 0.2; + var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 1.35; + var GRABBER_TRANSLATE_ARROW_CYLINDER_DIMENSION_MULTIPLE = 0.05; + var GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE = 7.5; + var GRABBER_TRANSLATE_ARROW_CONE_DIMENSION_MULTIPLE = 0.25; + var GRABBER_ROTATE_RINGS_DIMENSION_MULTIPLE = 2.0; + var GRABBER_STRETCH_SPHERE_OFFSET = 1.0; + var GRABBER_STRETCH_SPHERE_DIMENSION_MULTIPLE = 0.1; + var GRABBER_SCALE_CUBE_OFFSET = 1.0; + var GRABBER_SCALE_CUBE_DIMENSION_MULTIPLE = 0.15; + var GRABBER_CLONER_OFFSET = { x:0.9, y:-0.9, z:0.9 }; var GRABBER_SCALE_CUBE_IDLE_COLOR = { red:120, green:120, blue:120 }; var GRABBER_SCALE_CUBE_SELECTED_COLOR = { red:0, green:0, blue:0 }; var GRABBER_SCALE_EDGE_COLOR = { red:120, green:120, blue:120 }; var SCALE_MINIMUM_DIMENSION = 0.02; + var STRETCH_MINIMUM_DIMENSION = 0.001; // These are multipliers for sizing the rotation degrees display while rotating an entity var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.0; @@ -253,6 +259,13 @@ SelectionDisplay = (function() { Z : 2 } + var STRETCH_DIRECTION = { + X : 0, + Y : 1, + Z : 2, + ALL : 3 + } + var ROTATE_DIRECTION = { PITCH : 0, YAW : 1, @@ -291,7 +304,6 @@ SelectionDisplay = (function() { var grabberPropertiesTranslateArrowCones = { shape: "Cone", - dimensions: { x:0.05, y:0.05, z:0.05 }, solid: true, visible: false, ignoreRayIntersection: false, @@ -299,7 +311,6 @@ SelectionDisplay = (function() { }; var grabberPropertiesTranslateArrowCylinders = { shape: "Cylinder", - dimensions: { x:0.01, y:0.075, z:0.01 }, solid: true, visible: false, ignoreRayIntersection: false, @@ -319,7 +330,6 @@ SelectionDisplay = (function() { Overlays.editOverlay(grabberTranslateZCylinder, { color : COLOR_BLUE }); var grabberPropertiesRotateRings = { - size: 0.5, alpha: 1, innerRadius: 0.9, startAt: 0, @@ -347,9 +357,8 @@ SelectionDisplay = (function() { }); var grabberRotateCurrentRing = Overlays.addOverlay("circle3d", { - size: 0.5, alpha: 1, - color: { red: 224, green: 67, blue: 36 }, + color: { red: 255, green: 99, blue: 9 }, solid: true, innerRadius: 0.9, visible: false, @@ -377,7 +386,6 @@ SelectionDisplay = (function() { var grabberPropertiesStretchSpheres = { shape: "Sphere", - dimensions: { x:0.02, y:0.02, z:0.02 }, solid: true, visible: false, ignoreRayIntersection: false, @@ -393,7 +401,6 @@ SelectionDisplay = (function() { var grabberPropertiesStretchPanel = { shape: "Quad", alpha: 0.5, - dimensions: { x:GRABBER_SCALE_CUBE_OFFSET * 2, y:GRABBER_SCALE_CUBE_OFFSET * 2, z:0.01 }, solid: true, visible: false, ignoreRayIntersection: true, @@ -444,6 +451,25 @@ SelectionDisplay = (function() { var grabberScaleFREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); var grabberScaleFLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var grabberCloner = Overlays.addOverlay("cube", { + size: 0.05, + color: COLOR_GREEN, + solid: true, + visible: false, + ignoreRayIntersection: false, + drawInFront: true, + borderSize: 1.4 + }); + + var selectionBox = Overlays.addOverlay("cube", { + size: 1, + color: COLOR_RED, + alpha: 1, + solid: false, + visible: false, + dashed: false + }); + var allOverlays = [ grabberTranslateXCone, grabberTranslateXCylinder, @@ -481,7 +507,9 @@ SelectionDisplay = (function() { grabberScaleNREdge, grabberScaleNLEdge, grabberScaleFREdge, - grabberScaleFLEdge + grabberScaleFLEdge, + grabberCloner, + selectionBox ]; overlayNames[grabberTranslateXCone] = "grabberTranslateXCone"; @@ -521,6 +549,8 @@ SelectionDisplay = (function() { overlayNames[grabberScaleNLEdge] = "grabberScaleNLEdge"; overlayNames[grabberScaleFREdge] = "grabberScaleFREdge"; overlayNames[grabberScaleFLEdge] = "grabberScaleFLEdge"; + overlayNames[grabberCloner] = "grabberCloner"; + overlayNames[selectionBox] = "selectionBox"; // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. @@ -587,7 +617,7 @@ SelectionDisplay = (function() { pickNormal = { x:0, y:1, z:0 }; } - var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + var rotation = SelectionManager.worldRotation; pickNormal = Vec3.multiplyQbyV(rotation, pickNormal); lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); @@ -600,6 +630,7 @@ SelectionDisplay = (function() { that.setGrabberRotateVisible(false); that.setGrabberStretchVisible(false); that.setGrabberScaleVisible(false); + that.setGrabberClonerVisible(false); // Duplicate entities if alt is pressed. This will make a // copy of the selected entities and move the _original_ entities, not @@ -638,7 +669,7 @@ SelectionDisplay = (function() { projectionVector = { x:0, y:0, z:1 }; } - var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + var rotation = SelectionManager.worldRotation; projectionVector = Vec3.multiplyQbyV(rotation, projectionVector); var dotVector = Vec3.dot(vector, projectionVector); @@ -666,258 +697,388 @@ SelectionDisplay = (function() { }); } - function addGrabberStretchTool(overlay, mode, direction) { - var pickNormal = null; + // FUNCTION: VEC 3 MULT + var vec3Mult = function(v1, v2) { + return { + x: v1.x * v2.x, + y: v1.y * v2.y, + z: v1.z * v2.z + }; + }; + + function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset) { + var directionFor3DStretch = directionVec; + var distanceFor3DStretch = 0; + var DISTANCE_INFLUENCE_THRESHOLD = 1.2; + + var signs = { + x: directionVec.x < 0 ? -1 : (directionVec.x > 0 ? 1 : 0), + y: directionVec.y < 0 ? -1 : (directionVec.y > 0 ? 1 : 0), + z: directionVec.z < 0 ? -1 : (directionVec.z > 0 ? 1 : 0) + }; + + var mask = { + x: Math.abs(directionVec.x) > 0 ? 1 : 0, + y: Math.abs(directionVec.y) > 0 ? 1 : 0, + z: Math.abs(directionVec.z) > 0 ? 1 : 0 + }; + + var numDimensions = mask.x + mask.y + mask.z; + + var planeNormal = null; var lastPick = null; - var projectionVector = null; - var stretchPanel = null; - addGrabberTool(overlay, { - mode: mode, - onBegin: function(event, pickRay, pickResult) { - if (direction === TRANSLATE_DIRECTION.X) { - stretchPanel = grabberStretchXPanel; - pickNormal = { x:0, y:0, z:1 }; - } else if (direction === TRANSLATE_DIRECTION.Y) { - stretchPanel = grabberStretchYPanel; - pickNormal = { x:1, y:0, z:0 }; - } else if (direction === TRANSLATE_DIRECTION.Z) { - stretchPanel = grabberStretchZPanel; - pickNormal = { x:0, y:1, z:0 }; - } + var lastPick3D = null; + var initialPosition = null; + var initialDimensions = null; + var initialIntersection = null; + var initialProperties = null; + var registrationPoint = null; + var deltaPivot = null; + var deltaPivot3D = null; + var pickRayPosition = null; + var pickRayPosition3D = null; + var rotation = null; - Overlays.editOverlay(stretchPanel, { visible:true }); + var onBegin = function(event, pickRay, pickResult) { + var properties = Entities.getEntityProperties(SelectionManager.selections[0]); + initialProperties = properties; + rotation = (spaceMode === SPACE_LOCAL) ? properties.rotation : Quat.IDENTITY; - var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; - pickNormal = Vec3.multiplyQbyV(rotation, pickNormal); - - lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); - - SelectionManager.saveProperties(); - - that.setGrabberTranslateVisible(false); - that.setGrabberRotateVisible(false); - that.setGrabberStretchXVisible(direction === TRANSLATE_DIRECTION.X); - that.setGrabberStretchYVisible(direction === TRANSLATE_DIRECTION.Y); - that.setGrabberStretchZVisible(direction === TRANSLATE_DIRECTION.Z); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt) { - duplicatedEntityIDs = []; - for (var otherEntityID in SelectionManager.savedProperties) { - var properties = SelectionManager.savedProperties[otherEntityID]; - if (!properties.locked) { - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties - }); - } - } - } else { - duplicatedEntityIDs = null; - } - }, - onEnd: function(event, reason) { - Overlays.editOverlay(stretchPanel, { visible:false }); - pushCommandForSelections(duplicatedEntityIDs); - }, - onMove: function(event) { - pickRay = generalComputePickRay(event.x, event.y); - - // translate mode left/right based on view toward entity - var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); - var vector = Vec3.subtract(newIntersection, lastPick); - - if (direction === TRANSLATE_DIRECTION.X) { - projectionVector = { x:1, y:0, z:0 }; - } else if (direction === TRANSLATE_DIRECTION.Y) { - projectionVector = { x:0, y:1, z:0 }; - } else if (direction === TRANSLATE_DIRECTION.Z) { - projectionVector = { x:0, y:0, z:1 }; - } - - var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; - projectionVector = Vec3.multiplyQbyV(rotation, projectionVector); - - var dotVector = Vec3.dot(vector, projectionVector); - vector = Vec3.multiply(dotVector, projectionVector); - vector = grid.snapToGrid(vector); - - var wantDebug = false; - if (wantDebug) { - print("translateUpDown... "); - print(" event.y:" + event.y); - Vec3.print(" newIntersection:", newIntersection); - Vec3.print(" vector:", vector); - // Vec3.print(" newPosition:", newPosition); - } - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var id = SelectionManager.selections[i]; - var properties = SelectionManager.savedProperties[id]; - var newPosition = Vec3.sum(properties.position, vector); - var difference = Vec3.subtract(newPosition, SelectionManager.worldPosition); - var halfDifference = Vec3.multiply(difference, 0.5); - var quarterDifference = Vec3.multiply(halfDifference, 0.5); - var newDimensions = properties.dimensions; - var actualNewPosition = properties.position; - - if (direction == TRANSLATE_DIRECTION.X) { - newDimensions.x += halfDifference.x; - actualNewPosition.x += quarterDifference.x; - } else if (direction == TRANSLATE_DIRECTION.Y) { - newDimensions.y += halfDifference.y; - actualNewPosition.y += quarterDifference.y; - } else if (direction == TRANSLATE_DIRECTION.Z) { - newDimensions.z += halfDifference.z; - actualNewPosition.z += quarterDifference.z; - } - - Entities.editEntity(id, { - position: actualNewPosition, - dimensions: newDimensions - }); - } - - SelectionManager._update(); + if (spaceMode === SPACE_LOCAL) { + rotation = SelectionManager.localRotation; + initialPosition = SelectionManager.localPosition; + initialDimensions = SelectionManager.localDimensions; + registrationPoint = SelectionManager.localRegistrationPoint; + } else { + rotation = SelectionManager.worldRotation; + initialPosition = SelectionManager.worldPosition; + initialDimensions = SelectionManager.worldDimensions; + registrationPoint = SelectionManager.worldRegistrationPoint; } - }); + + // Modify range of registrationPoint to be [-0.5, 0.5] + var centeredRP = Vec3.subtract(registrationPoint, { + x: 0.5, + y: 0.5, + z: 0.5 + }); + + // Scale pivot to be in the same range as registrationPoint + var scaledPivot = Vec3.multiply(0.5, pivot); + deltaPivot = Vec3.subtract(centeredRP, scaledPivot); + + var scaledOffset = Vec3.multiply(0.5, offset); + + // Offset from the registration point + offsetRP = Vec3.subtract(scaledOffset, centeredRP); + + // Scaled offset in world coordinates + var scaledOffsetWorld = vec3Mult(initialDimensions, offsetRP); + + pickRayPosition = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); + + if (directionFor3DStretch) { + // pivot, offset and pickPlanePosition for 3D manipulation + var scaledPivot3D = Vec3.multiply(0.5, Vec3.multiply(1.0, directionFor3DStretch)); + deltaPivot3D = Vec3.subtract(centeredRP, scaledPivot3D); + + var scaledOffsetWorld3D = vec3Mult(initialDimensions, + Vec3.subtract(Vec3.multiply(0.5, Vec3.multiply(-1.0, directionFor3DStretch)), centeredRP)); + + pickRayPosition3D = Vec3.sum(initialPosition, Vec3.multiplyQbyV(rotation, scaledOffsetWorld)); + } + var start = null; + var end = null; + if ((numDimensions === 1) && mask.x) { + start = Vec3.multiplyQbyV(rotation, { + x: -10000, + y: 0, + z: 0 + }); + start = Vec3.sum(start, properties.position); + end = Vec3.multiplyQbyV(rotation, { + x: 10000, + y: 0, + z: 0 + }); + end = Vec3.sum(end, properties.position); + } + if ((numDimensions === 1) && mask.y) { + start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: -10000, + z: 0 + }); + start = Vec3.sum(start, properties.position); + end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 10000, + z: 0 + }); + end = Vec3.sum(end, properties.position); + } + if ((numDimensions === 1) && mask.z) { + start = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: -10000 + }); + start = Vec3.sum(start, properties.position); + end = Vec3.multiplyQbyV(rotation, { + x: 0, + y: 0, + z: 10000 + }); + end = Vec3.sum(end, properties.position); + } + if (numDimensions === 1) { + if (mask.x === 1) { + planeNormal = { + x: 0, + y: 1, + z: 0 + }; + } else if (mask.y === 1) { + planeNormal = { + x: 1, + y: 0, + z: 0 + }; + } else { + planeNormal = { + x: 0, + y: 1, + z: 0 + }; + } + } else if (numDimensions === 2) { + if (mask.x === 0) { + planeNormal = { + x: 1, + y: 0, + z: 0 + }; + } else if (mask.y === 0) { + planeNormal = { + x: 0, + y: 1, + z: 0 + }; + } else { + planeNormal = { + x: 0, + y: 0, + z: 1 + }; + } + } + + planeNormal = Vec3.multiplyQbyV(rotation, planeNormal); + lastPick = rayPlaneIntersection(pickRay, + pickRayPosition, + planeNormal); + + var planeNormal3D = { + x: 0, + y: 0, + z: 0 + }; + if (directionFor3DStretch) { + lastPick3D = rayPlaneIntersection(pickRay, + pickRayPosition3D, + planeNormal3D); + distanceFor3DStretch = Vec3.length(Vec3.subtract(pickRayPosition3D, pickRay.origin)); + } + + that.setGrabberTranslateVisible(false); + that.setGrabberRotateVisible(false); + that.setGrabberScaleVisible(directionEnum === STRETCH_DIRECTION.ALL); + that.setGrabberStretchXVisible(directionEnum === STRETCH_DIRECTION.X); + that.setGrabberStretchYVisible(directionEnum === STRETCH_DIRECTION.Y); + that.setGrabberStretchZVisible(directionEnum === STRETCH_DIRECTION.Z); + that.setGrabberClonerVisible(false); + + SelectionManager.saveProperties(); + }; + + var onEnd = function(event, reason) { + pushCommandForSelections(); + }; + + var onMove = function(event) { + var proportional = (spaceMode === SPACE_WORLD) || event.isShifted || directionEnum === STRETCH_DIRECTION.ALL; + + var position, dimensions, rotation; + if (spaceMode === SPACE_LOCAL) { + position = SelectionManager.localPosition; + dimensions = SelectionManager.localDimensions; + rotation = SelectionManager.localRotation; + } else { + position = SelectionManager.worldPosition; + dimensions = SelectionManager.worldDimensions; + rotation = SelectionManager.worldRotation; + } + + var localDeltaPivot = deltaPivot; + var localSigns = signs; + + var pickRay = generalComputePickRay(event.x, event.y); + + // Are we using handControllers or Mouse - only relevant for 3D tools + var controllerPose = getControllerWorldLocation(activeHand, true); + var vector = null; + if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() && + controllerPose.valid && that.triggered && directionFor3DStretch) { + localDeltaPivot = deltaPivot3D; + + newPick = pickRay.origin; + + vector = Vec3.subtract(newPick, lastPick3D); + + vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); + + if (distanceFor3DStretch > DISTANCE_INFLUENCE_THRESHOLD) { + // Range of Motion + vector = Vec3.multiply(distanceFor3DStretch , vector); + } + + localSigns = directionFor3DStretch; + + } else { + newPick = rayPlaneIntersection(pickRay, + pickRayPosition, + planeNormal); + vector = Vec3.subtract(newPick, lastPick); + + vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); + + vector = vec3Mult(mask, vector); + + } + + vector = grid.snapToSpacing(vector); + + var changeInDimensions = Vec3.multiply(-1, vec3Mult(localSigns, vector)); + var newDimensions; + if (proportional) { + var absX = Math.abs(changeInDimensions.x); + var absY = Math.abs(changeInDimensions.y); + var absZ = Math.abs(changeInDimensions.z); + var pctChange = 0; + if (absX > absY && absX > absZ) { + pctChange = changeInDimensions.x / initialProperties.dimensions.x; + pctChange = changeInDimensions.x / initialDimensions.x; + } else if (absY > absZ) { + pctChange = changeInDimensions.y / initialProperties.dimensions.y; + pctChange = changeInDimensions.y / initialDimensions.y; + } else { + pctChange = changeInDimensions.z / initialProperties.dimensions.z; + pctChange = changeInDimensions.z / initialDimensions.z; + } + pctChange += 1.0; + newDimensions = Vec3.multiply(pctChange, initialDimensions); + } else { + newDimensions = Vec3.sum(initialDimensions, changeInDimensions); + } + + newDimensions.x = Math.max(newDimensions.x, STRETCH_MINIMUM_DIMENSION); + newDimensions.y = Math.max(newDimensions.y, STRETCH_MINIMUM_DIMENSION); + newDimensions.z = Math.max(newDimensions.z, STRETCH_MINIMUM_DIMENSION); + + var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(localDeltaPivot, changeInDimensions)); + if (directionEnum === STRETCH_DIRECTION.ALL) { + changeInPosition = { x:0, y:0, z:0 }; + } + var newPosition = Vec3.sum(initialPosition, changeInPosition); + + for (var i = 0; i < SelectionManager.selections.length; i++) { + Entities.editEntity(SelectionManager.selections[i], { + position: newPosition, + dimensions: newDimensions + }); + } + + var wantDebug = false; + if (wantDebug) { + print(stretchMode); + // Vec3.print(" newIntersection:", newIntersection); + Vec3.print(" vector:", vector); + // Vec3.print(" oldPOS:", oldPOS); + // Vec3.print(" newPOS:", newPOS); + Vec3.print(" changeInDimensions:", changeInDimensions); + Vec3.print(" newDimensions:", newDimensions); + + Vec3.print(" changeInPosition:", changeInPosition); + Vec3.print(" newPosition:", newPosition); + } + + SelectionManager._update(); + };// End of onMove def + + return { + mode: stretchMode, + onBegin: onBegin, + onMove: onMove, + onEnd: onEnd + }; } - function addGrabberScaleTool(overlay, mode, direction) { - var pickNormal = null; - var lastPick = null; - var selectedGrabber = null; - addGrabberTool(overlay, { - mode: mode, - onBegin: function(event, pickRay, pickResult) { - pickNormal = { x:-1, y:1, z:-1 }; + function addGrabberStretchTool(overlay, mode, directionEnum) { + var directionVec, pivot, offset; + if (directionEnum === STRETCH_DIRECTION.X) { + directionVec = { x:-1, y:0, z:0 }; + pivot = { x:-1, y:0, z:0 }; + offset = { x:1, y:0, z:0 }; + } else if (directionEnum === STRETCH_DIRECTION.Y) { + directionVec = { x:0, y:-1, z:0 }; + pivot = { x:0, y:-1, z:0 }; + offset = { x:0, y:1, z:0 }; + } else if (directionEnum === STRETCH_DIRECTION.Z) { + directionVec = { x:0, y:0, z:-1 }; + pivot = { x:0, y:0, z:-1 }; + offset = { x:0, y:0, z:1 }; + } + var tool = makeStretchTool(mode, directionEnum, directionVec, pivot, offset); + return addGrabberTool(overlay, tool); + } - if (direction === SCALE_DIRECTION.LBN) { - selectedGrabber = grabberScaleLBNCube; - } else if (direction === SCALE_DIRECTION.RBN) { - selectedGrabber = grabberScaleRBNCube; - } else if (direction === SCALE_DIRECTION.LBF) { - selectedGrabber = grabberScaleLBFCube; - } else if (direction === SCALE_DIRECTION.RBF) { - selectedGrabber = grabberScaleRBFCube; - } else if (direction === SCALE_DIRECTION.LTN) { - selectedGrabber = grabberScaleLTNCube; - } else if (direction === SCALE_DIRECTION.RTN) { - selectedGrabber = grabberScaleRTNCube; - } else if (direction === SCALE_DIRECTION.LTF) { - selectedGrabber = grabberScaleLTFCube; - } else if (direction === SCALE_DIRECTION.RTF) { - selectedGrabber = grabberScaleRTFCube; - } - Overlays.editOverlay(selectedGrabber, { color: GRABBER_SCALE_CUBE_SELECTED_COLOR }); - - lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); - - SelectionManager.saveProperties(); - - that.setGrabberTranslateVisible(false); - that.setGrabberRotateVisible(false); - that.setGrabberStretchVisible(false); - that.setGrabberScaleVisible(true); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt) { - duplicatedEntityIDs = []; - for (var otherEntityID in SelectionManager.savedProperties) { - var properties = SelectionManager.savedProperties[otherEntityID]; - if (!properties.locked) { - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties - }); - } - } - } else { - duplicatedEntityIDs = null; - } - }, - onEnd: function(event, reason) { - Overlays.editOverlay(selectedGrabber, { color: GRABBER_SCALE_CUBE_IDLE_COLOR }); - pushCommandForSelections(duplicatedEntityIDs); - }, - onMove: function(event) { - pickRay = generalComputePickRay(event.x, event.y); - - // translate mode left/right based on view toward entity - var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); - var vector = Vec3.subtract(newIntersection, lastPick); - - var projectionVector; - if (direction === SCALE_DIRECTION.LBN) { - projectionVector = { x:-1, y:-1, z:-1 }; - } else if (direction === SCALE_DIRECTION.RBN) { - projectionVector = { x:-1, y:-1, z:1 }; - } else if (direction === SCALE_DIRECTION.LBF) { - projectionVector = { x:1, y:-1, z:-1 }; - } else if (direction === SCALE_DIRECTION.RBF) { - projectionVector = { x:1, y:-1, z:1 }; - } else if (direction === SCALE_DIRECTION.LTN) { - projectionVector = { x:-1, y:1, z:-1 }; - } else if (direction === SCALE_DIRECTION.RTN) { - projectionVector = { x:-1, y:1, z:1 }; - } else if (direction === SCALE_DIRECTION.LTF) { - projectionVector = { x:1, y:1, z:-1 }; - } else if (direction === SCALE_DIRECTION.RTF) { - projectionVector = { x:1, y:1, z:1 }; - } - - var dotVector = Vec3.dot(vector, projectionVector); - vector = Vec3.multiply(dotVector, projectionVector); - vector = grid.snapToGrid(vector); - - var wantDebug = false; - if (wantDebug) { - print("translateUpDown... "); - print(" event.y:" + event.y); - Vec3.print(" newIntersection:", newIntersection); - Vec3.print(" vector:", vector); - // Vec3.print(" newPosition:", newPosition); - } - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var id = SelectionManager.selections[i]; - var properties = SelectionManager.savedProperties[id]; - var newPosition = Vec3.sum(properties.position, vector); - var difference = Vec3.subtract(newPosition, SelectionManager.worldPosition); - var differenceAvg = (difference.x + difference.y + difference.z) / 3; - var newDimensionsX = properties.dimensions.x + differenceAvg; - var newDimensionsY = properties.dimensions.y + differenceAvg; - var newDimensionsZ = properties.dimensions.z + differenceAvg; - if (newDimensionsX < SCALE_MINIMUM_DIMENSION) { - var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsX; - newDimensionsX += differenceBelow; - newDimensionsY += differenceBelow; - newDimensionsZ += differenceBelow; - } - if (newDimensionsY < SCALE_MINIMUM_DIMENSION) { - var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsY; - newDimensionsX += differenceBelow; - newDimensionsY += differenceBelow; - newDimensionsZ += differenceBelow; - } - if (newDimensionsZ < SCALE_MINIMUM_DIMENSION) { - var differenceBelow = SCALE_MINIMUM_DIMENSION - newDimensionsZ; - newDimensionsX += differenceBelow; - newDimensionsY += differenceBelow; - newDimensionsZ += differenceBelow; - } - Entities.editEntity(id, { dimensions: { x:newDimensionsX, y:newDimensionsY, z:newDimensionsZ }}); - } - - SelectionManager._update(); - } - }); + function addGrabberScaleTool(overlay, mode, directionEnum) { + var directionVec, pivot, offset; + if (directionEnum === SCALE_DIRECTION.LBN) { + directionVec = { x:1, y:1, z:1 }; + pivot = { x:1, y:1, z:1 }; + offset = { x:-1, y:-1, z:-1 }; + } else if (directionEnum === SCALE_DIRECTION.RBN) { + directionVec = { x:1, y:1, z:-1 }; + pivot = { x:1, y:1, z:-1 }; + offset = { x:-1, y:-1, z:1 }; + } else if (directionEnum === SCALE_DIRECTION.LBF) { + directionVec = { x:-1, y:1, z:1 }; + pivot = { x:-1, y:1, z:1 }; + offset = { x:1, y:-1, z:-1 }; + } else if (directionEnum === SCALE_DIRECTION.RBF) { + directionVec = { x:-1, y:1, z:-1 }; + pivot = { x:-1, y:1, z:-1 }; + offset = { x:1, y:-1, z:1 }; + } else if (directionEnum === SCALE_DIRECTION.LTN) { + directionVec = { x:1, y:-1, z:1 }; + pivot = { x:1, y:-1, z:1 }; + offset = { x:-1, y:1, z:-1 }; + } else if (directionEnum === SCALE_DIRECTION.RTN) { + directionVec = { x:1, y:-1, z:-1 }; + pivot = { x:1, y:-1, z:-1 }; + offset = { x:-1, y:1, z:1 }; + } else if (directionEnum === SCALE_DIRECTION.LTF) { + directionVec = { x:-1, y:-1, z:1 }; + pivot = { x:-1, y:-1, z:1 }; + offset = { x:1, y:1, z:-1 }; + } else if (directionEnum === SCALE_DIRECTION.RTF) { + directionVec = { x:-1, y:-1, z:-1 }; + pivot = { x:-1, y:-1, z:-1 }; + offset = { x:1, y:1, z:1 }; + } + var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVec, pivot, offset); + return addGrabberTool(overlay, tool); } // FUNCTION: UPDATE ROTATION DEGREES OVERLAY @@ -970,9 +1131,9 @@ SelectionDisplay = (function() { }; if (reposition) { - var dPos = Vec3.subtract(initialProperties.position, initialPosition); + var dPos = Vec3.subtract(initialProperties.position, SelectionManager.worldPosition); dPos = Vec3.multiplyQbyV(rotationChange, dPos); - newProperties.position = Vec3.sum(initialPosition, dPos); + newProperties.position = Vec3.sum(SelectionManager.worldPosition, dPos); } Entities.editEntity(entityID, newProperties); @@ -980,8 +1141,8 @@ SelectionDisplay = (function() { } function addGrabberRotateTool(overlay, mode, direction) { - var initialPosition = SelectionManager.worldPosition; var selectedGrabber = null; + var worldRotation = null; addGrabberTool(overlay, { mode: mode, onBegin: function(event, pickRay, pickResult) { @@ -993,29 +1154,37 @@ SelectionDisplay = (function() { that.setGrabberRotateRollVisible(direction === ROTATE_DIRECTION.ROLL); that.setGrabberStretchVisible(false); that.setGrabberScaleVisible(false); - - initialPosition = SelectionManager.worldPosition; + that.setGrabberClonerVisible(false); if (direction === ROTATE_DIRECTION.PITCH) { rotationNormal = { x: 1, y: 0, z: 0 }; + worldRotation = worldRotationY; selectedGrabber = grabberRotatePitchRing; } else if (direction === ROTATE_DIRECTION.YAW) { rotationNormal = { x: 0, y: 1, z: 0 }; + worldRotation = worldRotationZ; selectedGrabber = grabberRotateYawRing; } else if (direction === ROTATE_DIRECTION.ROLL) { rotationNormal = { x: 0, y: 0, z: 1 }; + worldRotation = worldRotationX; selectedGrabber = grabberRotateRollRing; } Overlays.editOverlay(selectedGrabber, { hasTickMarks: true }); - var rotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; + var rotation = SelectionManager.worldRotation; rotationNormal = Vec3.multiplyQbyV(rotation, rotationNormal); var rotCenter = SelectionManager.worldPosition; Overlays.editOverlay(rotationDegreesDisplay, { visible: true }); - Overlays.editOverlay(grabberRotateCurrentRing, { visible: true }); + Overlays.editOverlay(grabberRotateCurrentRing, { + position: rotCenter, + rotation: worldRotation, + startAt: 0, + endAt: 0, + visible: true + }); updateRotationDegreesOverlay(0, direction, rotCenter); // editOverlays may not have committed rotation changes. @@ -1051,15 +1220,6 @@ SelectionDisplay = (function() { updateSelectionsRotation(rotChange); updateRotationDegreesOverlay(-angleFromZero, direction, rotCenter); - var worldRotation; - if (direction === ROTATE_DIRECTION.PITCH) { - worldRotation = worldRotationY; - } else if (direction === ROTATE_DIRECTION.YAW) { - worldRotation = worldRotationZ; - } else if (direction === ROTATE_DIRECTION.ROLL) { - worldRotation = worldRotationX; - } - var startAtCurrent = 0; var endAtCurrent = angleFromZero; if (angleFromZero < 0) { @@ -1067,11 +1227,13 @@ SelectionDisplay = (function() { endAtCurrent = 360; } Overlays.editOverlay(grabberRotateCurrentRing, { - position: rotCenter, - rotation: worldRotation, startAt: startAtCurrent, endAt: endAtCurrent }); + // not sure why but this seems to be needed to fix an reverse rotation for yaw ring only + if (direction === ROTATE_DIRECTION.YAW) { + Overlays.editOverlay(grabberRotateCurrentRing, { rotation: worldRotationZ }); + } } } }); @@ -1142,89 +1304,9 @@ SelectionDisplay = (function() { }); */ - that.updateHandles(); + that.updateGrabbers(); }; - // FUNCTION: UPDATE HANDLE POSITION ROTATION - that.updateHandlePositionRotation = function() { - if (SelectionManager.hasSelection()) { - var worldPosition = SelectionManager.worldPosition; - var worldRotation = Entities.getEntityProperties(SelectionManager.selections[0]).rotation; - - var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); - worldRotationX = Quat.multiply(worldRotation, localRotationX); - var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); - worldRotationY = Quat.multiply(worldRotation, localRotationY); - var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); - worldRotationZ = Quat.multiply(worldRotation, localRotationZ); - - var cylinderXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET, y:0, z:0 })); - Overlays.editOverlay(grabberTranslateXCylinder, { position: cylinderXPos, rotation:worldRotationX }); - var coneXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CONE_OFFSET, y:0, z:0 })); - Overlays.editOverlay(grabberTranslateXCone, { position: coneXPos, rotation:worldRotationX }); - var stretchXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_STRETCH_SPHERE_OFFSET, y:0, z:0 })); - Overlays.editOverlay(grabberStretchXSphere, { position: stretchXPos }); - Overlays.editOverlay(grabberStretchXPanel, { position: stretchXPos, rotation:worldRotationY }); - - var cylinderYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET, z:0 })); - Overlays.editOverlay(grabberTranslateYCylinder, { position: cylinderYPos, rotation:worldRotationY }); - var coneYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CONE_OFFSET, z:0 })); - Overlays.editOverlay(grabberTranslateYCone, { position: coneYPos, rotation:worldRotationY }); - var stretchYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET, z:0 })); - Overlays.editOverlay(grabberStretchYSphere, { position: stretchYPos }); - Overlays.editOverlay(grabberStretchYPanel, { position: stretchYPos, rotation:worldRotationZ }); - - var cylinderZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET })); - Overlays.editOverlay(grabberTranslateZCylinder, { position: cylinderZPos, rotation:worldRotationZ }); - var coneZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CONE_OFFSET })); - Overlays.editOverlay(grabberTranslateZCone, { position: coneZPos, rotation:worldRotationZ }); - var stretchZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET })); - Overlays.editOverlay(grabberStretchZSphere, { position: stretchZPos }); - Overlays.editOverlay(grabberStretchZPanel, { position: stretchZPos, rotation:worldRotationX }); - - if (!isActiveTool(grabberRotatePitchRing)) { - Overlays.editOverlay(grabberRotatePitchRing, { position: SelectionManager.worldPosition, rotation: worldRotationY }); - } - if (!isActiveTool(grabberRotateYawRing)) { - Overlays.editOverlay(grabberRotateYawRing, { position: SelectionManager.worldPosition, rotation: worldRotationZ }); - } - if (!isActiveTool(grabberRotateRollRing)) { - Overlays.editOverlay(grabberRotateRollRing, { position: SelectionManager.worldPosition, rotation: worldRotationX }); - } - - var grabberScaleLBNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleLBNCube, { position:grabberScaleLBNCubePos }); - var grabberScaleRBNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleRBNCube, { position:grabberScaleRBNCubePos }); - var grabberScaleLBFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleLBFCube, { position:grabberScaleLBFCubePos }); - var grabberScaleRBFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:-GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleRBFCube, { position:grabberScaleRBFCubePos }); - var grabberScaleLTNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleLTNCube, { position:grabberScaleLTNCubePos }); - var grabberScaleRTNCubePos = Vec3.sum(worldPosition, { x:-GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleRTNCube, { position:grabberScaleRTNCubePos }); - var grabberScaleLTFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:-GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleLTFCube, { position:grabberScaleLTFCubePos }); - var grabberScaleRTFCubePos = Vec3.sum(worldPosition, { x:GRABBER_SCALE_CUBE_OFFSET, y:GRABBER_SCALE_CUBE_OFFSET, z:GRABBER_SCALE_CUBE_OFFSET }); - Overlays.editOverlay(grabberScaleRTFCube, { position:grabberScaleRTFCubePos }); - - Overlays.editOverlay(grabberScaleTREdge, { start: grabberScaleRTNCubePos, end:grabberScaleRTFCubePos }); - Overlays.editOverlay(grabberScaleTLEdge, { start: grabberScaleLTNCubePos, end:grabberScaleLTFCubePos }); - Overlays.editOverlay(grabberScaleTFEdge, { start: grabberScaleLTFCubePos, end:grabberScaleRTFCubePos }); - Overlays.editOverlay(grabberScaleTNEdge, { start: grabberScaleLTNCubePos, end:grabberScaleRTNCubePos }); - Overlays.editOverlay(grabberScaleBREdge, { start: grabberScaleRBNCubePos, end:grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleBLEdge, { start: grabberScaleLBNCubePos, end:grabberScaleLBFCubePos }); - Overlays.editOverlay(grabberScaleBFEdge, { start: grabberScaleLBFCubePos, end:grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleBNEdge, { start: grabberScaleLBNCubePos, end:grabberScaleRBNCubePos }); - Overlays.editOverlay(grabberScaleNREdge, { start: grabberScaleRTNCubePos, end:grabberScaleRBNCubePos }); - Overlays.editOverlay(grabberScaleNLEdge, { start: grabberScaleLTNCubePos, end:grabberScaleLBNCubePos }); - Overlays.editOverlay(grabberScaleFREdge, { start: grabberScaleRTFCubePos, end:grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleFLEdge, { start: grabberScaleLTFCubePos, end:grabberScaleLBFCubePos }); - } - }; - Script.update.connect(that.updateHandlePositionRotation); - // FUNCTION: SET SPACE MODE that.setSpaceMode = function(newSpaceMode) { var wantDebug = false; @@ -1237,7 +1319,7 @@ SelectionDisplay = (function() { print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode); } spaceMode = newSpaceMode; - that.updateHandles(); + that.updateGrabbers(); } else if (wantDebug) { print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " + spaceMode + " DesiredMode: " + newSpaceMode); } @@ -1246,23 +1328,243 @@ SelectionDisplay = (function() { } }; - // FUNCTION: UPDATE HANDLES - that.updateHandles = function() { + // FUNCTION: UPDATE GRABBERS + that.updateGrabbers = function() { var wantDebug = false; if (wantDebug) { - print("======> Update Handles ======="); + print("======> Update Grabbers ======="); print(" Selections Count: " + SelectionManager.selections.length); print(" SpaceMode: " + spaceMode); print(" DisplayMode: " + getMode()); } + if (SelectionManager.selections.length === 0) { that.setOverlaysVisible(false); return; } - var isSingleSelection = (SelectionManager.selections.length === 1); - if (isSingleSelection) { - }// end of isSingleSelection + if (SelectionManager.hasSelection()) { + var worldPosition = SelectionManager.worldPosition; + var worldRotation = SelectionManager.worldRotation; + var worldDimensions = SelectionManager.worldDimensions; + + var worldDimensionsX = worldDimensions.x; + var worldDimensionsY = worldDimensions.y; + var worldDimensionsZ = worldDimensions.z; + var dimensionAverage = (worldDimensionsX + worldDimensionsY + worldDimensionsZ) / 3; + + var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); + worldRotationX = Quat.multiply(worldRotation, localRotationX); + var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); + worldRotationY = Quat.multiply(worldRotation, localRotationY); + var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); + worldRotationZ = Quat.multiply(worldRotation, localRotationZ); + + var arrowCylinderDimension = dimensionAverage * GRABBER_TRANSLATE_ARROW_CYLINDER_DIMENSION_MULTIPLE; + var arrowCylinderDimensions = { x:arrowCylinderDimension, y:arrowCylinderDimension * GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE, z:arrowCylinderDimension }; + var arrowConeDimension = dimensionAverage * GRABBER_TRANSLATE_ARROW_CONE_DIMENSION_MULTIPLE; + var arrowConeDimensions = { x:arrowConeDimension, y:arrowConeDimension, z:arrowConeDimension }; + var cylinderXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage, y:0, z:0 })); + Overlays.editOverlay(grabberTranslateXCylinder, { + position: cylinderXPos, + rotation: worldRotationX, + dimensions: arrowCylinderDimensions + }); + var cylinderXDiff = Vec3.subtract(cylinderXPos, worldPosition); + var coneXPos = Vec3.sum(cylinderXPos, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(grabberTranslateXCone, { + position: coneXPos, + rotation: worldRotationX, + dimensions: arrowConeDimensions + }); + var cylinderYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage, z:0 })); + Overlays.editOverlay(grabberTranslateYCylinder, { + position: cylinderYPos, + rotation: worldRotationY, + dimensions: arrowCylinderDimensions + }); + var cylinderYDiff = Vec3.subtract(cylinderYPos, worldPosition); + var coneYPos = Vec3.sum(cylinderYPos, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(grabberTranslateYCone, { + position: coneYPos, + rotation: worldRotationY, + dimensions: arrowConeDimensions + }); + var cylinderZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage })); + Overlays.editOverlay(grabberTranslateZCylinder, { + position: cylinderZPos, + rotation: worldRotationZ, + dimensions: arrowCylinderDimensions + }); + var cylinderZDiff = Vec3.subtract(cylinderZPos, worldPosition); + var coneZPos = Vec3.sum(cylinderZPos, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(grabberTranslateZCone, { + position: coneZPos, + rotation: worldRotationZ, + dimensions: arrowConeDimensions + }); + + var grabberScaleCubeOffsetX = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsX; + var grabberScaleCubeOffsetY = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsY; + var grabberScaleCubeOffsetZ = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsZ; + var scaleDimension = dimensionAverage * GRABBER_SCALE_CUBE_DIMENSION_MULTIPLE; + var scaleDimensions = { x:scaleDimension, y:scaleDimension, z:scaleDimension }; + var grabberScaleLBNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleLBNCube, { + position: grabberScaleLBNCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleRBNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleRBNCube, { + position: grabberScaleRBNCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleLBFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleLBFCube, { + position: grabberScaleLBFCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleRBFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleRBFCube, { + position: grabberScaleRBFCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleLTNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleLTNCube, { + position: grabberScaleLTNCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleRTNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleRTNCube, { + position: grabberScaleRTNCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleLTFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleLTFCube, { + position: grabberScaleLTFCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + var grabberScaleRTFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + Overlays.editOverlay(grabberScaleRTFCube, { + position: grabberScaleRTFCubePos, + rotation: worldRotation, + dimensions: scaleDimensions + }); + + Overlays.editOverlay(grabberScaleTREdge, { start: grabberScaleRTNCubePos, end: grabberScaleRTFCubePos }); + Overlays.editOverlay(grabberScaleTLEdge, { start: grabberScaleLTNCubePos, end: grabberScaleLTFCubePos }); + Overlays.editOverlay(grabberScaleTFEdge, { start: grabberScaleLTFCubePos, end: grabberScaleRTFCubePos }); + Overlays.editOverlay(grabberScaleTNEdge, { start: grabberScaleLTNCubePos, end: grabberScaleRTNCubePos }); + Overlays.editOverlay(grabberScaleBREdge, { start: grabberScaleRBNCubePos, end: grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleBLEdge, { start: grabberScaleLBNCubePos, end: grabberScaleLBFCubePos }); + Overlays.editOverlay(grabberScaleBFEdge, { start: grabberScaleLBFCubePos, end: grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleBNEdge, { start: grabberScaleLBNCubePos, end: grabberScaleRBNCubePos }); + Overlays.editOverlay(grabberScaleNREdge, { start: grabberScaleRTNCubePos, end: grabberScaleRBNCubePos }); + Overlays.editOverlay(grabberScaleNLEdge, { start: grabberScaleLTNCubePos, end: grabberScaleLBNCubePos }); + Overlays.editOverlay(grabberScaleFREdge, { start: grabberScaleRTFCubePos, end: grabberScaleRBFCubePos }); + Overlays.editOverlay(grabberScaleFLEdge, { start: grabberScaleLTFCubePos, end: grabberScaleLBFCubePos }); + + var stretchSphereDimension = dimensionAverage * GRABBER_STRETCH_SPHERE_DIMENSION_MULTIPLE; + var stretchSphereDimensions = { x:stretchSphereDimension, y:stretchSphereDimension, z:stretchSphereDimension }; + var stretchXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsX, y:0, z:0 })); + Overlays.editOverlay(grabberStretchXSphere, { + position: stretchXPos, + dimensions: stretchSphereDimensions + }); + var stretchPanelXDimensions = Vec3.subtract(grabberScaleLTFCubePos, grabberScaleRBFCubePos); + var tempY = Math.abs(stretchPanelXDimensions.y); + stretchPanelXDimensions.x = 0.01; + stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); + stretchPanelXDimensions.z = tempY; + Overlays.editOverlay(grabberStretchXPanel, { + position: stretchXPos, + rotation: worldRotationZ, + dimensions: stretchPanelXDimensions + }); + var stretchYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsY, z:0 })); + Overlays.editOverlay(grabberStretchYSphere, { + position: stretchYPos, + dimensions: stretchSphereDimensions + }); + var stretchPanelYDimensions = Vec3.subtract(grabberScaleLTFCubePos, grabberScaleRTNCubePos); + var tempX = Math.abs(stretchPanelYDimensions.x); + stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); + stretchPanelYDimensions.y = 0.01; + stretchPanelYDimensions.z = tempX; + Overlays.editOverlay(grabberStretchYPanel, { + position: stretchYPos, + rotation: worldRotationY, + dimensions: stretchPanelYDimensions + }); + var stretchZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsZ })); + Overlays.editOverlay(grabberStretchZSphere, { + position: stretchZPos, + dimensions: stretchSphereDimensions + }); + var stretchPanelZDimensions = Vec3.subtract(grabberScaleRTFCubePos, grabberScaleRBNCubePos); + var tempX = Math.abs(stretchPanelZDimensions.x); + stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); + stretchPanelZDimensions.y = tempX; + stretchPanelZDimensions.z = 0.01; + Overlays.editOverlay(grabberStretchZPanel, { + position: stretchZPos, + rotation: worldRotationX, + dimensions: stretchPanelZDimensions + }); + + var rotateDimension = dimensionAverage * GRABBER_ROTATE_RINGS_DIMENSION_MULTIPLE; + var rotateDimensions = { x:rotateDimension, y:rotateDimension, z:rotateDimension }; + if (!isActiveTool(grabberRotatePitchRing)) { + Overlays.editOverlay(grabberRotatePitchRing, { + position: SelectionManager.worldPosition, + rotation: worldRotationY, + dimensions: rotateDimensions + }); + } + if (!isActiveTool(grabberRotateYawRing)) { + Overlays.editOverlay(grabberRotateYawRing, { + position: SelectionManager.worldPosition, + rotation: worldRotationZ, + dimensions: rotateDimensions + }); + } + if (!isActiveTool(grabberRotateRollRing)) { + Overlays.editOverlay(grabberRotateRollRing, { + position: SelectionManager.worldPosition, + rotation: worldRotationX, + dimensions: rotateDimensions + }); + } + Overlays.editOverlay(grabberRotateCurrentRing, { dimensions: rotateDimensions }); + + var inModeRotate = isActiveTool(grabberRotatePitchRing) || isActiveTool(grabberRotateYawRing) || isActiveTool(grabberRotateRollRing); + var inModeTranslate = isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder) || + isActiveTool(grabberTranslateYCone) || isActiveTool(grabberTranslateYCylinder) || + isActiveTool(grabberTranslateZCone) || isActiveTool(grabberTranslateZCylinder) || + isActiveTool(grabberCloner) || isActiveTool(selectionBox); + + Overlays.editOverlay(selectionBox, { + position: worldPosition, + rotation: worldRotation, + dimensions: worldDimensions, + visible: !inModeRotate + }); + + var grabberClonerOffset = { x:GRABBER_CLONER_OFFSET.x * worldDimensionsX, y:GRABBER_CLONER_OFFSET.y * worldDimensionsY, z:GRABBER_CLONER_OFFSET.z * worldDimensionsZ }; + var grabberClonerPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, grabberClonerOffset)); + Overlays.editOverlay(grabberCloner, { + position: grabberClonerPos, + rotation: worldRotation, + dimensions: scaleDimensions, + }); + } that.setGrabberTranslateXVisible(!activeTool || isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder)); that.setGrabberTranslateYVisible(!activeTool || isActiveTool(grabberTranslateYCone) || isActiveTool(grabberTranslateYCylinder)); @@ -1275,9 +1577,10 @@ SelectionDisplay = (function() { that.setGrabberStretchZVisible(!activeTool || isActiveTool(grabberStretchZSphere)); that.setGrabberScaleVisible(!activeTool || isActiveTool(grabberScaleLBNCube) || isActiveTool(grabberScaleRBNCube) || isActiveTool(grabberScaleLBFCube) || isActiveTool(grabberScaleRBFCube) || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube)); + that.setGrabberClonerVisible(!activeTool || isActiveTool(grabberCloner)); if (wantDebug) { - print("====== Update Handles <======="); + print("====== Update Grabbers <======="); } }; @@ -1310,7 +1613,7 @@ SelectionDisplay = (function() { Overlays.editOverlay(grabberTranslateZCylinder, { visible: isVisible }); }; - // FUNCTION: SET GRABBER ROTATION VISIBLE + // FUNCTION: SET GRABBER ROTATE VISIBLE that.setGrabberRotateVisible = function(isVisible) { that.setGrabberRotatePitchVisible(isVisible); that.setGrabberRotateYawVisible(isVisible); @@ -1372,6 +1675,189 @@ SelectionDisplay = (function() { Overlays.editOverlay(grabberScaleFLEdge, { visible: isVisible }); }; + // FUNCTION: SET GRABBER CLONER VISIBLE + that.setGrabberClonerVisible = function(isVisible) { + Overlays.editOverlay(grabberCloner, { visible: isVisible }); + }; + + var initialXZPick = null; + var isConstrained = false; + var constrainMajorOnly = false; + var startPosition = null; + var duplicatedEntityIDs = null; + + // TOOL DEFINITION: TRANSLATE XZ TOOL + var translateXZTool = addGrabberTool(selectionBox, { + mode: 'TRANSLATE_XZ', + pickPlanePosition: { x: 0, y: 0, z: 0 }, + greatestDimension: 0.0, + startingDistance: 0.0, + startingElevation: 0.0, + onBegin: function(event, pickRay, pickResult, doClone) { + var wantDebug = false; + if (wantDebug) { + print("================== TRANSLATE_XZ(Beg) -> ======================="); + Vec3.print(" pickRay", pickRay); + Vec3.print(" pickRay.origin", pickRay.origin); + Vec3.print(" pickResult.intersection", pickResult.intersection); + } + + SelectionManager.saveProperties(); + + that.setGrabberTranslateVisible(false); + that.setGrabberRotateVisible(false); + that.setGrabberScaleVisible(false); + that.setGrabberStretchVisible(false); + that.setGrabberClonerVisible(false); + + startPosition = SelectionManager.worldPosition; + + translateXZTool.pickPlanePosition = pickResult.intersection; + translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); + translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); + translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); + if (wantDebug) { + print(" longest dimension: " + translateXZTool.greatestDimension); + print(" starting distance: " + translateXZTool.startingDistance); + print(" starting elevation: " + translateXZTool.startingElevation); + } + + initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { + x: 0, + y: 1, + z: 0 + }); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt || doClone) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties + }); + } + } + } else { + duplicatedEntityIDs = null; + } + + isConstrained = false; + if (wantDebug) { + print("================== TRANSLATE_XZ(End) <- ======================="); + } + }, + onEnd: function(event, reason) { + pushCommandForSelections(duplicatedEntityIDs); + }, + elevation: function(origin, intersection) { + return (origin.y - intersection.y) / Vec3.distance(origin, intersection); + }, + onMove: function(event) { + var wantDebug = false; + pickRay = generalComputePickRay(event.x, event.y); + + var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { + x: 0, + y: 1, + z: 0 + }); + + // If the pick ray doesn't hit the pick plane in this direction, do nothing. + // this will happen when someone drags across the horizon from the side they started on. + if (!pick) { + if (wantDebug) { + print(" "+ translateXZTool.mode + "Pick ray does not intersect XZ plane."); + } + + // EARLY EXIT--(Invalid ray detected.) + return; + } + + var vector = Vec3.subtract(pick, initialXZPick); + + // If the mouse is too close to the horizon of the pick plane, stop moving + var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it + var elevation = translateXZTool.elevation(pickRay.origin, pick); + if (wantDebug) { + print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); + } + if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || + (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { + if (wantDebug) { + print(" "+ translateXZTool.mode + " - too close to horizon!"); + } + + // EARLY EXIT--(Don't proceed past the reached limit.) + return; + } + + // If the angular size of the object is too small, stop moving + var MIN_ANGULAR_SIZE = 0.01; // Radians + if (translateXZTool.greatestDimension > 0) { + var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); + if (wantDebug) { + print("Angular size = " + angularSize); + } + if (angularSize < MIN_ANGULAR_SIZE) { + return; + } + } + + // If shifted, constrain to one axis + if (event.isShifted) { + if (Math.abs(vector.x) > Math.abs(vector.z)) { + vector.z = 0; + } else { + vector.x = 0; + } + if (!isConstrained) { + isConstrained = true; + } + } else { + if (isConstrained) { + isConstrained = false; + } + } + + constrainMajorOnly = event.isControl; + var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, SelectionManager.worldDimensions)); + vector = Vec3.subtract( + grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), + cornerPosition); + + + for (var i = 0; i < SelectionManager.selections.length; i++) { + var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; + if (!properties) { + continue; + } + var newPosition = Vec3.sum(properties.position, { + x: vector.x, + y: 0, + z: vector.z + }); + Entities.editEntity(SelectionManager.selections[i], { + position: newPosition + }); + + if (wantDebug) { + print("translateXZ... "); + Vec3.print(" vector:", vector); + Vec3.print(" newPosition:", properties.position); + Vec3.print(" newPosition:", newPosition); + } + } + + SelectionManager._update(); + } + }); + addGrabberTranslateTool(grabberTranslateXCone, "TRANSLATE_X", TRANSLATE_DIRECTION.X); addGrabberTranslateTool(grabberTranslateXCylinder, "TRANSLATE_X", TRANSLATE_DIRECTION.X); addGrabberTranslateTool(grabberTranslateYCone, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); @@ -1383,9 +1869,9 @@ SelectionDisplay = (function() { addGrabberRotateTool(grabberRotateYawRing, "ROTATE_YAW", ROTATE_DIRECTION.YAW); addGrabberRotateTool(grabberRotateRollRing, "ROTATE_ROLL", ROTATE_DIRECTION.ROLL); - addGrabberStretchTool(grabberStretchXSphere, "STRETCH_X", TRANSLATE_DIRECTION.X); - addGrabberStretchTool(grabberStretchYSphere, "STRETCH_Y", TRANSLATE_DIRECTION.Y); - addGrabberStretchTool(grabberStretchZSphere, "STRETCH_Z", TRANSLATE_DIRECTION.Z); + addGrabberStretchTool(grabberStretchXSphere, "STRETCH_X", STRETCH_DIRECTION.X); + addGrabberStretchTool(grabberStretchYSphere, "STRETCH_Y", STRETCH_DIRECTION.Y); + addGrabberStretchTool(grabberStretchZSphere, "STRETCH_Z", STRETCH_DIRECTION.Z); addGrabberScaleTool(grabberScaleLBNCube, "SCALE_LBN", SCALE_DIRECTION.LBN); addGrabberScaleTool(grabberScaleRBNCube, "SCALE_RBN", SCALE_DIRECTION.RBN); @@ -1396,19 +1882,28 @@ SelectionDisplay = (function() { addGrabberScaleTool(grabberScaleLTFCube, "SCALE_LTF", SCALE_DIRECTION.LTF); addGrabberScaleTool(grabberScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF); + // GRABBER TOOL: GRABBER CLONER + addGrabberTool(grabberCloner, { + mode: "CLONE", + onBegin: function(event, pickRay, pickResult) { + var doClone = true; + translateXZTool.onBegin(event,pickRay,pickResult,doClone); + }, + elevation: function (event) { + translateXZTool.elevation(event); + }, + + onEnd: function (event) { + translateXZTool.onEnd(event); + }, + + onMove: function (event) { + translateXZTool.onMove(event); + } + }); + // FUNCTION: CHECK MOVE that.checkMove = function() { - if (SelectionManager.hasSelection()) { - - // FIXME - this cause problems with editing in the entity properties window - // SelectionManager._update(); - - if (!Vec3.equal(Camera.getPosition(), lastCameraPosition) || - !Quat.equal(Camera.getOrientation(), lastCameraOrientation)) { - - //that.updateRotationHandles(); - } - } }; that.checkControllerMove = function() { @@ -1583,4 +2078,4 @@ SelectionDisplay = (function() { Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); return that; -}()); +}()); \ No newline at end of file From 6a035578017935304c77ac8821a5dc5d49f3d3cf Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 23 Jan 2018 14:44:10 -0800 Subject: [PATCH 038/272] don't override sensorToWorldMatrix --- interface/src/avatar/MyAvatar.cpp | 10 ++++++---- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e93b897013..2943cf7fd8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1790,7 +1790,7 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes } -void MyAvatar::initAnimGraph() { +void MyAvatar::initAnimGraph(bool updateBodySensorMat) { QUrl graphUrl; if (!_prefOverrideAnimGraphUrl.get().isEmpty()) { graphUrl = _prefOverrideAnimGraphUrl.get(); @@ -1803,8 +1803,10 @@ void MyAvatar::initAnimGraph() { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + if (updateBodySensorMat) { + _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + } } void MyAvatar::destroyAnimGraph() { @@ -1819,7 +1821,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(); + initAnimGraph(false); _isAnimatingScale = true; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 58b49b61ff..cdcd6f4607 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -730,7 +730,7 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void initHeadBones(); - void initAnimGraph(); + void initAnimGraph(bool updateBodySensorMat = true); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; From 2cbcc28bd4c860a45e0e050ae959537c6b795a02 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 24 Jan 2018 10:44:04 -0800 Subject: [PATCH 039/272] only call init animGraph once --- interface/src/avatar/MyAvatar.cpp | 27 +++++++++++++++------------ interface/src/avatar/MyAvatar.h | 4 +++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1475860665..5f2cbf92b2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1785,12 +1785,10 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { _currentAnimGraphUrl.set(url); _skeletonModel->getRig().initAnimGraph(url); - - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } -void MyAvatar::initAnimGraph(bool updateBodySensorMat) { +void MyAvatar::initAnimGraph() { QUrl graphUrl; if (!_prefOverrideAnimGraphUrl.get().isEmpty()) { graphUrl = _prefOverrideAnimGraphUrl.get(); @@ -1802,27 +1800,32 @@ void MyAvatar::initAnimGraph(bool updateBodySensorMat) { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); - - if (updateBodySensorMat) { - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - } + connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } void MyAvatar::destroyAnimGraph() { _skeletonModel->getRig().destroyAnimGraph(); } +void MyAvatar::animGraphLoaded() { + _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + _isAnimatingScale = true; + disconnect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); +} + void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { Avatar::postUpdate(deltaTime, scene); - if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) { + if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode() && _initHeadBones) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(false); - _isAnimatingScale = true; + initAnimGraph(); + _initHeadBones = false; + } else if (!_skeletonModel->isLoaded()) { + _initHeadBones = true; } if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cdcd6f4607..6a9e0e6a38 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -566,6 +566,7 @@ public slots: void increaseSize(); void decreaseSize(); void resetSize(); + void animGraphLoaded(); void setGravity(float gravity); float getGravity(); @@ -730,7 +731,7 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void initHeadBones(); - void initAnimGraph(bool updateBodySensorMat = true); + void initAnimGraph(); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; @@ -808,6 +809,7 @@ private: bool _enableDebugDrawIKConstraints { false }; bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; + bool _initHeadBones { false }; AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; From b7ba7862aa929a501a7fec542974d6ce3ebb4d5c Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 24 Jan 2018 11:18:42 -0800 Subject: [PATCH 040/272] give animGrapgh loader a high priority --- libraries/animation/src/AnimNodeLoader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 33f3d72756..8173845205 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -38,6 +38,8 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q static AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); +static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f; + // called after children have been loaded // returns node on success, nullptr on failure. static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; } @@ -653,6 +655,7 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) : { _resource = QSharedPointer::create(url); _resource->setSelf(_resource); + _resource->setLoadPriority(this, ANIM_GRAPH_LOAD_PRIORITY); connect(_resource.data(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone); connect(_resource.data(), &Resource::failed, this, &AnimNodeLoader::onRequestError); _resource->ensureLoading(); From c96e395a46df93b652a22d605f2b2ceb4bf68b64 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 25 Jan 2018 12:13:32 -0800 Subject: [PATCH 041/272] 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 042/272] 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 043/272] 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 6b0b17ff633f72bb16171da4f34ad9f672ecefec Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 26 Jan 2018 17:57:20 +0100 Subject: [PATCH 044/272] Working on better adaptive bias algorithm for shadow --- libraries/render-utils/src/LightStage.cpp | 8 ++--- libraries/render-utils/src/LightStage.h | 2 +- .../render-utils/src/RenderShadowTask.cpp | 10 ++++-- libraries/render-utils/src/RenderShadowTask.h | 16 ++++++++- libraries/render-utils/src/Shadow.slh | 17 +++++---- .../src/directional_ambient_light_shadow.slf | 4 ++- .../src/directional_skybox_light_shadow.slf | 4 ++- scripts/developer/utilities/render/shadow.qml | 35 +++++++++++++++++++ 8 files changed, 77 insertions(+), 19 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index f146cd6e0a..eac9dd7657 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -220,7 +220,7 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, } void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth, float farDepth) { + float nearDepth, float farDepth, float baseBias) { assert(nearDepth < farDepth); assert(cascadeIndex < _cascades.size()); @@ -270,11 +270,7 @@ void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, co // Update the buffer auto& schema = _schemaBuffer.edit(); schema.cascades[cascadeIndex].reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix(); - // Adapt shadow bias to shadow resolution with a totally empirical formula - const auto maxShadowFrustumDim = std::max(fabsf(min.x - max.x), fabsf(min.y - max.y)); - const auto REFERENCE_TEXEL_DENSITY = 7.5f; - const auto cascadeTexelDensity = MAP_SIZE / maxShadowFrustumDim; - schema.cascades[cascadeIndex].bias = MAX_BIAS * std::min(1.0f, REFERENCE_TEXEL_DENSITY / cascadeTexelDensity); + schema.cascades[cascadeIndex].bias = baseBias; } void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum) { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index d1a8680706..c2c2df8c89 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -80,7 +80,7 @@ public: void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth = 1.0f, float farDepth = 1000.0f); void setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth = 1.0f, float farDepth = 1000.0f); + float nearDepth = 1.0f, float farDepth = 1000.0f, float baseBias = 0.005f); void setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum); const UniformBufferView& getBuffer() const { return _schemaBuffer; } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d83dfd73a5..f41860b6de 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -216,7 +216,9 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende task.addJob("ShadowSetup"); for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { - const auto setupOutput = task.addJob("ShadowCascadeSetup", i); + char jobName[64]; + sprintf(jobName, "ShadowCascadeSetup%d", i); + const auto setupOutput = task.addJob(jobName, i); const auto shadowFilter = setupOutput.getN(1); // CPU jobs: @@ -253,6 +255,10 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext) { } } +void RenderShadowCascadeSetup::configure(const Config& configuration) { + _baseBias = configuration.bias * configuration.bias * 0.01f; +} + void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); @@ -266,7 +272,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon if (globalShadow && _cascadeIndexgetCascadeCount()) { output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); + globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, _baseBias); // Set the keylight render args args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum())); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index d8d4c624e7..42c279c02a 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -62,17 +62,31 @@ public: }; +class RenderShadowCascadeSetupConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(float bias MEMBER bias NOTIFY dirty) +public: + + float bias{ 0.5f }; + +signals: + void dirty(); +}; + class RenderShadowCascadeSetup { public: using Outputs = render::VaryingSet3; - using JobModel = render::Job::ModelO; + using Config = RenderShadowCascadeSetupConfig; + using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} + void configure(const Config& configuration); void run(const render::RenderContextPointer& renderContext, Outputs& output); private: unsigned int _cascadeIndex; + float _baseBias{ 0.1f }; }; class RenderShadowCascadeTeardown { diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index a12dd0f4a4..50ae8864f4 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -83,27 +83,30 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve return shadowAttenuation; } -float evalShadowCascadeAttenuation(int cascadeIndex, vec3 viewNormal, ShadowSampleOffsets offsets, vec4 shadowTexcoord) { +float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float bias) { if (!isShadowCascadeProjectedOnPixel(shadowTexcoord)) { // If a point is not in the map, do not attenuate return 1.0; } - // Multiply bias if we are at a grazing angle with light - float tangentFactor = abs(dot(getShadowDirInViewSpace(), viewNormal)); - float bias = getShadowBias(cascadeIndex) * (5.0-4.0*tangentFactor); + // Add fixed bias + bias += getShadowBias(cascadeIndex); return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias); } -float evalShadowAttenuation(vec4 worldPosition, float viewDepth, vec3 viewNormal) { +float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDepth, vec3 worldNormal) { ShadowSampleOffsets offsets = evalShadowFilterOffsets(worldPosition); vec4 cascadeShadowCoords[2]; ivec2 cascadeIndices; float cascadeMix = determineShadowCascadesOnPixel(worldPosition, viewDepth, cascadeShadowCoords, cascadeIndices); + // Adjust bias if we are at a grazing angle with light + float ndotl = dot(worldLightDir, worldNormal); + float bias = 0.5*(1.0/(ndotl*ndotl)-1.0); + bias *= getShadowScale(); vec2 cascadeAttenuations = vec2(1.0, 1.0); - cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, viewNormal, offsets, cascadeShadowCoords[0]); + cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[0], bias); if (cascadeMix > 0.0 && cascadeIndices.y < getShadowCascadeCount()) { - cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, viewNormal, offsets, cascadeShadowCoords[1]); + cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[1], bias); } float attenuation = mix(cascadeAttenuations.x, cascadeAttenuations.y, cascadeMix); // Falloff to max distance diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf index f7ea8c5966..eead392fd8 100644 --- a/libraries/render-utils/src/directional_ambient_light_shadow.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -28,7 +28,9 @@ void main(void) { vec4 viewPos = vec4(frag.position.xyz, 1.0); vec4 worldPos = getViewInverse() * viewPos; - float shadowAttenuation = evalShadowAttenuation(worldPos, -viewPos.z, frag.normal); + Light shadowLight = getKeyLight(); + vec3 worldLightDirection = getLightDirection(shadowLight); + float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal); if (frag.mode == FRAG_MODE_UNLIT) { discard; diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index 37c9ae7fba..2a2f8f65a3 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -28,7 +28,9 @@ void main(void) { vec4 viewPos = vec4(frag.position.xyz, 1.0); vec4 worldPos = getViewInverse() * viewPos; - float shadowAttenuation = evalShadowAttenuation(worldPos, -viewPos.z, frag.normal); + Light shadowLight = getKeyLight(); + vec3 worldLightDirection = getLightDirection(shadowLight); + float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal); // Light mapped or not ? if (frag.mode == FRAG_MODE_UNLIT) { diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index a8fcf1aec7..32405a5260 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -10,6 +10,9 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls +import "configSlider" Column { id: root @@ -68,4 +71,36 @@ Column { font.italic: true } } + ConfigSlider { + label: qsTr("Cascade 0 bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup0") + property: "bias" + max: 1.0 + min: 0.01 + } + ConfigSlider { + label: qsTr("Cascade 1 bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup1") + property: "bias" + max: 1.0 + min: 0.01 + } + ConfigSlider { + label: qsTr("Cascade 2 bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup2") + property: "bias" + max: 1.0 + min: 0.01 + } + ConfigSlider { + label: qsTr("Cascade 3 bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup3") + property: "bias" + max: 1.0 + min: 0.01 + } } From aa82ad885561411daf1d97778193f22cd18b612b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 26 Jan 2018 14:57:36 -0800 Subject: [PATCH 045/272] 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 046/272] 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 047/272] 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 048/272] 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 0324f41565c77acdda2d326560aeba2a2f260498 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 29 Jan 2018 17:23:35 +0100 Subject: [PATCH 049/272] Trying to improve adaptive shadow bias --- libraries/render-utils/src/LightStage.cpp | 35 ++++++++++++++----- libraries/render-utils/src/LightStage.h | 3 ++ .../render-utils/src/RenderShadowTask.cpp | 4 ++- libraries/render-utils/src/RenderShadowTask.h | 2 +- libraries/render-utils/src/Shadow.slh | 15 +++++--- libraries/render-utils/src/ShadowCore.slh | 14 ++++++-- libraries/render-utils/src/Shadows_shared.slh | 8 ++--- 7 files changed, 58 insertions(+), 23 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index eac9dd7657..e06d24f1b1 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -23,8 +23,6 @@ const glm::mat4 LightStage::Shadow::_biasMatrix{ 0.5, 0.5, 0.5, 1.0 }; const int LightStage::Shadow::MAP_SIZE = 1024; -static const auto MAX_BIAS = 0.006f; - const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; LightStage::LightStage() { @@ -63,7 +61,7 @@ LightStage::LightStage() { LightStage::Shadow::Schema::Schema() { ShadowTransform defaultTransform; - defaultTransform.bias = MAX_BIAS; + defaultTransform.fixedBias = 0.005f; std::fill(cascades, cascades + SHADOW_CASCADE_MAX_COUNT, defaultTransform); invMapSize = 1.0f / MAP_SIZE; cascadeCount = 1; @@ -72,6 +70,18 @@ LightStage::Shadow::Schema::Schema() { maxDistance = 20.0f; } +void LightStage::Shadow::Schema::updateCascade(int cascadeIndex, const ViewFrustum& shadowFrustum) { + auto& cascade = cascades[cascadeIndex]; + cascade.frustumPosition = shadowFrustum.getPosition(); + // The adaptative bias is computing how much depth offset we have to add to + // push back a coarsely sampled surface perpendicularly to the shadow direction, + // to not have shadow acnee. The final computation is done in the shader, based on the + // surface normal. + auto maxWorldFrustumSize = glm::max(shadowFrustum.getWidth(), shadowFrustum.getHeight()); + cascade.adaptiveBiasUnitScale = maxWorldFrustumSize * 0.5f * invMapSize; + cascade.adaptiveBiasTransformScale = shadowFrustum.getNearClip() * shadowFrustum.getFarClip() / (shadowFrustum.getFarClip() - shadowFrustum.getNearClip()); +} + LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared() }, _minDistance{ 0.0f }, @@ -210,13 +220,15 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, // Position the keylight frustum auto position = viewFrustum.getPosition() - (nearDepth + farDepth)*lightDirection; + // Update the buffer + auto& schema = _schemaBuffer.edit(); + auto cascadeIndex = 0; for (auto& cascade : _cascades) { cascade._frustum->setOrientation(orientation); cascade._frustum->setPosition(position); + schema.cascades[cascadeIndex].frustumPosition = position; + cascadeIndex++; } - // Update the buffer - auto& schema = _schemaBuffer.edit(); - schema.lightDirInViewSpace = glm::inverse(viewFrustum.getView()) * glm::vec4(lightDirection, 0.f); } void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, @@ -269,8 +281,10 @@ void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, co // Update the buffer auto& schema = _schemaBuffer.edit(); - schema.cascades[cascadeIndex].reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix(); - schema.cascades[cascadeIndex].bias = baseBias; + auto& schemaCascade = schema.cascades[cascadeIndex]; + schemaCascade.reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix(); + schemaCascade.fixedBias = baseBias; + schema.updateCascade(cascadeIndex, *cascade._frustum); } void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum) { @@ -281,7 +295,10 @@ void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const View *cascade._frustum = shadowFrustum; // Update the buffer - _schemaBuffer.edit().cascades[cascadeIndex].reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); + auto& schema = _schemaBuffer.edit(); + auto& schemaCascade = schema.cascades[cascadeIndex]; + schemaCascade.reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); + schema.updateCascade(cascadeIndex, shadowFrustum); } LightStage::Index LightStage::findLight(const LightPointer& light) const { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index c2c2df8c89..922ec5eb4a 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -110,6 +110,8 @@ public: Schema(); + void updateCascade(int cascadeIndex, const ViewFrustum& shadowFrustum); + }; UniformBufferView _schemaBuffer = nullptr; }; @@ -213,6 +215,7 @@ protected: Index _sunOffLightId; Index _defaultLightId; + }; using LightStagePointer = std::shared_ptr; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index f41860b6de..2172dda3e3 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -256,7 +256,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext) { } void RenderShadowCascadeSetup::configure(const Config& configuration) { - _baseBias = configuration.bias * configuration.bias * 0.01f; + // I'm not very proud of this empirical adjustment + auto cascadeBias = configuration.bias * powf(1.1f, _cascadeIndex); + _baseBias = cascadeBias * cascadeBias * 0.01f; } void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 42c279c02a..c4f0c65bfc 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -67,7 +67,7 @@ class RenderShadowCascadeSetupConfig : public render::Job::Config { Q_PROPERTY(float bias MEMBER bias NOTIFY dirty) public: - float bias{ 0.5f }; + float bias{ 0.25f }; signals: void dirty(); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 50ae8864f4..c11f5fa6a7 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -83,11 +83,17 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve return shadowAttenuation; } -float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float bias) { +float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float bias, + vec3 worldPosition, vec3 worldLightDir) { if (!isShadowCascadeProjectedOnPixel(shadowTexcoord)) { // If a point is not in the map, do not attenuate return 1.0; } + // After this, bias is in view units + bias *= getShadowAdaptiveBiasUnitScale(cascadeIndex); + // Transform to texcoord space (between 0 and 1) + float shadowDepth = abs(dot(worldPosition-getShadowFrustumPosition(cascadeIndex), worldLightDir)); + bias = transformShadowAdaptiveBias(cascadeIndex, shadowDepth, bias); // Add fixed bias bias += getShadowBias(cascadeIndex); return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias); @@ -101,12 +107,11 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe // Adjust bias if we are at a grazing angle with light float ndotl = dot(worldLightDir, worldNormal); - float bias = 0.5*(1.0/(ndotl*ndotl)-1.0); - bias *= getShadowScale(); + float bias = 1.0/(ndotl*ndotl)-1.0; vec2 cascadeAttenuations = vec2(1.0, 1.0); - cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[0], bias); + cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[0], bias, worldPosition.xyz, worldLightDir); if (cascadeMix > 0.0 && cascadeIndices.y < getShadowCascadeCount()) { - cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[1], bias); + cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[1], bias, worldPosition.xyz, worldLightDir); } float attenuation = mix(cascadeAttenuations.x, cascadeAttenuations.y, cascadeMix); // Falloff to max distance diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index 9b3b086598..2d48e16ef4 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -38,11 +38,19 @@ float getShadowScale() { } float getShadowBias(int cascadeIndex) { - return shadow.cascades[cascadeIndex].bias; + return shadow.cascades[cascadeIndex].fixedBias; } -vec3 getShadowDirInViewSpace() { - return shadow.lightDirInViewSpace; +vec3 getShadowFrustumPosition(int cascadeIndex) { + return shadow.cascades[cascadeIndex].frustumPosition; +} + +float getShadowAdaptiveBiasUnitScale(int cascadeIndex) { + return shadow.cascades[cascadeIndex].adaptiveBiasUnitScale; +} + +float transformShadowAdaptiveBias(int cascadeIndex, float shadowDepth, float depthBias) { + return shadow.cascades[cascadeIndex].adaptiveBiasTransformScale * depthBias / (shadowDepth*shadowDepth); } // Compute the texture coordinates from world coordinates diff --git a/libraries/render-utils/src/Shadows_shared.slh b/libraries/render-utils/src/Shadows_shared.slh index abb226421c..def6b1b4d4 100644 --- a/libraries/render-utils/src/Shadows_shared.slh +++ b/libraries/render-utils/src/Shadows_shared.slh @@ -11,16 +11,16 @@ struct ShadowTransform { MAT4 reprojection; - - float bias; + VEC3 frustumPosition; + float fixedBias; + float adaptiveBiasUnitScale; + float adaptiveBiasTransformScale; float _padding1; float _padding2; - float _padding3; }; struct ShadowParameters { ShadowTransform cascades[SHADOW_CASCADE_MAX_COUNT]; - VEC3 lightDirInViewSpace; int cascadeCount; float invMapSize; float invCascadeBlendWidth; From 9ee715364185b913bf928864867278a11ac35af0 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 29 Jan 2018 16:53:02 -0800 Subject: [PATCH 050/272] fix scale speed, fix stretch panels, fix scale cube highlight --- .../system/libraries/entitySelectionTool.js | 96 +++++++++++-------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 253c67bfca..3da7d1f083 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -246,6 +246,7 @@ SelectionDisplay = (function() { var SCALE_MINIMUM_DIMENSION = 0.02; var STRETCH_MINIMUM_DIMENSION = 0.001; + var STRETCH_DIRECTION_ALL_FACTOR = 15; // These are multipliers for sizing the rotation degrees display while rotating an entity var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.0; @@ -266,12 +267,6 @@ SelectionDisplay = (function() { ALL : 3 } - var ROTATE_DIRECTION = { - PITCH : 0, - YAW : 1, - ROLL : 2 - } - var SCALE_DIRECTION = { LBN : 0, RBN : 1, @@ -283,6 +278,12 @@ SelectionDisplay = (function() { RTF : 7 } + var ROTATE_DIRECTION = { + PITCH : 0, + YAW : 1, + ROLL : 2 + } + var spaceMode = SPACE_LOCAL; var overlayNames = []; var lastCameraPosition = Camera.getPosition(); @@ -706,7 +707,7 @@ SelectionDisplay = (function() { }; }; - function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset) { + function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, scaleGrabber) { var directionFor3DStretch = directionVec; var distanceFor3DStretch = 0; var DISTANCE_INFLUENCE_THRESHOLD = 1.2; @@ -892,16 +893,29 @@ SelectionDisplay = (function() { that.setGrabberTranslateVisible(false); that.setGrabberRotateVisible(false); - that.setGrabberScaleVisible(directionEnum === STRETCH_DIRECTION.ALL); + that.setGrabberScaleVisible(true); that.setGrabberStretchXVisible(directionEnum === STRETCH_DIRECTION.X); that.setGrabberStretchYVisible(directionEnum === STRETCH_DIRECTION.Y); that.setGrabberStretchZVisible(directionEnum === STRETCH_DIRECTION.Z); that.setGrabberClonerVisible(false); + + if (stretchPanel != null) { + Overlays.editOverlay(stretchPanel, { visible: true }); + } + if (scaleGrabber != null) { + Overlays.editOverlay(scaleGrabber, { color: GRABBER_SCALE_CUBE_SELECTED_COLOR }); + } SelectionManager.saveProperties(); }; var onEnd = function(event, reason) { + if (stretchPanel != null) { + Overlays.editOverlay(stretchPanel, { visible: false }); + } + if (scaleGrabber != null) { + Overlays.editOverlay(scaleGrabber, { color: GRABBER_SCALE_CUBE_IDLE_COLOR }); + } pushCommandForSelections(); }; @@ -959,6 +973,11 @@ SelectionDisplay = (function() { vector = grid.snapToSpacing(vector); var changeInDimensions = Vec3.multiply(-1, vec3Mult(localSigns, vector)); + + if (directionEnum === STRETCH_DIRECTION.ALL) { + changeInDimensions = Vec3.multiply(changeInDimensions, STRETCH_DIRECTION_ALL_FACTOR); + } + var newDimensions; if (proportional) { var absX = Math.abs(changeInDimensions.x); @@ -1024,60 +1043,53 @@ SelectionDisplay = (function() { } function addGrabberStretchTool(overlay, mode, directionEnum) { - var directionVec, pivot, offset; + var directionVec, pivot, offset, stretchPanel; if (directionEnum === STRETCH_DIRECTION.X) { + stretchPanel = grabberStretchXPanel; directionVec = { x:-1, y:0, z:0 }; - pivot = { x:-1, y:0, z:0 }; - offset = { x:1, y:0, z:0 }; } else if (directionEnum === STRETCH_DIRECTION.Y) { + stretchPanel = grabberStretchYPanel; directionVec = { x:0, y:-1, z:0 }; - pivot = { x:0, y:-1, z:0 }; - offset = { x:0, y:1, z:0 }; } else if (directionEnum === STRETCH_DIRECTION.Z) { + stretchPanel = grabberStretchZPanel directionVec = { x:0, y:0, z:-1 }; - pivot = { x:0, y:0, z:-1 }; - offset = { x:0, y:0, z:1 }; } - var tool = makeStretchTool(mode, directionEnum, directionVec, pivot, offset); + pivot = directionVec; + offset = Vec3.multiply(directionVec, -1); + var tool = makeStretchTool(mode, directionEnum, directionVec, pivot, offset, stretchPanel, null); return addGrabberTool(overlay, tool); } function addGrabberScaleTool(overlay, mode, directionEnum) { - var directionVec, pivot, offset; + var directionVec, pivot, offset, selectedGrabber; if (directionEnum === SCALE_DIRECTION.LBN) { directionVec = { x:1, y:1, z:1 }; - pivot = { x:1, y:1, z:1 }; - offset = { x:-1, y:-1, z:-1 }; + selectedGrabber = grabberScaleLBNCube; } else if (directionEnum === SCALE_DIRECTION.RBN) { directionVec = { x:1, y:1, z:-1 }; - pivot = { x:1, y:1, z:-1 }; - offset = { x:-1, y:-1, z:1 }; + selectedGrabber = grabberScaleRBNCube; } else if (directionEnum === SCALE_DIRECTION.LBF) { directionVec = { x:-1, y:1, z:1 }; - pivot = { x:-1, y:1, z:1 }; - offset = { x:1, y:-1, z:-1 }; + selectedGrabber = grabberScaleLBFCube; } else if (directionEnum === SCALE_DIRECTION.RBF) { directionVec = { x:-1, y:1, z:-1 }; - pivot = { x:-1, y:1, z:-1 }; - offset = { x:1, y:-1, z:1 }; + selectedGrabber = grabberScaleRBFCube; } else if (directionEnum === SCALE_DIRECTION.LTN) { directionVec = { x:1, y:-1, z:1 }; - pivot = { x:1, y:-1, z:1 }; - offset = { x:-1, y:1, z:-1 }; + selectedGrabber = grabberScaleLTNCube; } else if (directionEnum === SCALE_DIRECTION.RTN) { directionVec = { x:1, y:-1, z:-1 }; - pivot = { x:1, y:-1, z:-1 }; - offset = { x:-1, y:1, z:1 }; + selectedGrabber = grabberScaleRTNCube; } else if (directionEnum === SCALE_DIRECTION.LTF) { directionVec = { x:-1, y:-1, z:1 }; - pivot = { x:-1, y:-1, z:1 }; - offset = { x:1, y:1, z:-1 }; + selectedGrabber = grabberScaleLTFCube; } else if (directionEnum === SCALE_DIRECTION.RTF) { directionVec = { x:-1, y:-1, z:-1 }; - pivot = { x:-1, y:-1, z:-1 }; - offset = { x:1, y:1, z:1 }; + selectedGrabber = grabberScaleRTFCube; } - var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVec, pivot, offset); + pivot = directionVec; + offset = Vec3.multiply(directionVec, -1); + var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVec, pivot, offset, null, selectedGrabber); return addGrabberTool(overlay, tool); } @@ -1346,6 +1358,7 @@ SelectionDisplay = (function() { if (SelectionManager.hasSelection()) { var worldPosition = SelectionManager.worldPosition; var worldRotation = SelectionManager.worldRotation; + var worldRotationInverse = Quat.inverse(worldRotation); var worldDimensions = SelectionManager.worldDimensions; var worldDimensionsX = worldDimensions.x; @@ -1478,7 +1491,9 @@ SelectionDisplay = (function() { position: stretchXPos, dimensions: stretchSphereDimensions }); - var stretchPanelXDimensions = Vec3.subtract(grabberScaleLTFCubePos, grabberScaleRBFCubePos); + var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleLTFCubePos); + var grabberScaleRBFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRBFCubePos); + var stretchPanelXDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRBFCubePosRot); var tempY = Math.abs(stretchPanelXDimensions.y); stretchPanelXDimensions.x = 0.01; stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); @@ -1493,7 +1508,9 @@ SelectionDisplay = (function() { position: stretchYPos, dimensions: stretchSphereDimensions }); - var stretchPanelYDimensions = Vec3.subtract(grabberScaleLTFCubePos, grabberScaleRTNCubePos); + var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleLTNCubePos); + var grabberScaleRTNCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRTFCubePos); + var stretchPanelYDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRTNCubePosRot); var tempX = Math.abs(stretchPanelYDimensions.x); stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); stretchPanelYDimensions.y = 0.01; @@ -1508,7 +1525,9 @@ SelectionDisplay = (function() { position: stretchZPos, dimensions: stretchSphereDimensions }); - var stretchPanelZDimensions = Vec3.subtract(grabberScaleRTFCubePos, grabberScaleRBNCubePos); + var grabberScaleRTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRTFCubePos); + var grabberScaleRBNCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRBNCubePos); + var stretchPanelZDimensions = Vec3.subtract(grabberScaleRTFCubePosRot, grabberScaleRBNCubePosRot); var tempX = Math.abs(stretchPanelZDimensions.x); stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); stretchPanelZDimensions.y = tempX; @@ -1576,7 +1595,8 @@ SelectionDisplay = (function() { that.setGrabberStretchYVisible(!activeTool || isActiveTool(grabberStretchYSphere)); that.setGrabberStretchZVisible(!activeTool || isActiveTool(grabberStretchZSphere)); that.setGrabberScaleVisible(!activeTool || isActiveTool(grabberScaleLBNCube) || isActiveTool(grabberScaleRBNCube) || isActiveTool(grabberScaleLBFCube) || isActiveTool(grabberScaleRBFCube) - || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube)); + || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube) + || isActiveTool(grabberStretchXSphere) || isActiveTool(grabberStretchYSphere) || isActiveTool(grabberStretchZSphere)); that.setGrabberClonerVisible(!activeTool || isActiveTool(grabberCloner)); if (wantDebug) { From 2f0d92c3cde394770e6613ce2e434ad5d45e9908 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 29 Jan 2018 18:15:01 -0800 Subject: [PATCH 051/272] ctrl 22.5 snapping --- .../system/libraries/entitySelectionTool.js | 62 +++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 3da7d1f083..d843b6282b 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -254,6 +254,10 @@ SelectionDisplay = (function() { var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18; var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14; + var ROTATION_CTRL_SNAP_ANGLE = 22.5; + var ROTATION_DEFAULT_SNAP_ANGLE = 1; + var ROTATION_DEFAULT_TICK_MARKS_ANGLE = 5; + var TRANSLATE_DIRECTION = { X : 0, Y : 1, @@ -300,6 +304,8 @@ SelectionDisplay = (function() { var worldRotationY; var worldRotationZ; + var ctrlPressed = false; + var activeTool = null; var grabberTools = {}; @@ -335,7 +341,7 @@ SelectionDisplay = (function() { innerRadius: 0.9, startAt: 0, endAt: 360, - majorTickMarksAngle: 5, + majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE, majorTickMarksLength: 0.1, visible: false, ignoreRayIntersection: false, @@ -584,6 +590,25 @@ SelectionDisplay = (function() { that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand)); that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand)); + // Control key remains active only while key is held down + function keyReleaseEvent(key) { + if (key.key === 16777249) { + ctrlPressed = false; + that.updateActiveRotateRing(); + } + } + + // Triggers notification on specific key driven events + function keyPressEvent(key) { + if (key.key === 16777249) { + ctrlPressed = true; + that.updateActiveRotateRing(); + } + } + + Controller.keyPressEvent.connect(keyPressEvent); + Controller.keyReleaseEvent.connect(keyReleaseEvent); + function controllerComputePickRay() { var controllerPose = getControllerWorldLocation(activeHand, true); if (controllerPose.valid && that.triggered) { @@ -1227,7 +1252,9 @@ SelectionDisplay = (function() { var centerToIntersect = Vec3.subtract(result, rotCenter); // Note: orientedAngle which wants normalized centerToZero and centerToIntersect // handles that internally, so it's to pass unnormalized vectors here. - var angleFromZero = Math.floor((Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal))); + var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal); + var snapAngle = ctrlPressed ? ROTATION_CTRL_SNAP_ANGLE : ROTATION_DEFAULT_SNAP_ANGLE; + angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; var rotChange = Quat.angleAxis(angleFromZero, rotationNormal); updateSelectionsRotation(rotChange); updateRotationDegreesOverlay(-angleFromZero, direction, rotCenter); @@ -1310,12 +1337,6 @@ SelectionDisplay = (function() { } } - /* - Overlays.editOverlay(highlightBox, { - visible: false - }); - */ - that.updateGrabbers(); }; @@ -1544,24 +1565,28 @@ SelectionDisplay = (function() { Overlays.editOverlay(grabberRotatePitchRing, { position: SelectionManager.worldPosition, rotation: worldRotationY, - dimensions: rotateDimensions + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); } if (!isActiveTool(grabberRotateYawRing)) { Overlays.editOverlay(grabberRotateYawRing, { position: SelectionManager.worldPosition, rotation: worldRotationZ, - dimensions: rotateDimensions + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); } if (!isActiveTool(grabberRotateRollRing)) { Overlays.editOverlay(grabberRotateRollRing, { position: SelectionManager.worldPosition, rotation: worldRotationX, - dimensions: rotateDimensions + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); } Overlays.editOverlay(grabberRotateCurrentRing, { dimensions: rotateDimensions }); + that.updateActiveRotateRing(); var inModeRotate = isActiveTool(grabberRotatePitchRing) || isActiveTool(grabberRotateYawRing) || isActiveTool(grabberRotateRollRing); var inModeTranslate = isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder) || @@ -1604,6 +1629,21 @@ SelectionDisplay = (function() { } }; + that.updateActiveRotateRing = function() { + var activeRotateRing = null; + if (isActiveTool(grabberRotatePitchRing)) { + activeRotateRing = grabberRotatePitchRing; + } else if (isActiveTool(grabberRotateYawRing)) { + activeRotateRing = grabberRotateYawRing; + } else if (isActiveTool(grabberRotateRollRing)) { + activeRotateRing = grabberRotateRollRing; + } + if (activeRotateRing != null) { + var tickMarksAngle = ctrlPressed ? ROTATION_CTRL_SNAP_ANGLE : ROTATION_DEFAULT_TICK_MARKS_ANGLE; + Overlays.editOverlay(activeRotateRing, { majorTickMarksAngle: tickMarksAngle }); + } + }; + // FUNCTION: SET OVERLAYS VISIBLE that.setOverlaysVisible = function(isVisible) { for (var i = 0; i < allOverlays.length; i++) { From e679b75e99a53f45a5d50619c0716339b1b82778 Mon Sep 17 00:00:00 2001 From: David Back Date: Mon, 29 Jan 2018 19:02:36 -0800 Subject: [PATCH 052/272] fix degree display position --- .../system/libraries/entitySelectionTool.js | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index d843b6282b..fbda9e9eba 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -299,6 +299,7 @@ SelectionDisplay = (function() { var rotZero; var rotationNormal; + var rotDegreePos; var worldRotationX; var worldRotationY; @@ -1119,20 +1120,8 @@ SelectionDisplay = (function() { } // FUNCTION: UPDATE ROTATION DEGREES OVERLAY - function updateRotationDegreesOverlay(angleFromZero, direction, centerPosition) { + function updateRotationDegreesOverlay(angleFromZero, position) { var angle = angleFromZero * (Math.PI / 180); - var position = { - x: Math.cos(angle) * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, - y: Math.sin(angle) * ROTATION_DISPLAY_DISTANCE_MULTIPLIER, - z: 0 - }; - if (direction === ROTATE_DIRECTION.PITCH) - position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, -90, 0), position); - else if (direction === ROTATE_DIRECTION.YAW) - position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(90, 0, 0), position); - else if (direction === ROTATE_DIRECTION.ROLL) - position = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 180, 0), position); - position = Vec3.sum(centerPosition, position); var overlayProps = { position: position, dimensions: { @@ -1222,7 +1211,6 @@ SelectionDisplay = (function() { endAt: 0, visible: true }); - updateRotationDegreesOverlay(0, direction, rotCenter); // editOverlays may not have committed rotation changes. // Compute zero position based on where the overlay will be eventually. @@ -1230,6 +1218,11 @@ SelectionDisplay = (function() { // In case of a parallel ray, this will be null, which will cause early-out // in the onMove helper. rotZero = result; + + var rotCenterToZero = Vec3.subtract(rotZero, rotCenter); + var rotCenterToZeroLength = Vec3.length(rotCenterToZero); + rotDegreePos = Vec3.sum(rotCenter, Vec3.multiply(Vec3.normalize(rotCenterToZero), rotCenterToZeroLength * 1.2)); + updateRotationDegreesOverlay(0, rotDegreePos); }, onEnd: function(event, reason) { Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); @@ -1257,7 +1250,7 @@ SelectionDisplay = (function() { angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; var rotChange = Quat.angleAxis(angleFromZero, rotationNormal); updateSelectionsRotation(rotChange); - updateRotationDegreesOverlay(-angleFromZero, direction, rotCenter); + updateRotationDegreesOverlay(-angleFromZero, rotDegreePos); var startAtCurrent = 0; var endAtCurrent = angleFromZero; From 5a771e3a168357708d646dcba70c79ceb7eb4cb4 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 26 Jan 2018 17:08:53 -0500 Subject: [PATCH 053/272] [Case 10865] Ctrl/Cmd/Shift+Click Multi-Select for Asset Browser. * Removes manual selectionModel update from controls-uit/Tree.qml * This was interfering with the Key+Click functionality. It was introduced via Commit 99617600c47 to address a selection issue; however, it's unclear what that issue was. Selection within the Asset Browser works without it at present. * Amends the ContextMenu within the AssetBrowser to work in conjunction with the multi-selection changes. * ContextMenu will _only_ display when triggered within the current selection be it one or more items as opposed to previous behavior of selecting the item the menu was triggered on. * CopyURL is only enabled when the selection size is 1 * Rename is only enabled when the selection size is 1 * Delete is enabled when the selection size is greater than 0 Changes Committed: modified: interface/resources/qml/controls-uit/Tree.qml modified: interface/resources/qml/hifi/AssetServer.qml --- interface/resources/qml/controls-uit/Tree.qml | 4 -- interface/resources/qml/hifi/AssetServer.qml | 41 +++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 6bd11295b1..5199a10a27 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -202,8 +202,4 @@ TreeView { } onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) - - onClicked: { - selectionModel.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect); - } } diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 37c3c2adab..7c16b19865 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -694,7 +694,7 @@ Windows.ScrollingWindow { } } } - } + }// End_OF( itemLoader ) Rectangle { id: treeLabelToolTip @@ -731,50 +731,59 @@ Windows.ScrollingWindow { showTimer.stop(); treeLabelToolTip.visible = false; } - } + }// End_OF( treeLabelToolTip ) MouseArea { propagateComposedEvents: true anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (!HMD.active) { // Popup only displays properly on desktop - var index = treeView.indexAt(mouse.x, mouse.y); - treeView.selection.setCurrentIndex(index, 0x0002); - contextMenu.currentIndex = index; - contextMenu.popup(); + if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop + // Only display the popup if the click triggered within + // the selection. + var clickedIndex = treeView.indexAt(mouse.x, mouse.y); + var displayContextMenu = false; + for ( var i = 0; i < selectedItems; ++i) { + var currentSelectedIndex = treeView.selection.selectedIndexes[i]; + if (clickedIndex === currentSelectedIndex) { + contextMenu.popup(); + break; + } + } } } } - + Menu { id: contextMenu title: "Edit" property var url: "" - property var currentIndex: null MenuItem { text: "Copy URL" + enabled: (selectedItems == 1) onTriggered: { - copyURLToClipboard(contextMenu.currentIndex); + copyURLToClipboard(treeView.selection.currentIndex); } } MenuItem { text: "Rename" + enabled: (selectedItems == 1) onTriggered: { - renameFile(contextMenu.currentIndex); + renameFile(treeView.selection.currentIndex); } } MenuItem { text: "Delete" + enabled: (selectedItems > 0) onTriggered: { - deleteFile(contextMenu.currentIndex); + deleteFile(); } } - } - } + }// End_OF( contextMenu ) + }// End_OF( treeView ) Row { id: infoRow @@ -885,7 +894,7 @@ Windows.ScrollingWindow { "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } } - } + }// End_OF( infoRow ) HifiControls.ContentSection { id: uploadSection @@ -945,7 +954,7 @@ Windows.ScrollingWindow { } } } - } + }// End_OF( uploadSection ) } } From dfdf28f37e4572bb95b6354be850356ad8bffa27 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 26 Jan 2018 17:34:05 -0500 Subject: [PATCH 054/272] [Case 10865] Some cleanup for multi-selection (details below). * Remove setCurrentIndex call when looping over current selection. * Changed selectedItems var name to selectedItemCount to clarify what it represents. * Change path arg name to paths to clarify that there can be more than a single path contained within it. Changes Committed: modified: interface/resources/qml/hifi/AssetServer.qml --- interface/resources/qml/hifi/AssetServer.qml | 49 ++++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 7c16b19865..30f76fecd6 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -37,7 +37,7 @@ Windows.ScrollingWindow { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property var selectedItems: treeView.selection.selectedIndexes.length; + property var selectedItemCount: treeView.selection.selectedIndexes.length; Settings { category: "Overlay.AssetServer" @@ -75,17 +75,17 @@ Windows.ScrollingWindow { }); } - function doDeleteFile(path) { - console.log("Deleting " + path); + function doDeleteFile(paths) { + console.log("Deleting " + paths); - Assets.deleteMappings(path, function(err) { + Assets.deleteMappings(paths, function(err) { if (err) { - console.log("Asset browser - error deleting path: ", path, err); + console.log("Asset browser - error deleting paths: ", paths, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); + box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err); box.selected.connect(reload); } else { - console.log("Asset browser - finished deleting path: ", path); + console.log("Asset browser - finished deleting paths: ", paths); reload(); } }); @@ -145,7 +145,7 @@ Windows.ScrollingWindow { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - if (selectedItems > 1) { + if (selectedItemCount > 1) { return false; } @@ -155,7 +155,7 @@ Windows.ScrollingWindow { } function canRename() { - if (treeView.selection.hasSelection && selectedItems == 1) { + if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { return false; @@ -333,29 +333,28 @@ Windows.ScrollingWindow { }); } function deleteFile(index) { - var path = []; + var paths = []; if (!index) { - for (var i = 0; i < selectedItems; i++) { - treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); - index = treeView.selection.currentIndex; - path[i] = assetProxyModel.data(index, 0x100); + for (var i = 0; i < selectedItemCount; ++i) { + index = treeView.selection.selectedIndexes[i]; + paths[i] = assetProxyModel.data(index, 0x100); } } - if (!path) { + if (!paths) { return; } var modalMessage = ""; - var items = selectedItems.toString(); + var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - if (selectedItems > 1) { + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { - modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; + modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?"; } var object = desktop.messageBox({ @@ -367,7 +366,7 @@ Windows.ScrollingWindow { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - doDeleteFile(path); + doDeleteFile(paths); } }); } @@ -743,7 +742,7 @@ Windows.ScrollingWindow { // the selection. var clickedIndex = treeView.indexAt(mouse.x, mouse.y); var displayContextMenu = false; - for ( var i = 0; i < selectedItems; ++i) { + for ( var i = 0; i < selectedItemCount; ++i) { var currentSelectedIndex = treeView.selection.selectedIndexes[i]; if (clickedIndex === currentSelectedIndex) { contextMenu.popup(); @@ -761,7 +760,7 @@ Windows.ScrollingWindow { MenuItem { text: "Copy URL" - enabled: (selectedItems == 1) + enabled: (selectedItemCount == 1) onTriggered: { copyURLToClipboard(treeView.selection.currentIndex); } @@ -769,7 +768,7 @@ Windows.ScrollingWindow { MenuItem { text: "Rename" - enabled: (selectedItems == 1) + enabled: (selectedItemCount == 1) onTriggered: { renameFile(treeView.selection.currentIndex); } @@ -777,7 +776,7 @@ Windows.ScrollingWindow { MenuItem { text: "Delete" - enabled: (selectedItems > 0) + enabled: (selectedItemCount > 0) onTriggered: { deleteFile(); } @@ -796,8 +795,8 @@ Windows.ScrollingWindow { function makeText() { var numPendingBakes = assetMappingsModel.numPendingBakes; - if (selectedItems > 1 || numPendingBakes === 0) { - return selectedItems + " items selected"; + if (selectedItemCount > 1 || numPendingBakes === 0) { + return selectedItemCount + " items selected"; } else { return numPendingBakes + " bakes pending" } From 70e23f3ce86f5837f24eaea39c422aeea23c64f0 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 30 Jan 2018 14:00:09 -0500 Subject: [PATCH 055/272] [Case 10865] Bringing in multi-select fix from Desktop AssetServer. Changes Committed: modified: interface/resources/qml/hifi/dialogs/TabletAssetServer.qml --- .../qml/hifi/dialogs/TabletAssetServer.qml | 82 ++++++++++--------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a02496a252..9c61206592 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -39,7 +39,7 @@ Rectangle { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property var selectedItems: treeView.selection.selectedIndexes.length; + property var selectedItemCount: treeView.selection.selectedIndexes.length; Settings { category: "Overlay.AssetServer" @@ -76,17 +76,17 @@ Rectangle { }); } - function doDeleteFile(path) { - console.log("Deleting " + path); + function doDeleteFile(paths) { + console.log("Deleting " + paths); - Assets.deleteMappings(path, function(err) { + Assets.deleteMappings(paths, function(err) { if (err) { - console.log("Asset browser - error deleting path: ", path, err); + console.log("Asset browser - error deleting paths: ", paths, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); + box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err); box.selected.connect(reload); } else { - console.log("Asset browser - finished deleting path: ", path); + console.log("Asset browser - finished deleting paths: ", paths); reload(); } }); @@ -146,7 +146,7 @@ Rectangle { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - if (selectedItems > 1) { + if (selectedItemCount > 1) { return false; } @@ -156,7 +156,7 @@ Rectangle { } function canRename() { - if (treeView.selection.hasSelection && selectedItems == 1) { + if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { return false; @@ -334,29 +334,28 @@ Rectangle { }); } function deleteFile(index) { - var path = []; + var paths = []; if (!index) { - for (var i = 0; i < selectedItems; i++) { - treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); - index = treeView.selection.currentIndex; - path[i] = assetProxyModel.data(index, 0x100); + for (var i = 0; i < selectedItemCount; ++i) { + index = treeView.selection.selectedIndexes[i]; + paths[i] = assetProxyModel.data(index, 0x100); } } - if (!path) { + if (!paths) { return; } var modalMessage = ""; - var items = selectedItems.toString(); + var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - if (selectedItems > 1) { + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { - modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; + modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?"; } var object = tabletRoot.messageBox({ @@ -368,7 +367,7 @@ Rectangle { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - doDeleteFile(path); + doDeleteFile(paths); } }); } @@ -693,7 +692,7 @@ Rectangle { } } } - } + }// End_OF( itemLoader ) Rectangle { id: treeLabelToolTip @@ -730,50 +729,59 @@ Rectangle { showTimer.stop(); treeLabelToolTip.visible = false; } - } + }// End_OF( treeLabelToolTip ) MouseArea { propagateComposedEvents: true anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (!HMD.active) { // Popup only displays properly on desktop - var index = treeView.indexAt(mouse.x, mouse.y); - treeView.selection.setCurrentIndex(index, 0x0002); - contextMenu.currentIndex = index; - contextMenu.popup(); + if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop + // Only display the popup if the click triggered within + // the selection. + var clickedIndex = treeView.indexAt(mouse.x, mouse.y); + var displayContextMenu = false; + for ( var i = 0; i < selectedItemCount; ++i) { + var currentSelectedIndex = treeView.selection.selectedIndexes[i]; + if (clickedIndex === currentSelectedIndex) { + contextMenu.popup(); + break; + } + } } } } - + Menu { id: contextMenu title: "Edit" property var url: "" - property var currentIndex: null MenuItem { text: "Copy URL" + enabled: (selectedItemCount == 1) onTriggered: { - copyURLToClipboard(contextMenu.currentIndex); + copyURLToClipboard(treeView.selection.currentIndex); } } MenuItem { text: "Rename" + enabled: (selectedItemCount == 1) onTriggered: { - renameFile(contextMenu.currentIndex); + renameFile(treeView.selection.currentIndex); } } MenuItem { text: "Delete" + enabled: (selectedItemCount > 0) onTriggered: { - deleteFile(contextMenu.currentIndex); + deleteFile(); } } - } - } + }// End_OF( contextMenu ) + }// End_OF( treeView ) Row { id: infoRow @@ -786,8 +794,8 @@ Rectangle { function makeText() { var numPendingBakes = assetMappingsModel.numPendingBakes; - if (selectedItems > 1 || numPendingBakes === 0) { - return selectedItems + " items selected"; + if (selectedItemCount > 1 || numPendingBakes === 0) { + return selectedItemCount + " items selected"; } else { return numPendingBakes + " bakes pending" } @@ -884,7 +892,7 @@ Rectangle { "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } } - } + }// End_OF( infoRow ) HifiControls.TabletContentSection { id: uploadSection @@ -961,7 +969,7 @@ Rectangle { } } } - } + }// End_OF( uploadSection ) } } From f344e44d26bf8d307a00593e34481bd25954bebf Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 31 Jan 2018 10:19:17 +0100 Subject: [PATCH 056/272] Switched to a simpler manual fixed/slope based shadow bias system. Automatic stuff fail most of the time --- libraries/render-utils/src/LightStage.cpp | 22 +------ libraries/render-utils/src/LightStage.h | 4 +- .../render-utils/src/RenderShadowTask.cpp | 8 +-- libraries/render-utils/src/RenderShadowTask.h | 9 ++- libraries/render-utils/src/Shadow.slh | 18 ++--- libraries/render-utils/src/ShadowCore.slh | 13 +--- libraries/render-utils/src/Shadows_shared.slh | 4 +- .../developer/utilities/render/debugShadow.js | 4 +- scripts/developer/utilities/render/shadow.qml | 65 +++++++++++++++---- 9 files changed, 78 insertions(+), 69 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index e06d24f1b1..259d0dd665 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -70,18 +70,6 @@ LightStage::Shadow::Schema::Schema() { maxDistance = 20.0f; } -void LightStage::Shadow::Schema::updateCascade(int cascadeIndex, const ViewFrustum& shadowFrustum) { - auto& cascade = cascades[cascadeIndex]; - cascade.frustumPosition = shadowFrustum.getPosition(); - // The adaptative bias is computing how much depth offset we have to add to - // push back a coarsely sampled surface perpendicularly to the shadow direction, - // to not have shadow acnee. The final computation is done in the shader, based on the - // surface normal. - auto maxWorldFrustumSize = glm::max(shadowFrustum.getWidth(), shadowFrustum.getHeight()); - cascade.adaptiveBiasUnitScale = maxWorldFrustumSize * 0.5f * invMapSize; - cascade.adaptiveBiasTransformScale = shadowFrustum.getNearClip() * shadowFrustum.getFarClip() / (shadowFrustum.getFarClip() - shadowFrustum.getNearClip()); -} - LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared() }, _minDistance{ 0.0f }, @@ -222,17 +210,14 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, auto position = viewFrustum.getPosition() - (nearDepth + farDepth)*lightDirection; // Update the buffer auto& schema = _schemaBuffer.edit(); - auto cascadeIndex = 0; for (auto& cascade : _cascades) { cascade._frustum->setOrientation(orientation); cascade._frustum->setPosition(position); - schema.cascades[cascadeIndex].frustumPosition = position; - cascadeIndex++; } } void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth, float farDepth, float baseBias) { + float nearDepth, float farDepth, float fixedBias, float slopeBias) { assert(nearDepth < farDepth); assert(cascadeIndex < _cascades.size()); @@ -283,8 +268,8 @@ void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, co auto& schema = _schemaBuffer.edit(); auto& schemaCascade = schema.cascades[cascadeIndex]; schemaCascade.reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix(); - schemaCascade.fixedBias = baseBias; - schema.updateCascade(cascadeIndex, *cascade._frustum); + schemaCascade.fixedBias = fixedBias; + schemaCascade.slopeBias = slopeBias; } void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum) { @@ -298,7 +283,6 @@ void LightStage::Shadow::setCascadeFrustum(unsigned int cascadeIndex, const View auto& schema = _schemaBuffer.edit(); auto& schemaCascade = schema.cascades[cascadeIndex]; schemaCascade.reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); - schema.updateCascade(cascadeIndex, shadowFrustum); } LightStage::Index LightStage::findLight(const LightPointer& light) const { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 922ec5eb4a..9812426fa6 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -80,7 +80,7 @@ public: void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth = 1.0f, float farDepth = 1000.0f); void setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth = 1.0f, float farDepth = 1000.0f, float baseBias = 0.005f); + float nearDepth = 1.0f, float farDepth = 1000.0f, float fixedBias = 0.005f, float slopeBias = 0.005f); void setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum); const UniformBufferView& getBuffer() const { return _schemaBuffer; } @@ -110,8 +110,6 @@ public: Schema(); - void updateCascade(int cascadeIndex, const ViewFrustum& shadowFrustum); - }; UniformBufferView _schemaBuffer = nullptr; }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 2172dda3e3..2b5ab09c06 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -256,9 +256,8 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext) { } void RenderShadowCascadeSetup::configure(const Config& configuration) { - // I'm not very proud of this empirical adjustment - auto cascadeBias = configuration.bias * powf(1.1f, _cascadeIndex); - _baseBias = cascadeBias * cascadeBias * 0.01f; + _fixedBias = configuration.fixedBias * configuration.fixedBias * configuration.fixedBias * 0.004f; + _slopeBias = configuration.slopeBias * configuration.slopeBias * configuration.slopeBias * 0.01f; } void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { @@ -274,7 +273,8 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon if (globalShadow && _cascadeIndexgetCascadeCount()) { output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, _baseBias); + globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, + _fixedBias, _slopeBias); // Set the keylight render args args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum())); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index c4f0c65bfc..7e5655b375 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -64,10 +64,12 @@ public: class RenderShadowCascadeSetupConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float bias MEMBER bias NOTIFY dirty) + Q_PROPERTY(float fixedBias MEMBER fixedBias NOTIFY dirty) + Q_PROPERTY(float slopeBias MEMBER slopeBias NOTIFY dirty) public: - float bias{ 0.25f }; + float fixedBias{ 0.15f }; + float slopeBias{ 0.55f }; signals: void dirty(); @@ -86,7 +88,8 @@ public: private: unsigned int _cascadeIndex; - float _baseBias{ 0.1f }; + float _fixedBias{ 0.1f }; + float _slopeBias{ 0.1f }; }; class RenderShadowCascadeTeardown { diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index c11f5fa6a7..6575e68090 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -83,19 +83,12 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve return shadowAttenuation; } -float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float bias, - vec3 worldPosition, vec3 worldLightDir) { +float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) { if (!isShadowCascadeProjectedOnPixel(shadowTexcoord)) { // If a point is not in the map, do not attenuate return 1.0; } - // After this, bias is in view units - bias *= getShadowAdaptiveBiasUnitScale(cascadeIndex); - // Transform to texcoord space (between 0 and 1) - float shadowDepth = abs(dot(worldPosition-getShadowFrustumPosition(cascadeIndex), worldLightDir)); - bias = transformShadowAdaptiveBias(cascadeIndex, shadowDepth, bias); - // Add fixed bias - bias += getShadowBias(cascadeIndex); + float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL; return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias); } @@ -106,12 +99,11 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe float cascadeMix = determineShadowCascadesOnPixel(worldPosition, viewDepth, cascadeShadowCoords, cascadeIndices); // Adjust bias if we are at a grazing angle with light - float ndotl = dot(worldLightDir, worldNormal); - float bias = 1.0/(ndotl*ndotl)-1.0; + float oneMinusNdotL = 1.0 - clamp(dot(worldLightDir, worldNormal), 0, 1); vec2 cascadeAttenuations = vec2(1.0, 1.0); - cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[0], bias, worldPosition.xyz, worldLightDir); + cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[0], oneMinusNdotL); if (cascadeMix > 0.0 && cascadeIndices.y < getShadowCascadeCount()) { - cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[1], bias, worldPosition.xyz, worldLightDir); + cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[1], oneMinusNdotL); } float attenuation = mix(cascadeAttenuations.x, cascadeAttenuations.y, cascadeMix); // Falloff to max distance diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index 2d48e16ef4..782e2bc2b8 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -37,21 +37,14 @@ float getShadowScale() { return shadow.invMapSize; } -float getShadowBias(int cascadeIndex) { +float getShadowFixedBias(int cascadeIndex) { return shadow.cascades[cascadeIndex].fixedBias; } -vec3 getShadowFrustumPosition(int cascadeIndex) { - return shadow.cascades[cascadeIndex].frustumPosition; +float getShadowSlopeBias(int cascadeIndex) { + return shadow.cascades[cascadeIndex].slopeBias; } -float getShadowAdaptiveBiasUnitScale(int cascadeIndex) { - return shadow.cascades[cascadeIndex].adaptiveBiasUnitScale; -} - -float transformShadowAdaptiveBias(int cascadeIndex, float shadowDepth, float depthBias) { - return shadow.cascades[cascadeIndex].adaptiveBiasTransformScale * depthBias / (shadowDepth*shadowDepth); -} // Compute the texture coordinates from world coordinates vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) { diff --git a/libraries/render-utils/src/Shadows_shared.slh b/libraries/render-utils/src/Shadows_shared.slh index def6b1b4d4..0d49fc037e 100644 --- a/libraries/render-utils/src/Shadows_shared.slh +++ b/libraries/render-utils/src/Shadows_shared.slh @@ -11,10 +11,8 @@ struct ShadowTransform { MAT4 reprojection; - VEC3 frustumPosition; float fixedBias; - float adaptiveBiasUnitScale; - float adaptiveBiasTransformScale; + float slopeBias; float _padding1; float _padding2; }; diff --git a/scripts/developer/utilities/render/debugShadow.js b/scripts/developer/utilities/render/debugShadow.js index a0d2142258..1f1d00e6b4 100644 --- a/scripts/developer/utilities/render/debugShadow.js +++ b/scripts/developer/utilities/render/debugShadow.js @@ -14,7 +14,7 @@ var qml = Script.resolvePath('shadow.qml'); var window = new OverlayWindow({ title: 'Shadow Debug', source: qml, - width: 200, - height: 90 + width: 250, + height: 300 }); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index 32405a5260..a077ab9f50 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -36,6 +36,14 @@ Column { shadow1Config.enabled = false; shadow2Config.enabled = false; shadow3Config.enabled = false; + shadow0Config.isFrozen = false; + shadow1Config.isFrozen = false; + shadow2Config.isFrozen = false; + shadow3Config.isFrozen = false; + shadow0BoundConfig.isFrozen = false; + shadow1BoundConfig.isFrozen = false; + shadow2BoundConfig.isFrozen = false; + shadow3BoundConfig.isFrozen = false; } CheckBox { @@ -72,35 +80,68 @@ Column { } } ConfigSlider { - label: qsTr("Cascade 0 bias") + label: qsTr("Cascade 0 fixed bias") integral: false config: Render.getConfig("RenderMainView.ShadowCascadeSetup0") - property: "bias" + property: "fixedBias" max: 1.0 - min: 0.01 + min: 0.0 } ConfigSlider { - label: qsTr("Cascade 1 bias") + label: qsTr("Cascade 1 fixed bias") integral: false config: Render.getConfig("RenderMainView.ShadowCascadeSetup1") - property: "bias" + property: "fixedBias" max: 1.0 - min: 0.01 + min: 0.0 } ConfigSlider { - label: qsTr("Cascade 2 bias") + label: qsTr("Cascade 2 fixed bias") integral: false config: Render.getConfig("RenderMainView.ShadowCascadeSetup2") - property: "bias" + property: "fixedBias" max: 1.0 - min: 0.01 + min: 0.0 } ConfigSlider { - label: qsTr("Cascade 3 bias") + label: qsTr("Cascade 3 fixed bias") integral: false config: Render.getConfig("RenderMainView.ShadowCascadeSetup3") - property: "bias" + property: "fixedBias" max: 1.0 - min: 0.01 + min: 0.0 + } + + ConfigSlider { + label: qsTr("Cascade 0 slope bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup0") + property: "slopeBias" + max: 1.0 + min: 0.0 + } + ConfigSlider { + label: qsTr("Cascade 1 slope bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup1") + property: "slopeBias" + max: 1.0 + min: 0.0 + } + ConfigSlider { + label: qsTr("Cascade 2 slope bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup2") + property: "slopeBias" + max: 1.0 + min: 0.0 + } + ConfigSlider { + label: qsTr("Cascade 3 slope bias") + integral: false + config: Render.getConfig("RenderMainView.ShadowCascadeSetup3") + property: "slopeBias" + max: 1.0 + min: 0.0 } } From 3fa2babec2ea97178ae2030982459f6b511366b7 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 31 Jan 2018 11:55:46 +0100 Subject: [PATCH 057/272] Moved cascade frustum pre-computation to single ShadowSetup job --- .../render-utils/src/RenderShadowTask.cpp | 75 ++++++++++++++++--- libraries/render-utils/src/RenderShadowTask.h | 61 ++++++++++----- scripts/developer/utilities/render/shadow.qml | 41 +++++----- 3 files changed, 128 insertions(+), 49 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 2b5ab09c06..b83911582c 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -213,7 +213,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende initZPassPipelines(*shapePlumber, state); } - task.addJob("ShadowSetup"); + const auto coarseFrustum = task.addJob("ShadowSetup"); for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; @@ -243,7 +243,31 @@ void RenderShadowTask::configure(const Config& configuration) { // Task::configure(configuration); } -void RenderShadowSetup::run(const render::RenderContextPointer& renderContext) { +RenderShadowSetup::RenderShadowSetup() : + _coarseShadowFrustum{ std::make_shared() } { + +} + +void RenderShadowSetup::configure(const Config& configuration) { + setConstantBias(0, configuration.constantBias0); + setConstantBias(1, configuration.constantBias1); + setConstantBias(2, configuration.constantBias2); + setConstantBias(3, configuration.constantBias3); + setSlopeBias(0, configuration.slopeBias0); + setSlopeBias(1, configuration.slopeBias1); + setSlopeBias(2, configuration.slopeBias2); + setSlopeBias(3, configuration.slopeBias3); +} + +void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) { + _bias[cascadeIndex]._constant = value * value * value * 0.004f; +} + +void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { + _bias[cascadeIndex]._slope = value * value * value * 0.01f; +} + +void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); // Cache old render args @@ -252,12 +276,46 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext) { const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); - } -} + auto firstCascadeFrustum = globalShadow->getCascade(0).getFrustum(); + unsigned int cascadeIndex; + _coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition()); + _coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation()); -void RenderShadowCascadeSetup::configure(const Config& configuration) { - _fixedBias = configuration.fixedBias * configuration.fixedBias * configuration.fixedBias * 0.004f; - _slopeBias = configuration.slopeBias * configuration.slopeBias * configuration.slopeBias * 0.01f; + // Adjust each cascade frustum + for (cascadeIndex = 0; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) { + auto& bias = _bias[cascadeIndex]; + globalShadow->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), + SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, + bias._constant, bias._slope); + } + // Now adjust coarse frustum bounds + auto left = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight()); + auto right = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight()); + auto top = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp()); + auto bottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp()); + auto near = firstCascadeFrustum->getNearClip(); + auto far = firstCascadeFrustum->getFarClip(); + for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) { + auto cascadeLeft = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight()); + auto cascadeRight = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight()); + auto cascadeTop = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp()); + auto cascadeBottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp()); + auto cascadeNear = firstCascadeFrustum->getNearClip(); + auto cascadeFar = firstCascadeFrustum->getFarClip(); + left = glm::min(left, cascadeLeft); + right = glm::max(right, cascadeRight); + bottom = glm::min(bottom, cascadeBottom); + top = glm::max(top, cascadeTop); + near = glm::min(near, cascadeNear); + far = glm::max(far, cascadeFar); + } + _coarseShadowFrustum->setProjection(glm::ortho(left, right, bottom, top, near, far)); + _coarseShadowFrustum->calculate(); + + output = _coarseShadowFrustum; + } else { + output = nullptr; + } } void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { @@ -273,9 +331,6 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon if (globalShadow && _cascadeIndexgetCascadeCount()) { output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - globalShadow->setKeylightCascadeFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, - _fixedBias, _slopeBias); - // Set the keylight render args args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum())); args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 7e5655b375..f488c46b8e 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -17,6 +17,8 @@ #include +#include "Shadows_shared.slh" + class ViewFrustum; class RenderShadowMap { @@ -53,43 +55,64 @@ public: void configure(const Config& configuration); }; -class RenderShadowSetup { -public: - using JobModel = render::Job::Model; - - RenderShadowSetup() {} - void run(const render::RenderContextPointer& renderContext); - -}; - -class RenderShadowCascadeSetupConfig : public render::Job::Config { +class RenderShadowSetupConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float fixedBias MEMBER fixedBias NOTIFY dirty) - Q_PROPERTY(float slopeBias MEMBER slopeBias NOTIFY dirty) + Q_PROPERTY(float constantBias0 MEMBER constantBias0 NOTIFY dirty) + Q_PROPERTY(float constantBias1 MEMBER constantBias1 NOTIFY dirty) + Q_PROPERTY(float constantBias2 MEMBER constantBias2 NOTIFY dirty) + Q_PROPERTY(float constantBias3 MEMBER constantBias3 NOTIFY dirty) + Q_PROPERTY(float slopeBias0 MEMBER slopeBias0 NOTIFY dirty) + Q_PROPERTY(float slopeBias1 MEMBER slopeBias1 NOTIFY dirty) + Q_PROPERTY(float slopeBias2 MEMBER slopeBias2 NOTIFY dirty) + Q_PROPERTY(float slopeBias3 MEMBER slopeBias3 NOTIFY dirty) public: - float fixedBias{ 0.15f }; - float slopeBias{ 0.55f }; + float constantBias0{ 0.15f }; + float constantBias1{ 0.15f }; + float constantBias2{ 0.15f }; + float constantBias3{ 0.15f }; + float slopeBias0{ 0.55f }; + float slopeBias1{ 0.55f }; + float slopeBias2{ 0.55f }; + float slopeBias3{ 0.55f }; signals: void dirty(); }; +class RenderShadowSetup { +public: + using Output = ViewFrustumPointer; + using Config = RenderShadowSetupConfig; + using JobModel = render::Job::ModelO; + + RenderShadowSetup(); + void configure(const Config& configuration); + void run(const render::RenderContextPointer& renderContext, Output& output); + +private: + + ViewFrustumPointer _coarseShadowFrustum; + struct { + float _constant; + float _slope; + } _bias[SHADOW_CASCADE_MAX_COUNT]; + + void setConstantBias(int cascadeIndex, float value); + void setSlopeBias(int cascadeIndex, float value); +}; + class RenderShadowCascadeSetup { public: using Outputs = render::VaryingSet3; - using Config = RenderShadowCascadeSetupConfig; - using JobModel = render::Job::ModelO; + using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} - void configure(const Config& configuration); void run(const render::RenderContextPointer& renderContext, Outputs& output); private: unsigned int _cascadeIndex; - float _fixedBias{ 0.1f }; - float _slopeBias{ 0.1f }; }; class RenderShadowCascadeTeardown { diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index a077ab9f50..3400dcd847 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -18,6 +18,7 @@ Column { id: root spacing: 8 property var viewConfig: Render.getConfig("RenderMainView.DrawViewFrustum"); + property var shadowConfig : Render.getConfig("RenderMainView.ShadowSetup"); property var shadow0Config: Render.getConfig("RenderMainView.DrawShadowFrustum0"); property var shadow1Config: Render.getConfig("RenderMainView.DrawShadowFrustum1"); property var shadow2Config: Render.getConfig("RenderMainView.DrawShadowFrustum2"); @@ -80,34 +81,34 @@ Column { } } ConfigSlider { - label: qsTr("Cascade 0 fixed bias") + label: qsTr("Cascade 0 constant bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup0") - property: "fixedBias" + config: shadowConfig + property: "constantBias0" max: 1.0 min: 0.0 } ConfigSlider { - label: qsTr("Cascade 1 fixed bias") + label: qsTr("Cascade 1 constant bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup1") - property: "fixedBias" + config: shadowConfig + property: "constantBias1" max: 1.0 min: 0.0 } ConfigSlider { - label: qsTr("Cascade 2 fixed bias") + label: qsTr("Cascade 2 constant bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup2") - property: "fixedBias" + config: shadowConfig + property: "constantBias2" max: 1.0 min: 0.0 } ConfigSlider { - label: qsTr("Cascade 3 fixed bias") + label: qsTr("Cascade 3 constant bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup3") - property: "fixedBias" + config: shadowConfig + property: "constantBias3" max: 1.0 min: 0.0 } @@ -115,32 +116,32 @@ Column { ConfigSlider { label: qsTr("Cascade 0 slope bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup0") - property: "slopeBias" + config: shadowConfig + property: "slopeBias0" max: 1.0 min: 0.0 } ConfigSlider { label: qsTr("Cascade 1 slope bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup1") - property: "slopeBias" + config: shadowConfig + property: "slopeBias1" max: 1.0 min: 0.0 } ConfigSlider { label: qsTr("Cascade 2 slope bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup2") - property: "slopeBias" + config: shadowConfig + property: "slopeBias2" max: 1.0 min: 0.0 } ConfigSlider { label: qsTr("Cascade 3 slope bias") integral: false - config: Render.getConfig("RenderMainView.ShadowCascadeSetup3") - property: "slopeBias" + config: shadowConfig + property: "slopeBias3" max: 1.0 min: 0.0 } From d422545c78a999041f956e02a5d2e74203e79493 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Wed, 31 Jan 2018 17:13:06 +0100 Subject: [PATCH 058/272] Changed shadow task to do a single octree query as well as pipeline/depth sort for all cascades. Still issue with disapearing objects from shadow map with viewpoint --- .../render-utils/src/RenderShadowTask.cpp | 105 +++++---- libraries/render-utils/src/RenderShadowTask.h | 17 +- libraries/render-utils/src/RenderViewTask.cpp | 9 +- libraries/render/src/render/CullTask.cpp | 203 ++++++++++++++---- libraries/render/src/render/CullTask.h | 40 +++- .../src/render/RenderFetchCullSortTask.cpp | 6 +- 6 files changed, 273 insertions(+), 107 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index b83911582c..c9df67dad1 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -213,28 +213,34 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende initZPassPipelines(*shapePlumber, state); } - const auto coarseFrustum = task.addJob("ShadowSetup"); + const auto setupOutput = task.addJob("ShadowSetup"); + // Fetch and cull the items from the scene + static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); + const auto fetchInput = render::Varying(shadowCasterFilter); + const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); + const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying(); + const auto shadowItems = task.addJob("FetchShadowSelection", selectionInputs); + + // Sort + const auto sortedPipelines = task.addJob("PipelineSortShadow", shadowItems); + const auto sortedShapes = task.addJob("DepthSortShadow", sortedPipelines, true); for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); - const auto setupOutput = task.addJob(jobName, i); - const auto shadowFilter = setupOutput.getN(1); + const auto shadowFilter = task.addJob(jobName, i); - // CPU jobs: - // Fetch and cull the items from the scene - const auto shadowSelection = task.addJob("FetchShadowSelection", shadowFilter); - const auto cullInputs = CullSpatialSelection::Inputs(shadowSelection, shadowFilter).asVarying(); - const auto culledShadowSelection = task.addJob("CullShadowSelection", cullInputs, cullFunctor, RenderDetails::SHADOW); - - // Sort - const auto sortedPipelines = task.addJob("PipelineSortShadowSort", culledShadowSelection); - const auto sortedShapesAndBounds = task.addJob("DepthSortShadowMap", sortedPipelines, true); + // CPU jobs: finer grained culling + const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying(); + const auto culledShadowItemsAndBounds = task.addJob("CullShadowCascade", cullInputs, cullFunctor, RenderDetails::SHADOW); // GPU jobs: Render to shadow map - task.addJob("RenderShadowMap", sortedShapesAndBounds, shapePlumber, i); - task.addJob("ShadowCascadeTeardown", setupOutput); + sprintf(jobName, "RenderShadowMap%d", i); + task.addJob(jobName, culledShadowItemsAndBounds, shapePlumber, i); + task.addJob("ShadowCascadeTeardown", shadowFilter); } + + task.addJob("ShadowTeardown", setupOutput); } void RenderShadowTask::configure(const Config& configuration) { @@ -267,16 +273,19 @@ void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { _bias[cascadeIndex]._slope = value * value * value * 0.01f; } -void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { +void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); // Cache old render args RenderArgs* args = renderContext->args; + output.edit0() = args->_renderMode; + output.edit1() = args->_sizeScale; + const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); - auto firstCascadeFrustum = globalShadow->getCascade(0).getFrustum(); + auto& firstCascadeFrustum = globalShadow->getCascade(0).getFrustum(); unsigned int cascadeIndex; _coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition()); _coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation()); @@ -296,12 +305,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O auto near = firstCascadeFrustum->getNearClip(); auto far = firstCascadeFrustum->getFarClip(); for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) { - auto cascadeLeft = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight()); - auto cascadeRight = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight()); - auto cascadeTop = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp()); - auto cascadeBottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp()); - auto cascadeNear = firstCascadeFrustum->getNearClip(); - auto cascadeFar = firstCascadeFrustum->getFarClip(); + auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum(); + auto cascadeLeft = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getRight()); + auto cascadeRight = glm::dot(cascadeFrustum->getFarTopRight(), cascadeFrustum->getRight()); + auto cascadeTop = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getUp()); + auto cascadeBottom = glm::dot(cascadeFrustum->getFarBottomRight(), cascadeFrustum->getUp()); + auto cascadeNear = cascadeFrustum->getNearClip(); + auto cascadeFar = cascadeFrustum->getFarClip(); left = glm::min(left, cascadeLeft); right = glm::max(right, cascadeRight); bottom = glm::min(bottom, cascadeBottom); @@ -312,9 +322,14 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O _coarseShadowFrustum->setProjection(glm::ortho(left, right, bottom, top, near, far)); _coarseShadowFrustum->calculate(); - output = _coarseShadowFrustum; - } else { - output = nullptr; + // Push frustum for further culling and selection + args->pushViewFrustum(*_coarseShadowFrustum); + + args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) { + // Set to ridiculously high amount to prevent solid angle culling in octree selection + args->_sizeScale = 1e16f; + } } } @@ -324,37 +339,41 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon // Cache old render args RenderArgs* args = renderContext->args; - output.edit0() = args->_renderMode; - output.edit2() = args->_sizeScale; - const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); + output = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); // Set the keylight render args - args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum())); - args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; - if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) { - const float shadowSizeScale = 1e16f; - // Set the size scale to a ridiculously high value to prevent small object culling which assumes - // the view frustum is a perspective projection. But this isn't the case for the sun which - // is an orthographic projection. - args->_sizeScale = shadowSizeScale; - } - + auto& cascade = globalShadow->getCascade(_cascadeIndex); + auto& cascadeFrustum = cascade.getFrustum(); + args->pushViewFrustum(*cascadeFrustum); + // Set the cull threshold to 2 shadow texels. + auto texelSize = glm::max(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x; + texelSize *= 2.0f; + // SizeScale is used in the shadow cull function defined ine RenderViewTask + args->_sizeScale = texelSize * texelSize; } else { - output.edit1() = ItemFilter::Builder::nothing(); + output = ItemFilter::Builder::nothing(); } } void RenderShadowCascadeTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) { RenderArgs* args = renderContext->args; - if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE && !input.get1().selectsNothing()) { + if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE && !input.selectsNothing()) { + args->popViewFrustum(); + } + assert(args->hasViewFrustum()); +} + +void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) { + RenderArgs* args = renderContext->args; + + if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE) { args->popViewFrustum(); } assert(args->hasViewFrustum()); // Reset the render args args->_renderMode = input.get0(); - args->_sizeScale = input.get2(); -}; + args->_sizeScale = input.get1(); +} diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index f488c46b8e..1736d07fd5 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -82,13 +82,13 @@ signals: class RenderShadowSetup { public: - using Output = ViewFrustumPointer; + using Outputs = render::VaryingSet2; using Config = RenderShadowSetupConfig; - using JobModel = render::Job::ModelO; + using JobModel = render::Job::ModelO; RenderShadowSetup(); void configure(const Config& configuration); - void run(const render::RenderContextPointer& renderContext, Output& output); + void run(const render::RenderContextPointer& renderContext, Outputs& output); private: @@ -104,7 +104,7 @@ private: class RenderShadowCascadeSetup { public: - using Outputs = render::VaryingSet3; + using Outputs = render::ItemFilter; using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} @@ -117,9 +117,16 @@ private: class RenderShadowCascadeTeardown { public: - using Input = RenderShadowCascadeSetup::Outputs; + using Input = render::ItemFilter; using JobModel = render::Job::ModelI; void run(const render::RenderContextPointer& renderContext, const Input& input); }; +class RenderShadowTeardown { +public: + using Input = RenderShadowSetup::Outputs; + using JobModel = render::Job::ModelI; + void run(const render::RenderContextPointer& renderContext, const Input& input); +}; + #endif // hifi_RenderShadowTask_h diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index dc6c66e058..c2e43582cd 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -21,13 +21,8 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: // but the cullFunctor passed is probably tailored for perspective projection and culls too much. task.addJob("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) { // Cull only objects that are too small relatively to shadow frustum - auto& frustum = args->getViewFrustum(); - auto frustumSize = std::max(frustum.getHeight(), frustum.getWidth()); - const auto boundsRadius = bounds.getDimensions().length(); - const auto relativeBoundRadius = boundsRadius / frustumSize; - const auto threshold = 1e-3f; - return relativeBoundRadius > threshold; - return true; + const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions()); + return boundsSquareRadius > args->_sizeScale; }); const auto items = task.addJob("FetchCullSort", cullFunctor); diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 70331cdb47..c6ff224560 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -19,6 +19,50 @@ using namespace render; +// Culling Frustum / solidAngle test helper class +struct Test { + CullFunctor _functor; + RenderArgs* _args; + RenderDetails::Item& _renderDetails; + glm::vec3 _eyePos; + float _squareTanAlpha; + + Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) : + _functor(functor), + _args(pargs), + _renderDetails(renderDetails) { + // FIXME: Keep this code here even though we don't use it yet + /*_eyePos = _args->getViewFrustum().getPosition(); + float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); + auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees + angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree + auto tanAlpha = tan(angle); + _squareTanAlpha = (float)(tanAlpha * tanAlpha); + */ + } + + bool frustumTest(const AABox& bound) { + if (!_args->getViewFrustum().boxIntersectsFrustum(bound)) { + _renderDetails._outOfView++; + return false; + } + return true; + } + + bool solidAngleTest(const AABox& bound) { + // FIXME: Keep this code here even though we don't use it yet + //auto eyeToPoint = bound.calcCenter() - _eyePos; + //auto boundSize = bound.getDimensions(); + //float test = (glm::dot(boundSize, boundSize) / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha; + //if (test < 0.0f) { + if (!_functor(_args, bound)) { + _renderDetails._tooSmall++; + return false; + } + return true; + } +}; + void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details, const ItemBounds& inItems, ItemBounds& outItems) { assert(renderContext->args); @@ -82,18 +126,20 @@ void FetchSpatialTree::configure(const Config& config) { _lodAngle = config.lodAngle; } -void FetchSpatialTree::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection) { +void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection) { // start fresh outSelection.clear(); + auto& filter = inputs; + if (!filter.selectsNothing()) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; auto& scene = renderContext->_scene; - // Eventually use a frozen frustum auto queryFrustum = args->getViewFrustum(); + // Eventually use a frozen frustum if (_freezeFrustum) { if (_justFrozeFrustum) { _justFrozeFrustum = false; @@ -134,50 +180,6 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, args->pushViewFrustum(_frozenFrustum); // replace the true view frustum by the frozen one } - // Culling Frustum / solidAngle test helper class - struct Test { - CullFunctor _functor; - RenderArgs* _args; - RenderDetails::Item& _renderDetails; - glm::vec3 _eyePos; - float _squareTanAlpha; - - Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) : - _functor(functor), - _args(pargs), - _renderDetails(renderDetails) - { - // FIXME: Keep this code here even though we don't use it yet - /*_eyePos = _args->getViewFrustum().getPosition(); - float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); - auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees - angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree - auto tanAlpha = tan(angle); - _squareTanAlpha = (float)(tanAlpha * tanAlpha); - */ - } - - bool frustumTest(const AABox& bound) { - if (!_args->getViewFrustum().boxIntersectsFrustum(bound)) { - _renderDetails._outOfView++; - return false; - } - return true; - } - - bool solidAngleTest(const AABox& bound) { - // FIXME: Keep this code here even though we don't use it yet - //auto eyeToPoint = bound.calcCenter() - _eyePos; - //auto boundSize = bound.getDimensions(); - //float test = (glm::dot(boundSize, boundSize) / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha; - //if (test < 0.0f) { - if (!_functor(_args, bound)) { - _renderDetails._tooSmall++; - return false; - } - return true; - } - }; Test test(_cullFunctor, args, details); // Now we have a selection of items to render @@ -309,3 +311,112 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } + +void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + + const auto& inShapes = inputs.get0(); + const auto& filter = inputs.get1(); + auto& outShapes = outputs.edit0(); + auto& outBounds = outputs.edit1(); + + outShapes.clear(); + outBounds = AABox(); + + if (!filter.selectsNothing()) { + auto& details = args->_details.edit(_detailType); + Test test(_cullFunctor, args, details); + + for (auto& inItems : inShapes) { + auto key = inItems.first; + auto outItems = outShapes.find(key); + if (outItems == outShapes.end()) { + outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first; + outItems->second.reserve(inItems.second.size()); + } + + details._considered += (int)inItems.second.size(); + + for (auto& item : inItems.second) { + if (test.frustumTest(item.bound) && test.solidAngleTest(item.bound)) { + outItems->second.emplace_back(item); + outBounds += item.bound; + } + } + + details._rendered += (int)outItems->second.size(); + } + + for (auto& items : outShapes) { + items.second.shrink_to_fit(); + } + } +} + +void FetchSpatialSelection::run(const RenderContextPointer& renderContext, + const Inputs& inputs, ItemBounds& outItems) { + assert(renderContext->args); + RenderArgs* args = renderContext->args; + auto& scene = renderContext->_scene; + auto& inSelection = inputs.get0(); + + // Now we have a selection of items to render + outItems.clear(); + outItems.reserve(inSelection.numItems()); + + const auto filter = inputs.get1(); + if (!filter.selectsNothing()) { + // Now get the bound, and + // filter individually against the _filter + + // inside & fit items: filter only, culling is disabled + { + PerformanceTimer perfTimer("insideFitItems"); + for (auto id : inSelection.insideItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + // inside & subcell items: filter only, culling is disabled + { + PerformanceTimer perfTimer("insideSmallItems"); + for (auto id : inSelection.insideSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + // partial & fit items: filter only, culling is disabled + { + PerformanceTimer perfTimer("partialFitItems"); + for (auto id : inSelection.partialItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + // partial & subcell items: filter only, culling is disabled + { + PerformanceTimer perfTimer("partialSmallItems"); + for (auto id : inSelection.partialSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + } +} diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 486c4f4cdf..a140a86aee 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -55,12 +55,13 @@ namespace render { float _lodAngle; public: using Config = FetchSpatialTreeConfig; - using JobModel = Job::ModelIO; + using Inputs = ItemFilter; + using JobModel = Job::ModelIO; FetchSpatialTree() {} void configure(const Config& config); - void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection); + void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection); }; class CullSpatialSelectionConfig : public Job::Config { @@ -96,7 +97,8 @@ namespace render { _detailType(type) {} CullSpatialSelection(CullFunctor cullFunctor) : - _cullFunctor{ cullFunctor } {} + _cullFunctor{ cullFunctor } { + } CullFunctor _cullFunctor; RenderDetails::Type _detailType{ RenderDetails::OTHER }; @@ -105,6 +107,38 @@ namespace render { void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; + class CullShapeBounds { + public: + using Inputs = render::VaryingSet2; + using Outputs = render::VaryingSet2; + using JobModel = Job::ModelIO; + + CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) : + _cullFunctor{ cullFunctor }, + _detailType(type) {} + + CullShapeBounds(CullFunctor cullFunctor) : + _cullFunctor{ cullFunctor } { + } + + void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + + private: + + CullFunctor _cullFunctor; + RenderDetails::Type _detailType{ RenderDetails::OTHER }; + + }; + + class FetchSpatialSelection { + public: + using Inputs = render::VaryingSet2; + using JobModel = Job::ModelIO; + + FetchSpatialSelection() {} + void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); + }; + } #endif // hifi_render_CullTask_h; \ No newline at end of file diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index d7294fa2bd..a1b4f079e7 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -23,9 +23,9 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin // CPU jobs: // Fetch and cull the items from the scene const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); - const auto spatialFilter = render::Varying(filter); - const auto spatialSelection = task.addJob("FetchSceneSelection", spatialFilter); - const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying(); + const auto fetchInput = render::Varying(filter); + const auto spatialSelection = task.addJob("FetchSceneSelection", fetchInput); + const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying(); const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); // Overlays are not culled From c01790bd3e2deefe8789bfeceebff1182a0da76f Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 31 Jan 2018 18:27:15 -0800 Subject: [PATCH 059/272] punch list updates and various fixes --- .../system/libraries/entitySelectionTool.js | 342 ++++++++++++------ 1 file changed, 231 insertions(+), 111 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index fbda9e9eba..87dc089c1a 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -94,6 +94,7 @@ SelectionManager = (function() { for (var i = 0; i < entityIDs.length; i++) { var entityID = entityIDs[i]; that.selections.push(entityID); + //Selection.addToSelectedItemsList("contextOverlayHighlightList", "entity", entityID); } that._update(true); @@ -110,8 +111,10 @@ SelectionManager = (function() { } if (idx === -1) { that.selections.push(entityID); + //Selection.addToSelectedItemsList("contextOverlayHighlightList", "entity", entityID); } else if (toggleSelection) { that.selections.splice(idx, 1); + //Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); } } @@ -122,6 +125,7 @@ SelectionManager = (function() { var idx = that.selections.indexOf(entityID); if (idx >= 0) { that.selections.splice(idx, 1); + //Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); } that._update(true); }; @@ -145,9 +149,9 @@ SelectionManager = (function() { that.localPosition = properties.position; that.localRotation = properties.rotation; that.localRegistrationPoint = properties.registrationPoint; - that.worldDimensions = properties.dimensions; // properties.boundingbox.dimensions; - that.worldPosition = properties.position; - that.worldRotation = properties.rotation; + that.worldDimensions = properties.boundingBox.dimensions; + that.worldPosition = properties.boundingBox.center; + that.worldRotation = properties.boundingBox.rotation; SelectionDisplay.setSpaceMode(SPACE_LOCAL); } else { that.localRotation = null; @@ -225,39 +229,43 @@ function getRelativeCenterPosition(dimensions, registrationPoint) { SelectionDisplay = (function() { var that = {}; - var COLOR_GREEN = { red:0, green:255, blue:0 }; - var COLOR_BLUE = { red:0, green:0, blue:255 }; - var COLOR_RED = { red:255, green:0, blue:0 }; + var COLOR_GREEN = { red:44, green:142, blue:14 }; + var COLOR_BLUE = { red:0, green:147, blue:197 }; + var COLOR_RED = { red:183, green:10, blue:55 }; - var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 1.35; - var GRABBER_TRANSLATE_ARROW_CYLINDER_DIMENSION_MULTIPLE = 0.05; + var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 0.1; + var GRABBER_TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE = 0.005; var GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE = 7.5; - var GRABBER_TRANSLATE_ARROW_CONE_DIMENSION_MULTIPLE = 0.25; - var GRABBER_ROTATE_RINGS_DIMENSION_MULTIPLE = 2.0; - var GRABBER_STRETCH_SPHERE_OFFSET = 1.0; - var GRABBER_STRETCH_SPHERE_DIMENSION_MULTIPLE = 0.1; - var GRABBER_SCALE_CUBE_OFFSET = 1.0; - var GRABBER_SCALE_CUBE_DIMENSION_MULTIPLE = 0.15; + var GRABBER_TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE = 0.025; + var GRABBER_ROTATE_RINGS_CAMERA_DISTANCE_MULTIPLE = 0.15; + var GRABBER_STRETCH_SPHERE_OFFSET = 0.06; + var GRABBER_STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE = 0.01; + var GRABBER_SCALE_CUBE_OFFSET = 0.5; + var GRABBER_SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.015; var GRABBER_CLONER_OFFSET = { x:0.9, y:-0.9, z:0.9 }; - var GRABBER_SCALE_CUBE_IDLE_COLOR = { red:120, green:120, blue:120 }; - var GRABBER_SCALE_CUBE_SELECTED_COLOR = { red:0, green:0, blue:0 }; - var GRABBER_SCALE_EDGE_COLOR = { red:120, green:120, blue:120 }; + var GRABBER_SCALE_CUBE_IDLE_COLOR = { red:106, green:106, blue:106 }; + var GRABBER_SCALE_CUBE_SELECTED_COLOR = { red:18, green:18, blue:18 }; + var GRABBER_SCALE_EDGE_COLOR = { red:87, green:87, blue:87 }; + var GRABBER_HOVER_COLOR = { red:227, green:227, blue:227 }; var SCALE_MINIMUM_DIMENSION = 0.02; var STRETCH_MINIMUM_DIMENSION = 0.001; - var STRETCH_DIRECTION_ALL_FACTOR = 15; + var STRETCH_DIRECTION_ALL_FACTOR = 25; // These are multipliers for sizing the rotation degrees display while rotating an entity var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.0; - var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.6; - var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.18; - var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.14; + var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.3; + var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.09; + var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.07; var ROTATION_CTRL_SNAP_ANGLE = 22.5; var ROTATION_DEFAULT_SNAP_ANGLE = 1; var ROTATION_DEFAULT_TICK_MARKS_ANGLE = 5; + var ROTATION_RING_IDLE_INNER_RADIUS = 0.97; + var ROTATION_RING_SELECTED_INNER_RADIUS = 0.9; + var TRANSLATE_DIRECTION = { X : 0, Y : 1, @@ -307,6 +315,10 @@ SelectionDisplay = (function() { var ctrlPressed = false; + var previousHandle = null; + var previousHandleHelper = null; + var previousHandleColor; + var activeTool = null; var grabberTools = {}; @@ -339,9 +351,10 @@ SelectionDisplay = (function() { var grabberPropertiesRotateRings = { alpha: 1, - innerRadius: 0.9, + solid: true, startAt: 0, endAt: 360, + innerRadius: ROTATION_RING_IDLE_INNER_RADIUS, majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE, majorTickMarksLength: 0.1, visible: false, @@ -472,7 +485,7 @@ SelectionDisplay = (function() { var selectionBox = Overlays.addOverlay("cube", { size: 1, color: COLOR_RED, - alpha: 1, + alpha: 0, // setting to 0 alpha for now to keep this hidden vs using visible false because its used as the translate xz tool overlay solid: false, visible: false, dashed: false @@ -644,12 +657,13 @@ SelectionDisplay = (function() { pickNormal = { x:0, y:1, z:0 }; } - var rotation = SelectionManager.worldRotation; + var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; pickNormal = Vec3.multiplyQbyV(rotation, pickNormal); lastPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, pickNormal); SelectionManager.saveProperties(); + that.resetPreviousHandleColor(); that.setGrabberTranslateXVisible(direction === TRANSLATE_DIRECTION.X); that.setGrabberTranslateYVisible(direction === TRANSLATE_DIRECTION.Y); @@ -696,7 +710,7 @@ SelectionDisplay = (function() { projectionVector = { x:0, y:0, z:1 }; } - var rotation = SelectionManager.worldRotation; + var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; projectionVector = Vec3.multiplyQbyV(rotation, projectionVector); var dotVector = Vec3.dot(vector, projectionVector); @@ -924,6 +938,9 @@ SelectionDisplay = (function() { that.setGrabberStretchYVisible(directionEnum === STRETCH_DIRECTION.Y); that.setGrabberStretchZVisible(directionEnum === STRETCH_DIRECTION.Z); that.setGrabberClonerVisible(false); + + SelectionManager.saveProperties(); + that.resetPreviousHandleColor(); if (stretchPanel != null) { Overlays.editOverlay(stretchPanel, { visible: true }); @@ -931,8 +948,6 @@ SelectionDisplay = (function() { if (scaleGrabber != null) { Overlays.editOverlay(scaleGrabber, { color: GRABBER_SCALE_CUBE_SELECTED_COLOR }); } - - SelectionManager.saveProperties(); }; var onEnd = function(event, reason) { @@ -1122,13 +1137,15 @@ SelectionDisplay = (function() { // FUNCTION: UPDATE ROTATION DEGREES OVERLAY function updateRotationDegreesOverlay(angleFromZero, position) { var angle = angleFromZero * (Math.PI / 180); + var cameraPosition = Camera.getPosition(); + var entityToCameraDistance = Vec3.length(Vec3.subtract(cameraPosition, position)); var overlayProps = { position: position, dimensions: { - x: ROTATION_DISPLAY_SIZE_X_MULTIPLIER, - y: ROTATION_DISPLAY_SIZE_Y_MULTIPLIER + x: entityToCameraDistance * ROTATION_DISPLAY_SIZE_X_MULTIPLIER, + y: entityToCameraDistance * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER }, - lineHeight: ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER, + lineHeight: entityToCameraDistance * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER, text: normalizeDegrees(-angleFromZero) + "°" }; Overlays.editOverlay(rotationDegreesDisplay, overlayProps); @@ -1173,6 +1190,7 @@ SelectionDisplay = (function() { mode: mode, onBegin: function(event, pickRay, pickResult) { SelectionManager.saveProperties(); + that.resetPreviousHandleColor(); that.setGrabberTranslateVisible(false); that.setGrabberRotatePitchVisible(direction === ROTATE_DIRECTION.PITCH); @@ -1196,9 +1214,13 @@ SelectionDisplay = (function() { selectedGrabber = grabberRotateRollRing; } - Overlays.editOverlay(selectedGrabber, { hasTickMarks: true }); + Overlays.editOverlay(selectedGrabber, { + hasTickMarks: true, + solid: false, + innerRadius: ROTATION_RING_SELECTED_INNER_RADIUS + }); - var rotation = SelectionManager.worldRotation; + var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; rotationNormal = Vec3.multiplyQbyV(rotation, rotationNormal); var rotCenter = SelectionManager.worldPosition; @@ -1221,12 +1243,16 @@ SelectionDisplay = (function() { var rotCenterToZero = Vec3.subtract(rotZero, rotCenter); var rotCenterToZeroLength = Vec3.length(rotCenterToZero); - rotDegreePos = Vec3.sum(rotCenter, Vec3.multiply(Vec3.normalize(rotCenterToZero), rotCenterToZeroLength * 1.2)); + rotDegreePos = Vec3.sum(rotCenter, Vec3.multiply(Vec3.normalize(rotCenterToZero), rotCenterToZeroLength * 1.75)); updateRotationDegreesOverlay(0, rotDegreePos); }, onEnd: function(event, reason) { Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); - Overlays.editOverlay(selectedGrabber, { hasTickMarks: false }); + Overlays.editOverlay(selectedGrabber, { + hasTickMarks: false, + solid: true, + innerRadius: ROTATION_RING_IDLE_INNER_RADIUS + }); Overlays.editOverlay(grabberRotateCurrentRing, { visible: false }); pushCommandForSelections(); }, @@ -1266,6 +1292,7 @@ SelectionDisplay = (function() { if (direction === ROTATE_DIRECTION.YAW) { Overlays.editOverlay(grabberRotateCurrentRing, { rotation: worldRotationZ }); } + } } }); @@ -1307,7 +1334,6 @@ SelectionDisplay = (function() { }; that.highlightSelectable = function(entityID) { - var properties = Entities.getEntityProperties(entityID); }; that.unhighlightSelectable = function(entityID) { @@ -1370,118 +1396,119 @@ SelectionDisplay = (function() { } if (SelectionManager.hasSelection()) { - var worldPosition = SelectionManager.worldPosition; - var worldRotation = SelectionManager.worldRotation; - var worldRotationInverse = Quat.inverse(worldRotation); - var worldDimensions = SelectionManager.worldDimensions; + var position = SelectionManager.worldPosition; + var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; + var dimensions = spaceMode === SPACE_LOCAL ? SelectionManager.localDimensions : SelectionManager.worldDimensions; + var rotationInverse = Quat.inverse(rotation); - var worldDimensionsX = worldDimensions.x; - var worldDimensionsY = worldDimensions.y; - var worldDimensionsZ = worldDimensions.z; - var dimensionAverage = (worldDimensionsX + worldDimensionsY + worldDimensionsZ) / 3; + var cameraPosition = Camera.getPosition(); + var entityToCameraDistance = Vec3.length(Vec3.subtract(cameraPosition, position)); var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); - worldRotationX = Quat.multiply(worldRotation, localRotationX); + rotationX = Quat.multiply(rotation, localRotationX); + worldRotationX = rotationX; var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); - worldRotationY = Quat.multiply(worldRotation, localRotationY); + rotationY = Quat.multiply(rotation, localRotationY); + worldRotationY = rotationY; var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); - worldRotationZ = Quat.multiply(worldRotation, localRotationZ); + rotationZ = Quat.multiply(rotation, localRotationZ); + worldRotationZ = rotationZ; - var arrowCylinderDimension = dimensionAverage * GRABBER_TRANSLATE_ARROW_CYLINDER_DIMENSION_MULTIPLE; + var arrowCylinderDimension = entityToCameraDistance * GRABBER_TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE; var arrowCylinderDimensions = { x:arrowCylinderDimension, y:arrowCylinderDimension * GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE, z:arrowCylinderDimension }; - var arrowConeDimension = dimensionAverage * GRABBER_TRANSLATE_ARROW_CONE_DIMENSION_MULTIPLE; + var arrowConeDimension = entityToCameraDistance * GRABBER_TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE; var arrowConeDimensions = { x:arrowConeDimension, y:arrowConeDimension, z:arrowConeDimension }; - var cylinderXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage, y:0, z:0 })); + var cylinderXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance, y:0, z:0 })); Overlays.editOverlay(grabberTranslateXCylinder, { position: cylinderXPos, - rotation: worldRotationX, + rotation: rotationX, dimensions: arrowCylinderDimensions }); - var cylinderXDiff = Vec3.subtract(cylinderXPos, worldPosition); + var cylinderXDiff = Vec3.subtract(cylinderXPos, position); var coneXPos = Vec3.sum(cylinderXPos, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowCylinderDimensions.y * 0.83)); Overlays.editOverlay(grabberTranslateXCone, { position: coneXPos, - rotation: worldRotationX, + rotation: rotationX, dimensions: arrowConeDimensions }); - var cylinderYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage, z:0 })); + var cylinderYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance, z:0 })); Overlays.editOverlay(grabberTranslateYCylinder, { position: cylinderYPos, - rotation: worldRotationY, + rotation: rotationY, dimensions: arrowCylinderDimensions }); - var cylinderYDiff = Vec3.subtract(cylinderYPos, worldPosition); + var cylinderYDiff = Vec3.subtract(cylinderYPos, position); var coneYPos = Vec3.sum(cylinderYPos, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowCylinderDimensions.y * 0.83)); Overlays.editOverlay(grabberTranslateYCone, { position: coneYPos, - rotation: worldRotationY, + rotation: rotationY, dimensions: arrowConeDimensions }); - var cylinderZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * dimensionAverage })); + var cylinderZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance })); Overlays.editOverlay(grabberTranslateZCylinder, { position: cylinderZPos, - rotation: worldRotationZ, + rotation: rotationZ, dimensions: arrowCylinderDimensions }); - var cylinderZDiff = Vec3.subtract(cylinderZPos, worldPosition); + var cylinderZDiff = Vec3.subtract(cylinderZPos, position); var coneZPos = Vec3.sum(cylinderZPos, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowCylinderDimensions.y * 0.83)); Overlays.editOverlay(grabberTranslateZCone, { position: coneZPos, - rotation: worldRotationZ, + rotation: rotationZ, dimensions: arrowConeDimensions }); - var grabberScaleCubeOffsetX = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsX; - var grabberScaleCubeOffsetY = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsY; - var grabberScaleCubeOffsetZ = GRABBER_SCALE_CUBE_OFFSET * worldDimensionsZ; - var scaleDimension = dimensionAverage * GRABBER_SCALE_CUBE_DIMENSION_MULTIPLE; + var grabberScaleCubeOffsetX = GRABBER_SCALE_CUBE_OFFSET * dimensions.x; + var grabberScaleCubeOffsetY = GRABBER_SCALE_CUBE_OFFSET * dimensions.y; + var grabberScaleCubeOffsetZ = GRABBER_SCALE_CUBE_OFFSET * dimensions.z; + var scaleDimension = entityToCameraDistance * GRABBER_SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE; var scaleDimensions = { x:scaleDimension, y:scaleDimension, z:scaleDimension }; - var grabberScaleLBNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + var grabberScaleLBNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleLBNCube, { position: grabberScaleLBNCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleRBNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + var grabberScaleRBNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleRBNCube, { position: grabberScaleRBNCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleLBFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + var grabberScaleLBFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleLBFCube, { position: grabberScaleLBFCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleRBFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + var grabberScaleRBFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleRBFCube, { position: grabberScaleRBFCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleLTNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + var grabberScaleLTNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleLTNCube, { position: grabberScaleLTNCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleRTNCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + var grabberScaleRTNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleRTNCube, { position: grabberScaleRTNCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleLTFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); + var grabberScaleLTFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleLTFCube, { position: grabberScaleLTFCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); - var grabberScaleRTFCubePos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); + var grabberScaleRTFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); Overlays.editOverlay(grabberScaleRTFCube, { position: grabberScaleRTFCubePos, - rotation: worldRotation, + rotation: rotation, dimensions: scaleDimensions }); @@ -1498,82 +1525,85 @@ SelectionDisplay = (function() { Overlays.editOverlay(grabberScaleFREdge, { start: grabberScaleRTFCubePos, end: grabberScaleRBFCubePos }); Overlays.editOverlay(grabberScaleFLEdge, { start: grabberScaleLTFCubePos, end: grabberScaleLBFCubePos }); - var stretchSphereDimension = dimensionAverage * GRABBER_STRETCH_SPHERE_DIMENSION_MULTIPLE; + var stretchSphereDimension = entityToCameraDistance * GRABBER_STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE; var stretchSphereDimensions = { x:stretchSphereDimension, y:stretchSphereDimension, z:stretchSphereDimension }; - var stretchXPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsX, y:0, z:0 })); + var stretchXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance, y:0, z:0 })); Overlays.editOverlay(grabberStretchXSphere, { position: stretchXPos, dimensions: stretchSphereDimensions }); - var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleLTFCubePos); - var grabberScaleRBFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRBFCubePos); + var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleLTFCubePos); + var grabberScaleRBFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRBFCubePos); var stretchPanelXDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRBFCubePosRot); var tempY = Math.abs(stretchPanelXDimensions.y); stretchPanelXDimensions.x = 0.01; stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); stretchPanelXDimensions.z = tempY; + var stretchPanelXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:dimensions.x / 2, y:0, z:0 })); Overlays.editOverlay(grabberStretchXPanel, { - position: stretchXPos, - rotation: worldRotationZ, + position: stretchPanelXPos, + rotation: rotationZ, dimensions: stretchPanelXDimensions }); - var stretchYPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsY, z:0 })); + var stretchYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance, z:0 })); Overlays.editOverlay(grabberStretchYSphere, { position: stretchYPos, dimensions: stretchSphereDimensions }); - var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleLTNCubePos); - var grabberScaleRTNCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRTFCubePos); + var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleLTNCubePos); + var grabberScaleRTNCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRTFCubePos); var stretchPanelYDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRTNCubePosRot); var tempX = Math.abs(stretchPanelYDimensions.x); stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); stretchPanelYDimensions.y = 0.01; stretchPanelYDimensions.z = tempX; + var stretchPanelYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:dimensions.y / 2, z:0 })); Overlays.editOverlay(grabberStretchYPanel, { - position: stretchYPos, - rotation: worldRotationY, + position: stretchPanelYPos, + rotation: rotationY, dimensions: stretchPanelYDimensions }); - var stretchZPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET * worldDimensionsZ })); + var stretchZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance })); Overlays.editOverlay(grabberStretchZSphere, { position: stretchZPos, dimensions: stretchSphereDimensions }); - var grabberScaleRTFCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRTFCubePos); - var grabberScaleRBNCubePosRot = Vec3.multiplyQbyV(worldRotationInverse, grabberScaleRBNCubePos); + var grabberScaleRTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRTFCubePos); + var grabberScaleRBNCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRBNCubePos); var stretchPanelZDimensions = Vec3.subtract(grabberScaleRTFCubePosRot, grabberScaleRBNCubePosRot); var tempX = Math.abs(stretchPanelZDimensions.x); stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); stretchPanelZDimensions.y = tempX; stretchPanelZDimensions.z = 0.01; + var stretchPanelZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:dimensions.z / 2 })); Overlays.editOverlay(grabberStretchZPanel, { - position: stretchZPos, - rotation: worldRotationX, + position: stretchPanelZPos, + rotation: rotationX, dimensions: stretchPanelZDimensions }); - var rotateDimension = dimensionAverage * GRABBER_ROTATE_RINGS_DIMENSION_MULTIPLE; + var rotateDimension = entityToCameraDistance * GRABBER_ROTATE_RINGS_CAMERA_DISTANCE_MULTIPLE; var rotateDimensions = { x:rotateDimension, y:rotateDimension, z:rotateDimension }; if (!isActiveTool(grabberRotatePitchRing)) { Overlays.editOverlay(grabberRotatePitchRing, { - position: SelectionManager.worldPosition, - rotation: worldRotationY, + position: position, + rotation: rotationY, dimensions: rotateDimensions, majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); } if (!isActiveTool(grabberRotateYawRing)) { Overlays.editOverlay(grabberRotateYawRing, { - position: SelectionManager.worldPosition, - rotation: worldRotationZ, + position: position, + rotation: rotationZ, dimensions: rotateDimensions, majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); } if (!isActiveTool(grabberRotateRollRing)) { Overlays.editOverlay(grabberRotateRollRing, { - position: SelectionManager.worldPosition, - rotation: worldRotationX, + position: position, + rotation: rotationX, dimensions: rotateDimensions, majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE }); @@ -1588,18 +1618,18 @@ SelectionDisplay = (function() { isActiveTool(grabberCloner) || isActiveTool(selectionBox); Overlays.editOverlay(selectionBox, { - position: worldPosition, - rotation: worldRotation, - dimensions: worldDimensions, + position: position, + rotation: rotation, + dimensions: dimensions, visible: !inModeRotate }); - var grabberClonerOffset = { x:GRABBER_CLONER_OFFSET.x * worldDimensionsX, y:GRABBER_CLONER_OFFSET.y * worldDimensionsY, z:GRABBER_CLONER_OFFSET.z * worldDimensionsZ }; - var grabberClonerPos = Vec3.sum(worldPosition, Vec3.multiplyQbyV(worldRotation, grabberClonerOffset)); + var grabberClonerOffset = { x:GRABBER_CLONER_OFFSET.x * dimensions.x, y:GRABBER_CLONER_OFFSET.y * dimensions.y, z:GRABBER_CLONER_OFFSET.z * dimensions.z }; + var grabberClonerPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, grabberClonerOffset)); Overlays.editOverlay(grabberCloner, { position: grabberClonerPos, - rotation: worldRotation, - dimensions: scaleDimensions, + rotation: rotation, + dimensions: scaleDimensions }); } @@ -1615,12 +1645,14 @@ SelectionDisplay = (function() { that.setGrabberScaleVisible(!activeTool || isActiveTool(grabberScaleLBNCube) || isActiveTool(grabberScaleRBNCube) || isActiveTool(grabberScaleLBFCube) || isActiveTool(grabberScaleRBFCube) || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube) || isActiveTool(grabberStretchXSphere) || isActiveTool(grabberStretchYSphere) || isActiveTool(grabberStretchZSphere)); - that.setGrabberClonerVisible(!activeTool || isActiveTool(grabberCloner)); + //keep cloner always hidden for now since you can hold Alt to clone while dragging to translate - we may bring cloner back for HMD only later + //that.setGrabberClonerVisible(!activeTool || isActiveTool(grabberCloner)); if (wantDebug) { print("====== Update Grabbers <======="); } }; + Script.update.connect(that.updateGrabbers); that.updateActiveRotateRing = function() { var activeRotateRing = null; @@ -1756,6 +1788,7 @@ SelectionDisplay = (function() { } SelectionManager.saveProperties(); + that.resetPreviousHandleColor(); that.setGrabberTranslateVisible(false); that.setGrabberRotateVisible(false); @@ -2059,6 +2092,33 @@ SelectionDisplay = (function() { return activeTool; }; + that.resetPreviousHandleColor = function() { + if (previousHandle != null) { + Overlays.editOverlay(previousHandle, { color: previousHandleColor }); + previousHandle = null; + } + if (previousHandleHelper != null) { + Overlays.editOverlay(previousHandleHelper, { color: previousHandleColor }); + previousHandleHelper = null; + } + }; + + that.getHandleHelper = function(overlay) { + if (overlay === grabberTranslateXCone) { + return grabberTranslateXCylinder; + } else if (overlay === grabberTranslateXCylinder) { + return grabberTranslateXCone; + } else if (overlay === grabberTranslateYCone) { + return grabberTranslateYCylinder; + } else if (overlay === grabberTranslateYCylinder) { + return grabberTranslateYCone; + } else if (overlay === grabberTranslateZCone) { + return grabberTranslateZCylinder; + } else if (overlay === grabberTranslateZCylinder) { + return grabberTranslateZCone; + } + }; + // FUNCTION: MOUSE MOVE EVENT that.mouseMoveEvent = function(event) { var wantDebug = false; @@ -2083,6 +2143,66 @@ SelectionDisplay = (function() { return true; } + // if no tool is active, then just look for handles to highlight... + var pickRay = generalComputePickRay(event.x, event.y); + var result = Overlays.findRayIntersection(pickRay); + var pickedColor; + var highlightNeeded = false; + + if (result.intersects) { + switch (result.overlayID) { + case grabberTranslateXCone: + case grabberTranslateXCylinder: + case grabberRotatePitchRing: + case grabberStretchXSphere: + pickedColor = COLOR_RED; + highlightNeeded = true; + break; + case grabberTranslateYCone: + case grabberTranslateYCylinder: + case grabberRotateYawRing: + case grabberStretchYSphere: + pickedColor = COLOR_GREEN; + highlightNeeded = true; + break; + case grabberTranslateZCone: + case grabberTranslateZCylinder: + case grabberRotateRollRing: + case grabberStretchZSphere: + pickedColor = COLOR_BLUE; + highlightNeeded = true; + break; + case grabberScaleLBNCube: + case grabberScaleRBNCube: + case grabberScaleLBFCube: + case grabberScaleRBFCube: + case grabberScaleLTNCube: + case grabberScaleRTNCube: + case grabberScaleLTFCube: + case grabberScaleRTFCube: + pickedColor = GRABBER_SCALE_CUBE_IDLE_COLOR; + highlightNeeded = true; + break; + default: + that.resetPreviousHandleColor(); + break; + } + + if (highlightNeeded) { + that.resetPreviousHandleColor(); + Overlays.editOverlay(result.overlayID, { color: GRABBER_HOVER_COLOR }); + previousHandle = result.overlayID; + previousHandleHelper = that.getHandleHelper(result.overlayID); + if (previousHandleHelper != null) { + Overlays.editOverlay(previousHandleHelper, { color: GRABBER_HOVER_COLOR }); + } + previousHandleColor = pickedColor; + } + + } else { + that.resetPreviousHandleColor(); + } + if (wantDebug) { print("=============== eST::MouseMoveEvent END ======================="); } From db56246cd6b1e88bd438ee5d8e4714b0948cc285 Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 1 Feb 2018 17:30:56 -0800 Subject: [PATCH 060/272] more fixes, clean up, updates --- scripts/system/edit.js | 3 +- .../system/libraries/entitySelectionTool.js | 2525 +++++++++-------- 2 files changed, 1313 insertions(+), 1215 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 8dd2980ee6..4ef88fcd21 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -65,7 +65,7 @@ gridTool.setVisible(false); var entityListTool = new EntityListTool(); selectionManager.addEventListener(function () { - selectionDisplay.updateGrabbers(); + selectionDisplay.updateHandles(); entityIconOverlayManager.updatePositions(); // Update particle explorer @@ -1250,7 +1250,6 @@ var lastPosition = null; // Do some stuff regularly, like check for placement of various overlays Script.update.connect(function (deltaTime) { progressDialog.move(); - selectionDisplay.checkMove(); selectionDisplay.checkControllerMove(); var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); var dPosition = Vec3.distance(Camera.position, lastPosition); diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 87dc089c1a..c68fb6e71c 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -19,6 +19,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; SPACE_LOCAL = "local"; SPACE_WORLD = "world"; +HIGHLIGHT_LIST_NAME = "editHandleHighlightList"; Script.include("./controllers.js"); @@ -58,6 +59,22 @@ SelectionManager = (function() { subscribeToUpdateMessages(); + var COLOR_ORANGE_HIGHLIGHT = { red: 255, green: 99, blue: 9 } + var editHandleOutlineStyle = { + outlineUnoccludedColor: COLOR_ORANGE_HIGHLIGHT, + outlineOccludedColor: COLOR_ORANGE_HIGHLIGHT, + fillUnoccludedColor: COLOR_ORANGE_HIGHLIGHT, + fillOccludedColor: COLOR_ORANGE_HIGHLIGHT, + outlineUnoccludedAlpha: 1, + outlineOccludedAlpha: 0, + fillUnoccludedAlpha: 0, + fillOccludedAlpha: 0, + outlineWidth: 3, + isOutlineSmooth: true + }; + //disabling this for now as it is causing rendering issues with the other handle overlays + //Selection.enableListHighlight(HIGHLIGHT_LIST_NAME, editHandleOutlineStyle); + that.savedProperties = {}; that.selections = []; var listeners = []; @@ -94,7 +111,7 @@ SelectionManager = (function() { for (var i = 0; i < entityIDs.length; i++) { var entityID = entityIDs[i]; that.selections.push(entityID); - //Selection.addToSelectedItemsList("contextOverlayHighlightList", "entity", entityID); + Selection.addToSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID); } that._update(true); @@ -111,10 +128,10 @@ SelectionManager = (function() { } if (idx === -1) { that.selections.push(entityID); - //Selection.addToSelectedItemsList("contextOverlayHighlightList", "entity", entityID); + Selection.addToSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID); } else if (toggleSelection) { that.selections.splice(idx, 1); - //Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); + Selection.removeFromSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID); } } @@ -125,7 +142,7 @@ SelectionManager = (function() { var idx = that.selections.indexOf(entityID); if (idx >= 0) { that.selections.splice(idx, 1); - //Selection.removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityID); + Selection.removeFromSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID); } that._update(true); }; @@ -149,9 +166,11 @@ SelectionManager = (function() { that.localPosition = properties.position; that.localRotation = properties.rotation; that.localRegistrationPoint = properties.registrationPoint; + that.worldDimensions = properties.boundingBox.dimensions; that.worldPosition = properties.boundingBox.center; that.worldRotation = properties.boundingBox.rotation; + SelectionDisplay.setSpaceMode(SPACE_LOCAL); } else { that.localRotation = null; @@ -163,7 +182,7 @@ SelectionManager = (function() { var brn = properties.boundingBox.brn; var tfl = properties.boundingBox.tfl; - for (var i = 1; i < that.selections.length; i++) { + for (var i = 0; i < that.selections.length; i++) { properties = Entities.getEntityProperties(that.selections[i]); var bb = properties.boundingBox; brn.x = Math.min(bb.brn.x, brn.x); @@ -213,18 +232,6 @@ function normalizeDegrees(degrees) { return degrees; } -// FUNCTION: getRelativeCenterPosition -// Return the enter position of an entity relative to it's registrationPoint -// A registration point of (0.5, 0.5, 0.5) will have an offset of (0, 0, 0) -// A registration point of (1.0, 1.0, 1.0) will have an offset of (-dimensions.x / 2, -dimensions.y / 2, -dimensions.z / 2) -function getRelativeCenterPosition(dimensions, registrationPoint) { - return { - x: -dimensions.x * (registrationPoint.x - 0.5), - y: -dimensions.y * (registrationPoint.y - 0.5), - z: -dimensions.z * (registrationPoint.z - 0.5) - }; -} - // SELECTION DISPLAY DEFINITION SelectionDisplay = (function() { var that = {}; @@ -232,39 +239,39 @@ SelectionDisplay = (function() { var COLOR_GREEN = { red:44, green:142, blue:14 }; var COLOR_BLUE = { red:0, green:147, blue:197 }; var COLOR_RED = { red:183, green:10, blue:55 }; + var COLOR_HOVER = { red:227, green:227, blue:227 }; + var COLOR_SCALE_EDGE = { red:87, green:87, blue:87 }; + var COLOR_SCALE_CUBE = { red:106, green:106, blue:106 }; + var COLOR_SCALE_CUBE_SELECTED = { red:18, green:18, blue:18 }; - var GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET = 0.1; - var GRABBER_TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE = 0.005; - var GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE = 7.5; - var GRABBER_TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE = 0.025; - var GRABBER_ROTATE_RINGS_CAMERA_DISTANCE_MULTIPLE = 0.15; - var GRABBER_STRETCH_SPHERE_OFFSET = 0.06; - var GRABBER_STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE = 0.01; - var GRABBER_SCALE_CUBE_OFFSET = 0.5; - var GRABBER_SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.015; - var GRABBER_CLONER_OFFSET = { x:0.9, y:-0.9, z:0.9 }; + var TRANSLATE_ARROW_CYLINDER_OFFSET = 0.1; + var TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE = 0.005; + var TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE = 7.5; + var TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE = 0.025; - var GRABBER_SCALE_CUBE_IDLE_COLOR = { red:106, green:106, blue:106 }; - var GRABBER_SCALE_CUBE_SELECTED_COLOR = { red:18, green:18, blue:18 }; - var GRABBER_SCALE_EDGE_COLOR = { red:87, green:87, blue:87 }; - var GRABBER_HOVER_COLOR = { red:227, green:227, blue:227 }; - - var SCALE_MINIMUM_DIMENSION = 0.02; - var STRETCH_MINIMUM_DIMENSION = 0.001; - var STRETCH_DIRECTION_ALL_FACTOR = 25; + var ROTATE_RING_CAMERA_DISTANCE_MULTIPLE = 0.15; + var ROTATE_CTRL_SNAP_ANGLE = 22.5; + var ROTATE_DEFAULT_SNAP_ANGLE = 1; + var ROTATE_DEFAULT_TICK_MARKS_ANGLE = 5; + var ROTATE_RING_IDLE_INNER_RADIUS = 0.97; + var ROTATE_RING_SELECTED_INNER_RADIUS = 0.9; // These are multipliers for sizing the rotation degrees display while rotating an entity - var ROTATION_DISPLAY_DISTANCE_MULTIPLIER = 1.0; - var ROTATION_DISPLAY_SIZE_X_MULTIPLIER = 0.3; - var ROTATION_DISPLAY_SIZE_Y_MULTIPLIER = 0.09; - var ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.07; + var ROTATE_DISPLAY_DISTANCE_MULTIPLIER = 1.0; + var ROTATE_DISPLAY_SIZE_X_MULTIPLIER = 0.3; + var ROTATE_DISPLAY_SIZE_Y_MULTIPLIER = 0.09; + var ROTATE_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.07; - var ROTATION_CTRL_SNAP_ANGLE = 22.5; - var ROTATION_DEFAULT_SNAP_ANGLE = 1; - var ROTATION_DEFAULT_TICK_MARKS_ANGLE = 5; + var STRETCH_SPHERE_OFFSET = 0.06; + var STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE = 0.01; + var STRETCH_MINIMUM_DIMENSION = 0.001; + var STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE = 2; - var ROTATION_RING_IDLE_INNER_RADIUS = 0.97; - var ROTATION_RING_SELECTED_INNER_RADIUS = 0.9; + var SCALE_CUBE_OFFSET = 0.5; + var SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE = 0.015; + var SCALE_MINIMUM_DIMENSION = 0.02; + + var CLONER_OFFSET = { x:0.9, y:-0.9, z:0.9 }; var TRANSLATE_DIRECTION = { X : 0, @@ -305,79 +312,76 @@ SelectionDisplay = (function() { getControllerWorldLocation(Controller.Standard.RightHand, true) ]; - var rotZero; + var rotationZero; var rotationNormal; - var rotDegreePos; + var rotationDegreesPosition; var worldRotationX; var worldRotationY; var worldRotationZ; - var ctrlPressed = false; - var previousHandle = null; var previousHandleHelper = null; var previousHandleColor; - var activeTool = null; - var grabberTools = {}; + var ctrlPressed = false; - var grabberPropertiesTranslateArrowCones = { + var handlePropertiesTranslateArrowCones = { shape: "Cone", solid: true, visible: false, ignoreRayIntersection: false, drawInFront: true }; - var grabberPropertiesTranslateArrowCylinders = { + var handlePropertiesTranslateArrowCylinders = { shape: "Cylinder", solid: true, visible: false, ignoreRayIntersection: false, drawInFront: true }; - var grabberTranslateXCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); - var grabberTranslateXCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); - Overlays.editOverlay(grabberTranslateXCone, { color : COLOR_RED }); - Overlays.editOverlay(grabberTranslateXCylinder, { color : COLOR_RED }); - var grabberTranslateYCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); - var grabberTranslateYCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); - Overlays.editOverlay(grabberTranslateYCone, { color : COLOR_GREEN }); - Overlays.editOverlay(grabberTranslateYCylinder, { color : COLOR_GREEN }); - var grabberTranslateZCone = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCones); - var grabberTranslateZCylinder = Overlays.addOverlay("shape", grabberPropertiesTranslateArrowCylinders); - Overlays.editOverlay(grabberTranslateZCone, { color : COLOR_BLUE }); - Overlays.editOverlay(grabberTranslateZCylinder, { color : COLOR_BLUE }); + var handleTranslateXCone = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCones); + var handleTranslateXCylinder = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCylinders); + Overlays.editOverlay(handleTranslateXCone, { color : COLOR_RED }); + Overlays.editOverlay(handleTranslateXCylinder, { color : COLOR_RED }); + var handleTranslateYCone = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCones); + var handleTranslateYCylinder = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCylinders); + Overlays.editOverlay(handleTranslateYCone, { color : COLOR_GREEN }); + Overlays.editOverlay(handleTranslateYCylinder, { color : COLOR_GREEN }); + var handleTranslateZCone = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCones); + var handleTranslateZCylinder = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCylinders); + Overlays.editOverlay(handleTranslateZCone, { color : COLOR_BLUE }); + Overlays.editOverlay(handleTranslateZCylinder, { color : COLOR_BLUE }); - var grabberPropertiesRotateRings = { + var handlePropertiesRotateRings = { alpha: 1, solid: true, startAt: 0, endAt: 360, - innerRadius: ROTATION_RING_IDLE_INNER_RADIUS, - majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE, + innerRadius: ROTATE_RING_IDLE_INNER_RADIUS, + majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE, majorTickMarksLength: 0.1, visible: false, ignoreRayIntersection: false, drawInFront: true }; - var grabberRotatePitchRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); - Overlays.editOverlay(grabberRotatePitchRing, { + var handleRotatePitchRing = Overlays.addOverlay("circle3d", handlePropertiesRotateRings); + Overlays.editOverlay(handleRotatePitchRing, { color : COLOR_RED, majorTickMarksColor: COLOR_RED, }); - var grabberRotateYawRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); - Overlays.editOverlay(grabberRotateYawRing, { + var handleRotateYawRing = Overlays.addOverlay("circle3d", handlePropertiesRotateRings); + Overlays.editOverlay(handleRotateYawRing, { color : COLOR_GREEN, majorTickMarksColor: COLOR_GREEN, }); - var grabberRotateRollRing = Overlays.addOverlay("circle3d", grabberPropertiesRotateRings); - Overlays.editOverlay(grabberRotateRollRing, { + var handleRotateRollRing = Overlays.addOverlay("circle3d", handlePropertiesRotateRings); + Overlays.editOverlay(handleRotateRollRing, { color : COLOR_BLUE, majorTickMarksColor: COLOR_BLUE, }); - var grabberRotateCurrentRing = Overlays.addOverlay("circle3d", { + var handleRotateCurrentRing = Overlays.addOverlay("circle3d", { alpha: 1, color: { red: 255, green: 99, blue: 9 }, solid: true, @@ -405,21 +409,21 @@ SelectionDisplay = (function() { leftMargin: 0 }); - var grabberPropertiesStretchSpheres = { + var handlePropertiesStretchSpheres = { shape: "Sphere", solid: true, visible: false, ignoreRayIntersection: false, drawInFront: true }; - var grabberStretchXSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); - Overlays.editOverlay(grabberStretchXSphere, { color : COLOR_RED }); - var grabberStretchYSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); - Overlays.editOverlay(grabberStretchYSphere, { color : COLOR_GREEN }); - var grabberStretchZSphere = Overlays.addOverlay("shape", grabberPropertiesStretchSpheres); - Overlays.editOverlay(grabberStretchZSphere, { color : COLOR_BLUE }); + var handleStretchXSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres); + Overlays.editOverlay(handleStretchXSphere, { color : COLOR_RED }); + var handleStretchYSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres); + Overlays.editOverlay(handleStretchYSphere, { color : COLOR_GREEN }); + var handleStretchZSphere = Overlays.addOverlay("shape", handlePropertiesStretchSpheres); + Overlays.editOverlay(handleStretchZSphere, { color : COLOR_BLUE }); - var grabberPropertiesStretchPanel = { + var handlePropertiesStretchPanel = { shape: "Quad", alpha: 0.5, solid: true, @@ -427,52 +431,52 @@ SelectionDisplay = (function() { ignoreRayIntersection: true, drawInFront: true, } - var grabberStretchXPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); - Overlays.editOverlay(grabberStretchXPanel, { color : COLOR_RED }); - var grabberStretchYPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); - Overlays.editOverlay(grabberStretchYPanel, { color : COLOR_GREEN }); - var grabberStretchZPanel = Overlays.addOverlay("shape", grabberPropertiesStretchPanel); - Overlays.editOverlay(grabberStretchZPanel, { color : COLOR_BLUE }); + var handleStretchXPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); + Overlays.editOverlay(handleStretchXPanel, { color : COLOR_RED }); + var handleStretchYPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); + Overlays.editOverlay(handleStretchYPanel, { color : COLOR_GREEN }); + var handleStretchZPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); + Overlays.editOverlay(handleStretchZPanel, { color : COLOR_BLUE }); - var grabberPropertiesScaleCubes = { + var handlePropertiesScaleCubes = { size: 0.025, - color: GRABBER_SCALE_CUBE_IDLE_COLOR, + color: COLOR_SCALE_CUBE, solid: true, visible: false, ignoreRayIntersection: false, drawInFront: true, borderSize: 1.4 }; - var grabberScaleLBNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, -y, -z) - var grabberScaleRBNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, -y, z) - var grabberScaleLBFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, -y, -z) - var grabberScaleRBFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, -y, z) - var grabberScaleLTNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, y, -z) - var grabberScaleRTNCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // (-x, y, z) - var grabberScaleLTFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, y, -z) - var grabberScaleRTFCube = Overlays.addOverlay("cube", grabberPropertiesScaleCubes); // ( x, y, z) + var handleScaleLBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, -z) + var handleScaleRBNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, -y, z) + var handleScaleLBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, -z) + var handleScaleRBFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, -y, z) + var handleScaleLTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, -z) + var handleScaleRTNCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // (-x, y, z) + var handleScaleLTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, -z) + var handleScaleRTFCube = Overlays.addOverlay("cube", handlePropertiesScaleCubes); // ( x, y, z) - var grabberPropertiesScaleEdge = { - color: GRABBER_SCALE_EDGE_COLOR, + var handlePropertiesScaleEdge = { + color: COLOR_SCALE_EDGE, visible: false, ignoreRayIntersection: true, drawInFront: true, lineWidth: 0.2 } - var grabberScaleTREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleTLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleTFEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleTNEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleBREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleBLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleBFEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleBNEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleNREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleNLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleFREdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); - var grabberScaleFLEdge = Overlays.addOverlay("line3d", grabberPropertiesScaleEdge); + var handleScaleTREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleTLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleTFEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleTNEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleBREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleBLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleBFEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleBNEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleNREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleNLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleFREdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); + var handleScaleFLEdge = Overlays.addOverlay("line3d", handlePropertiesScaleEdge); - var grabberCloner = Overlays.addOverlay("cube", { + var handleCloner = Overlays.addOverlay("cube", { size: 0.05, color: COLOR_GREEN, solid: true, @@ -482,97 +486,107 @@ SelectionDisplay = (function() { borderSize: 1.4 }); + // setting to 0 alpha for now to keep this hidden vs using visible false + // because its used as the translate xz tool handle overlay var selectionBox = Overlays.addOverlay("cube", { size: 1, color: COLOR_RED, - alpha: 0, // setting to 0 alpha for now to keep this hidden vs using visible false because its used as the translate xz tool overlay + alpha: 0, solid: false, visible: false, dashed: false }); var allOverlays = [ - grabberTranslateXCone, - grabberTranslateXCylinder, - grabberTranslateYCone, - grabberTranslateYCylinder, - grabberTranslateZCone, - grabberTranslateZCylinder, - grabberRotatePitchRing, - grabberRotateYawRing, - grabberRotateRollRing, - grabberRotateCurrentRing, + handleTranslateXCone, + handleTranslateXCylinder, + handleTranslateYCone, + handleTranslateYCylinder, + handleTranslateZCone, + handleTranslateZCylinder, + handleRotatePitchRing, + handleRotateYawRing, + handleRotateRollRing, + handleRotateCurrentRing, rotationDegreesDisplay, - grabberStretchXSphere, - grabberStretchYSphere, - grabberStretchZSphere, - grabberStretchXPanel, - grabberStretchYPanel, - grabberStretchZPanel, - grabberScaleLBNCube, - grabberScaleRBNCube, - grabberScaleLBFCube, - grabberScaleRBFCube, - grabberScaleLTNCube, - grabberScaleRTNCube, - grabberScaleLTFCube, - grabberScaleRTFCube, - grabberScaleTREdge, - grabberScaleTLEdge, - grabberScaleTFEdge, - grabberScaleTNEdge, - grabberScaleBREdge, - grabberScaleBLEdge, - grabberScaleBFEdge, - grabberScaleBNEdge, - grabberScaleNREdge, - grabberScaleNLEdge, - grabberScaleFREdge, - grabberScaleFLEdge, - grabberCloner, + handleStretchXSphere, + handleStretchYSphere, + handleStretchZSphere, + handleStretchXPanel, + handleStretchYPanel, + handleStretchZPanel, + handleScaleLBNCube, + handleScaleRBNCube, + handleScaleLBFCube, + handleScaleRBFCube, + handleScaleLTNCube, + handleScaleRTNCube, + handleScaleLTFCube, + handleScaleRTFCube, + handleScaleTREdge, + handleScaleTLEdge, + handleScaleTFEdge, + handleScaleTNEdge, + handleScaleBREdge, + handleScaleBLEdge, + handleScaleBFEdge, + handleScaleBNEdge, + handleScaleNREdge, + handleScaleNLEdge, + handleScaleFREdge, + handleScaleFLEdge, + handleCloner, selectionBox ]; - overlayNames[grabberTranslateXCone] = "grabberTranslateXCone"; - overlayNames[grabberTranslateXCylinder] = "grabberTranslateXCylinder"; - overlayNames[grabberTranslateYCone] = "grabberTranslateYCone"; - overlayNames[grabberTranslateYCylinder] = "grabberTranslateYCylinder"; - overlayNames[grabberTranslateZCone] = "grabberTranslateZCone"; - overlayNames[grabberTranslateZCylinder] = "grabberTranslateZCylinder"; - overlayNames[grabberRotatePitchRing] = "grabberRotatePitchRing"; - overlayNames[grabberRotateYawRing] = "grabberRotateYawRing"; - overlayNames[grabberRotateRollRing] = "grabberRotateRollRing"; - overlayNames[grabberRotateCurrentRing] = "grabberRotateCurrentRing"; + overlayNames[handleTranslateXCone] = "handleTranslateXCone"; + overlayNames[handleTranslateXCylinder] = "handleTranslateXCylinder"; + overlayNames[handleTranslateYCone] = "handleTranslateYCone"; + overlayNames[handleTranslateYCylinder] = "handleTranslateYCylinder"; + overlayNames[handleTranslateZCone] = "handleTranslateZCone"; + overlayNames[handleTranslateZCylinder] = "handleTranslateZCylinder"; + + overlayNames[handleRotatePitchRing] = "handleRotatePitchRing"; + overlayNames[handleRotateYawRing] = "handleRotateYawRing"; + overlayNames[handleRotateRollRing] = "handleRotateRollRing"; + overlayNames[handleRotateCurrentRing] = "handleRotateCurrentRing"; overlayNames[rotationDegreesDisplay] = "rotationDegreesDisplay"; - overlayNames[grabberStretchXSphere] = "grabberStretchXSphere"; - overlayNames[grabberStretchYSphere] = "grabberStretchYSphere"; - overlayNames[grabberStretchZSphere] = "grabberStretchZSphere"; - overlayNames[grabberStretchXPanel] = "grabberStretchXPanel"; - overlayNames[grabberStretchYPanel] = "grabberStretchYPanel"; - overlayNames[grabberStretchZPanel] = "grabberStretchZPanel"; - overlayNames[grabberScaleLBNCube] = "grabberScaleLBNCube"; - overlayNames[grabberScaleRBNCube] = "grabberScaleRBNCube"; - overlayNames[grabberScaleLBFCube] = "grabberScaleLBFCube"; - overlayNames[grabberScaleRBFCube] = "grabberScaleRBFCube"; - overlayNames[grabberScaleLTNCube] = "grabberScaleLTNCube"; - overlayNames[grabberScaleRTNCube] = "grabberScaleRTNCube"; - overlayNames[grabberScaleLTFCube] = "grabberScaleLTFCube"; - overlayNames[grabberScaleRTFCube] = "grabberScaleRTFCube"; - overlayNames[grabberScaleTREdge] = "grabberScaleTREdge"; - overlayNames[grabberScaleTLEdge] = "grabberScaleTLEdge"; - overlayNames[grabberScaleTFEdge] = "grabberScaleTFEdge"; - overlayNames[grabberScaleTNEdge] = "grabberScaleTNEdge"; - overlayNames[grabberScaleBREdge] = "grabberScaleBREdge"; - overlayNames[grabberScaleBLEdge] = "grabberScaleBLEdge"; - overlayNames[grabberScaleBFEdge] = "grabberScaleBFEdge"; - overlayNames[grabberScaleBNEdge] = "grabberScaleBNEdge"; - overlayNames[grabberScaleNREdge] = "grabberScaleNREdge"; - overlayNames[grabberScaleNLEdge] = "grabberScaleNLEdge"; - overlayNames[grabberScaleFREdge] = "grabberScaleFREdge"; - overlayNames[grabberScaleFLEdge] = "grabberScaleFLEdge"; - overlayNames[grabberCloner] = "grabberCloner"; + + overlayNames[handleStretchXSphere] = "handleStretchXSphere"; + overlayNames[handleStretchYSphere] = "handleStretchYSphere"; + overlayNames[handleStretchZSphere] = "handleStretchZSphere"; + overlayNames[handleStretchXPanel] = "handleStretchXPanel"; + overlayNames[handleStretchYPanel] = "handleStretchYPanel"; + overlayNames[handleStretchZPanel] = "handleStretchZPanel"; + + overlayNames[handleScaleLBNCube] = "handleScaleLBNCube"; + overlayNames[handleScaleRBNCube] = "handleScaleRBNCube"; + overlayNames[handleScaleLBFCube] = "handleScaleLBFCube"; + overlayNames[handleScaleRBFCube] = "handleScaleRBFCube"; + overlayNames[handleScaleLTNCube] = "handleScaleLTNCube"; + overlayNames[handleScaleRTNCube] = "handleScaleRTNCube"; + overlayNames[handleScaleLTFCube] = "handleScaleLTFCube"; + overlayNames[handleScaleRTFCube] = "handleScaleRTFCube"; + + overlayNames[handleScaleTREdge] = "handleScaleTREdge"; + overlayNames[handleScaleTLEdge] = "handleScaleTLEdge"; + overlayNames[handleScaleTFEdge] = "handleScaleTFEdge"; + overlayNames[handleScaleTNEdge] = "handleScaleTNEdge"; + overlayNames[handleScaleBREdge] = "handleScaleBREdge"; + overlayNames[handleScaleBLEdge] = "handleScaleBLEdge"; + overlayNames[handleScaleBFEdge] = "handleScaleBFEdge"; + overlayNames[handleScaleBNEdge] = "handleScaleBNEdge"; + overlayNames[handleScaleNREdge] = "handleScaleNREdge"; + overlayNames[handleScaleNLEdge] = "handleScaleNLEdge"; + overlayNames[handleScaleFREdge] = "handleScaleFREdge"; + overlayNames[handleScaleFLEdge] = "handleScaleFLEdge"; + + overlayNames[handleCloner] = "handleCloner"; overlayNames[selectionBox] = "selectionBox"; + var activeTool = null; + var handleTools = {}; + // We get mouseMoveEvents from the handControllers, via handControllerPointer. // But we dont' get mousePressEvents. that.triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); @@ -604,8 +618,247 @@ SelectionDisplay = (function() { that.triggerMapping.from(Controller.Standard.RT).peek().to(makeTriggerHandler(Controller.Standard.RightHand)); that.triggerMapping.from(Controller.Standard.LT).peek().to(makeTriggerHandler(Controller.Standard.LeftHand)); + // FUNCTION DEF(s): Intersection Check Helpers + function testRayIntersect(queryRay, overlayIncludes, overlayExcludes) { + var wantDebug = false; + if ((queryRay === undefined) || (queryRay === null)) { + if (wantDebug) { + print("testRayIntersect - EARLY EXIT -> queryRay is undefined OR null!"); + } + return null; + } + + var intersectObj = Overlays.findRayIntersection(queryRay, true, overlayIncludes, overlayExcludes); + + if (wantDebug) { + if (!overlayIncludes) { + print("testRayIntersect - no overlayIncludes provided."); + } + if (!overlayExcludes) { + print("testRayIntersect - no overlayExcludes provided."); + } + print("testRayIntersect - Hit: " + intersectObj.intersects); + print(" intersectObj.overlayID:" + intersectObj.overlayID + "[" + overlayNames[intersectObj.overlayID] + "]"); + print(" OverlayName: " + overlayNames[intersectObj.overlayID]); + print(" intersectObj.distance:" + intersectObj.distance); + print(" intersectObj.face:" + intersectObj.face); + Vec3.print(" intersectObj.intersection:", intersectObj.intersection); + } + + return intersectObj; + } + + // FUNCTION: MOUSE PRESS EVENT + that.mousePressEvent = function (event) { + var wantDebug = false; + if (wantDebug) { + print("=============== eST::MousePressEvent BEG ======================="); + } + if (!event.isLeftButton && !that.triggered) { + // EARLY EXIT-(if another mouse button than left is pressed ignore it) + return false; + } + + 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]; + for (var key in handleTools) { + if (handleTools.hasOwnProperty(key)) { + interactiveOverlays.push(key); + } + } + + // Start with unknown mode, in case no tool can handle this. + activeTool = null; + + var results = testRayIntersect(pickRay, interactiveOverlays); + if (results.intersects) { + var hitOverlayID = results.overlayID; + if ((hitOverlayID === HMD.tabletID) || (hitOverlayID === HMD.tabletScreenID) || (hitOverlayID === HMD.homeButtonID)) { + // EARLY EXIT-(mouse clicks on the tablet should override the edit affordances) + return false; + } + + entityIconOverlayManager.setIconsSelectable(SelectionManager.selections, true); + + var hitTool = handleTools[ hitOverlayID ]; + if (hitTool) { + activeTool = hitTool; + if (activeTool.onBegin) { + activeTool.onBegin(event, pickRay, results); + } else { + print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin"); + } + } else { + print("ERROR: entitySelectionTool.mousePressEvent - Hit unexpected object, check interactiveOverlays"); + }// End_if (hitTool) + }// End_If(results.intersects) + + if (wantDebug) { + print(" DisplayMode: " + getMode()); + print("=============== eST::MousePressEvent END ======================="); + } + + // If mode is known then we successfully handled this; + // otherwise, we're missing a tool. + return activeTool; + }; + + that.resetPreviousHandleColor = function() { + if (previousHandle != null) { + Overlays.editOverlay(previousHandle, { color: previousHandleColor }); + previousHandle = null; + } + if (previousHandleHelper != null) { + Overlays.editOverlay(previousHandleHelper, { color: previousHandleColor }); + previousHandleHelper = null; + } + }; + + that.getHandleHelper = function(overlay) { + if (overlay === handleTranslateXCone) { + return handleTranslateXCylinder; + } else if (overlay === handleTranslateXCylinder) { + return handleTranslateXCone; + } else if (overlay === handleTranslateYCone) { + return handleTranslateYCylinder; + } else if (overlay === handleTranslateYCylinder) { + return handleTranslateYCone; + } else if (overlay === handleTranslateZCone) { + return handleTranslateZCylinder; + } else if (overlay === handleTranslateZCylinder) { + return handleTranslateZCone; + } + }; + + // FUNCTION: MOUSE MOVE EVENT + that.mouseMoveEvent = function(event) { + var wantDebug = false; + if (wantDebug) { + print("=============== eST::MouseMoveEvent BEG ======================="); + } + if (activeTool) { + if (wantDebug) { + print(" Trigger ActiveTool(" + activeTool.mode + ")'s onMove"); + } + activeTool.onMove(event); + + if (wantDebug) { + print(" Trigger SelectionManager::update"); + } + SelectionManager._update(); + + if (wantDebug) { + print("=============== eST::MouseMoveEvent END ======================="); + } + // EARLY EXIT--(Move handled via active tool) + return true; + } + + // if no tool is active, then just look for handles to highlight... + var pickRay = generalComputePickRay(event.x, event.y); + var result = Overlays.findRayIntersection(pickRay); + var pickedColor; + var highlightNeeded = false; + + if (result.intersects) { + switch (result.overlayID) { + case handleTranslateXCone: + case handleTranslateXCylinder: + case handleRotatePitchRing: + case handleStretchXSphere: + pickedColor = COLOR_RED; + highlightNeeded = true; + break; + case handleTranslateYCone: + case handleTranslateYCylinder: + case handleRotateYawRing: + case handleStretchYSphere: + pickedColor = COLOR_GREEN; + highlightNeeded = true; + break; + case handleTranslateZCone: + case handleTranslateZCylinder: + case handleRotateRollRing: + case handleStretchZSphere: + pickedColor = COLOR_BLUE; + highlightNeeded = true; + break; + case handleScaleLBNCube: + case handleScaleRBNCube: + case handleScaleLBFCube: + case handleScaleRBFCube: + case handleScaleLTNCube: + case handleScaleRTNCube: + case handleScaleLTFCube: + case handleScaleRTFCube: + pickedColor = COLOR_SCALE_CUBE; + highlightNeeded = true; + break; + default: + that.resetPreviousHandleColor(); + break; + } + + if (highlightNeeded) { + that.resetPreviousHandleColor(); + Overlays.editOverlay(result.overlayID, { color: COLOR_HOVER }); + previousHandle = result.overlayID; + previousHandleHelper = that.getHandleHelper(result.overlayID); + if (previousHandleHelper != null) { + Overlays.editOverlay(previousHandleHelper, { color: COLOR_HOVER }); + } + previousHandleColor = pickedColor; + } + + } else { + that.resetPreviousHandleColor(); + } + + if (wantDebug) { + print("=============== eST::MouseMoveEvent END ======================="); + } + return false; + }; + + // FUNCTION: MOUSE RELEASE EVENT + that.mouseReleaseEvent = function(event) { + var wantDebug = false; + if (wantDebug) { + print("=============== eST::MouseReleaseEvent BEG ======================="); + } + var showHandles = false; + if (activeTool) { + if (activeTool.onEnd) { + if (wantDebug) { + print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd"); + } + activeTool.onEnd(event); + } else if (wantDebug) { + print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd"); + } + } + + showHandles = activeTool; // base on prior tool value + activeTool = null; + + // if something is selected, then reset the "original" properties for any potential next click+move operation + if (SelectionManager.hasSelection()) { + if (showHandles) { + if (wantDebug) { + print(" Triggering that.select"); + } + that.select(SelectionManager.selections[0], event); + } + } + + if (wantDebug) { + print("=============== eST::MouseReleaseEvent END ======================="); + } + }; + // Control key remains active only while key is held down - function keyReleaseEvent(key) { + that.keyReleaseEvent = function(key) { if (key.key === 16777249) { ctrlPressed = false; that.updateActiveRotateRing(); @@ -613,15 +866,33 @@ SelectionDisplay = (function() { } // Triggers notification on specific key driven events - function keyPressEvent(key) { + that.keyPressEvent = function(key) { if (key.key === 16777249) { ctrlPressed = true; that.updateActiveRotateRing(); } } - Controller.keyPressEvent.connect(keyPressEvent); - Controller.keyReleaseEvent.connect(keyReleaseEvent); + // NOTE: mousePressEvent and mouseMoveEvent from the main script should call us., so we don't hook these: + // Controller.mousePressEvent.connect(that.mousePressEvent); + // Controller.mouseMoveEvent.connect(that.mouseMoveEvent); + Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); + Controller.keyPressEvent.connect(that.keyPressEvent); + Controller.keyReleaseEvent.connect(that.keyReleaseEvent); + + that.checkControllerMove = function() { + if (SelectionManager.hasSelection()) { + var controllerPose = getControllerWorldLocation(activeHand, true); + var hand = (activeHand === Controller.Standard.LeftHand) ? 0 : 1; + if (controllerPose.valid && lastControllerPoses[hand].valid) { + if (!Vec3.equal(controllerPose.position, lastControllerPoses[hand].position) || + !Vec3.equal(controllerPose.rotation, lastControllerPoses[hand].rotation)) { + that.mouseMoveEvent({}); + } + } + lastControllerPoses[hand] = controllerPose; + } + }; function controllerComputePickRay() { var controllerPose = getControllerWorldLocation(activeHand, true); @@ -636,17 +907,703 @@ SelectionDisplay = (function() { function generalComputePickRay(x, y) { return controllerComputePickRay() || Camera.computePickRay(x, y); } - - function addGrabberTool(overlay, tool) { - grabberTools[overlay] = tool; + + function getDistanceToCamera(position) { + var cameraPosition = Camera.getPosition(); + var toCameraDistance = Vec3.length(Vec3.subtract(cameraPosition, position)); + return toCameraDistance; + } + + // @return string - The mode of the currently active tool; + // otherwise, "UNKNOWN" if there's no active tool. + function getMode() { + return (activeTool ? activeTool.mode : "UNKNOWN"); + } + + that.cleanup = function() { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.deleteOverlay(allOverlays[i]); + } + }; + + that.select = function(entityID, event) { + var properties = Entities.getEntityProperties(SelectionManager.selections[0]); + + lastCameraPosition = Camera.getPosition(); + lastCameraOrientation = Camera.getOrientation(); + + if (event !== false) { + pickRay = generalComputePickRay(event.x, event.y); + + var wantDebug = false; + if (wantDebug) { + print("select() with EVENT...... "); + print(" event.y:" + event.y); + Vec3.print(" current position:", properties.position); + } + } + + that.updateHandles(); + }; + + // FUNCTION: SET SPACE MODE + that.setSpaceMode = function(newSpaceMode) { + var wantDebug = false; + if (wantDebug) { + print("======> SetSpaceMode called. ========"); + } + + if (spaceMode !== newSpaceMode) { + if (wantDebug) { + print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode); + } + spaceMode = newSpaceMode; + that.updateHandles(); + } else if (wantDebug) { + print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " + spaceMode + " DesiredMode: " + newSpaceMode); + } + if (wantDebug) { + print("====== SetSpaceMode called. <========"); + } + }; + + function addHandleTool(overlay, tool) { + handleTools[overlay] = tool; return tool; } - function addGrabberTranslateTool(overlay, mode, direction) { + // @param: toolHandle: The overlayID associated with the tool + // that correlates to the tool you wish to query. + // @note: If toolHandle is null or undefined then activeTool + // will be checked against those values as opposed to + // the tool registered under toolHandle. Null & Undefined + // are treated as separate values. + // @return: bool - Indicates if the activeTool is that queried. + function isActiveTool(toolHandle) { + if (!toolHandle) { + // Allow isActiveTool(null) and similar to return true if there's + // no active tool + return (activeTool === toolHandle); + } + + if (!handleTools.hasOwnProperty(toolHandle)) { + print("WARNING: entitySelectionTool.isActiveTool - Encountered unknown grabberToolHandle: " + toolHandle + ". Tools should be registered via addHandleTool."); + // EARLY EXIT + return false; + } + + return (activeTool === handleTools[ toolHandle ]); + } + + // FUNCTION: UPDATE HANDLES + that.updateHandles = function() { + var wantDebug = false; + if (wantDebug) { + print("======> Update Handles ======="); + print(" Selections Count: " + SelectionManager.selections.length); + print(" SpaceMode: " + spaceMode); + print(" DisplayMode: " + getMode()); + } + + if (SelectionManager.selections.length === 0) { + that.setOverlaysVisible(false); + return; + } + + if (SelectionManager.hasSelection()) { + var position = SelectionManager.worldPosition; + var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; + var dimensions = spaceMode === SPACE_LOCAL ? SelectionManager.localDimensions : SelectionManager.worldDimensions; + var rotationInverse = Quat.inverse(rotation); + var toCameraDistance = getDistanceToCamera(position); + + var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); + rotationX = Quat.multiply(rotation, localRotationX); + worldRotationX = rotationX; + var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); + rotationY = Quat.multiply(rotation, localRotationY); + worldRotationY = rotationY; + var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); + rotationZ = Quat.multiply(rotation, localRotationZ); + worldRotationZ = rotationZ; + + // UPDATE TRANSLATION ARROWS + var arrowCylinderDimension = toCameraDistance * TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE; + var arrowCylinderDimensions = { + x:arrowCylinderDimension, + y:arrowCylinderDimension * TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE, + z:arrowCylinderDimension + }; + var arrowConeDimension = toCameraDistance * TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE; + var arrowConeDimensions = { x:arrowConeDimension, y:arrowConeDimension, z:arrowConeDimension }; + var cylinderXPosition = { x:TRANSLATE_ARROW_CYLINDER_OFFSET * toCameraDistance, y:0, z:0 }; + cylinderXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, cylinderXPosition)); + Overlays.editOverlay(handleTranslateXCylinder, { + position: cylinderXPosition, + rotation: rotationX, + dimensions: arrowCylinderDimensions + }); + var cylinderXDiff = Vec3.subtract(cylinderXPosition, position); + var coneXPosition = Vec3.sum(cylinderXPosition, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(handleTranslateXCone, { + position: coneXPosition, + rotation: rotationX, + dimensions: arrowConeDimensions + }); + var cylinderYPosition = { x:0, y:TRANSLATE_ARROW_CYLINDER_OFFSET * toCameraDistance, z:0 }; + cylinderYPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, cylinderYPosition)); + Overlays.editOverlay(handleTranslateYCylinder, { + position: cylinderYPosition, + rotation: rotationY, + dimensions: arrowCylinderDimensions + }); + var cylinderYDiff = Vec3.subtract(cylinderYPosition, position); + var coneYPosition = Vec3.sum(cylinderYPosition, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(handleTranslateYCone, { + position: coneYPosition, + rotation: rotationY, + dimensions: arrowConeDimensions + }); + var cylinderZPosition = { x:0, y:0, z:TRANSLATE_ARROW_CYLINDER_OFFSET * toCameraDistance }; + cylinderZPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, cylinderZPosition)); + Overlays.editOverlay(handleTranslateZCylinder, { + position: cylinderZPosition, + rotation: rotationZ, + dimensions: arrowCylinderDimensions + }); + var cylinderZDiff = Vec3.subtract(cylinderZPosition, position); + var coneZPosition = Vec3.sum(cylinderZPosition, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowCylinderDimensions.y * 0.83)); + Overlays.editOverlay(handleTranslateZCone, { + position: coneZPosition, + rotation: rotationZ, + dimensions: arrowConeDimensions + }); + + // UPDATE ROTATION RINGS + var rotateDimension = toCameraDistance * ROTATE_RING_CAMERA_DISTANCE_MULTIPLE; + var rotateDimensions = { x:rotateDimension, y:rotateDimension, z:rotateDimension }; + if (!isActiveTool(handleRotatePitchRing)) { + Overlays.editOverlay(handleRotatePitchRing, { + position: position, + rotation: rotationY, + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE + }); + } + if (!isActiveTool(handleRotateYawRing)) { + Overlays.editOverlay(handleRotateYawRing, { + position: position, + rotation: rotationZ, + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE + }); + } + if (!isActiveTool(handleRotateRollRing)) { + Overlays.editOverlay(handleRotateRollRing, { + position: position, + rotation: rotationX, + dimensions: rotateDimensions, + majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE + }); + } + Overlays.editOverlay(handleRotateCurrentRing, { dimensions: rotateDimensions }); + that.updateActiveRotateRing(); + + // UPDATE SCALE CUBES + var scaleCubeOffsetX = SCALE_CUBE_OFFSET * dimensions.x; + var scaleCubeOffsetY = SCALE_CUBE_OFFSET * dimensions.y; + var scaleCubeOffsetZ = SCALE_CUBE_OFFSET * dimensions.z; + var scaleCubeDimension = toCameraDistance * SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE; + var scaleCubeDimensions = { x:scaleCubeDimension, y:scaleCubeDimension, z:scaleCubeDimension }; + var scaleCubeRotation = spaceMode === SPACE_LOCAL ? rotation : Quat.IDENTITY; + var scaleLBNCubePosition = { x:-scaleCubeOffsetX, y:-scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + scaleLBNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLBNCubePosition)); + Overlays.editOverlay(handleScaleLBNCube, { + position: scaleLBNCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleRBNCubePosition = { x:-scaleCubeOffsetX, y:-scaleCubeOffsetY, z:scaleCubeOffsetZ }; + scaleRBNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRBNCubePosition)); + Overlays.editOverlay(handleScaleRBNCube, { + position: scaleRBNCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleLBFCubePosition = { x:scaleCubeOffsetX, y:-scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + scaleLBFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLBFCubePosition)); + Overlays.editOverlay(handleScaleLBFCube, { + position: scaleLBFCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleRBFCubePosition = { x:scaleCubeOffsetX, y:-scaleCubeOffsetY, z:scaleCubeOffsetZ }; + scaleRBFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRBFCubePosition)); + Overlays.editOverlay(handleScaleRBFCube, { + position: scaleRBFCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleLTNCubePosition = { x:-scaleCubeOffsetX, y:scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + scaleLTNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLTNCubePosition)); + Overlays.editOverlay(handleScaleLTNCube, { + position: scaleLTNCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleRTNCubePosition = { x:-scaleCubeOffsetX, y:scaleCubeOffsetY, z:scaleCubeOffsetZ }; + scaleRTNCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRTNCubePosition)); + Overlays.editOverlay(handleScaleRTNCube, { + position: scaleRTNCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleLTFCubePosition = { x:scaleCubeOffsetX, y:scaleCubeOffsetY, z:-scaleCubeOffsetZ }; + scaleLTFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleLTFCubePosition)); + Overlays.editOverlay(handleScaleLTFCube, { + position: scaleLTFCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + var scaleRTFCubePosition = { x:scaleCubeOffsetX, y:scaleCubeOffsetY, z:scaleCubeOffsetZ }; + scaleRTFCubePosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, scaleRTFCubePosition)); + Overlays.editOverlay(handleScaleRTFCube, { + position: scaleRTFCubePosition, + rotation: scaleCubeRotation, + dimensions: scaleCubeDimensions + }); + + // UPDATE SCALE EDGES + Overlays.editOverlay(handleScaleTREdge, { start: scaleRTNCubePosition, end: scaleRTFCubePosition }); + Overlays.editOverlay(handleScaleTLEdge, { start: scaleLTNCubePosition, end: scaleLTFCubePosition }); + Overlays.editOverlay(handleScaleTFEdge, { start: scaleLTFCubePosition, end: scaleRTFCubePosition }); + Overlays.editOverlay(handleScaleTNEdge, { start: scaleLTNCubePosition, end: scaleRTNCubePosition }); + Overlays.editOverlay(handleScaleBREdge, { start: scaleRBNCubePosition, end: scaleRBFCubePosition }); + Overlays.editOverlay(handleScaleBLEdge, { start: scaleLBNCubePosition, end: scaleLBFCubePosition }); + Overlays.editOverlay(handleScaleBFEdge, { start: scaleLBFCubePosition, end: scaleRBFCubePosition }); + Overlays.editOverlay(handleScaleBNEdge, { start: scaleLBNCubePosition, end: scaleRBNCubePosition }); + Overlays.editOverlay(handleScaleNREdge, { start: scaleRTNCubePosition, end: scaleRBNCubePosition }); + Overlays.editOverlay(handleScaleNLEdge, { start: scaleLTNCubePosition, end: scaleLBNCubePosition }); + Overlays.editOverlay(handleScaleFREdge, { start: scaleRTFCubePosition, end: scaleRBFCubePosition }); + Overlays.editOverlay(handleScaleFLEdge, { start: scaleLTFCubePosition, end: scaleLBFCubePosition }); + + // UPDATE STRETCH SPHERES + var stretchSphereDimension = toCameraDistance * STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE; + var stretchSphereDimensions = { x:stretchSphereDimension, y:stretchSphereDimension, z:stretchSphereDimension }; + var stretchXPosition = { x:STRETCH_SPHERE_OFFSET * toCameraDistance, y:0, z:0 }; + stretchXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchXPosition)); + Overlays.editOverlay(handleStretchXSphere, { + position: stretchXPosition, + dimensions: stretchSphereDimensions + }); + var stretchYPosition = { x:0, y:STRETCH_SPHERE_OFFSET * toCameraDistance, z:0 }; + stretchYPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchYPosition)); + Overlays.editOverlay(handleStretchYSphere, { + position: stretchYPosition, + dimensions: stretchSphereDimensions + }); + var stretchZPosition = { x:0, y:0, z:STRETCH_SPHERE_OFFSET * toCameraDistance }; + stretchZPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, stretchZPosition)); + Overlays.editOverlay(handleStretchZSphere, { + position: stretchZPosition, + dimensions: stretchSphereDimensions + }); + + // UPDATE STRETCH HIGHLIGHT PANELS + var scaleLTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTFCubePosition); + var scaleRBFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRBFCubePosition); + var stretchPanelXDimensions = Vec3.subtract(scaleLTFCubePositionRotated, scaleRBFCubePositionRotated); + var tempY = Math.abs(stretchPanelXDimensions.y); + stretchPanelXDimensions.x = 0.01; + stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); + stretchPanelXDimensions.z = tempY; + var stretchPanelXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:dimensions.x / 2, y:0, z:0 })); + Overlays.editOverlay(handleStretchXPanel, { + position: stretchPanelXPosition, + rotation: rotationZ, + dimensions: stretchPanelXDimensions + }); + var scaleLTNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleLTNCubePosition); + var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition); + var stretchPanelYDimensions = Vec3.subtract(scaleLTNCubePositionRotated, scaleRTFCubePositionRotated); + var tempX = Math.abs(stretchPanelYDimensions.x); + stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); + stretchPanelYDimensions.y = 0.01; + stretchPanelYDimensions.z = tempX; + var stretchPanelYPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:dimensions.y / 2, z:0 })); + Overlays.editOverlay(handleStretchYPanel, { + position: stretchPanelYPosition, + rotation: rotationY, + dimensions: stretchPanelYDimensions + }); + var scaleRTFCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRTFCubePosition); + var scaleRBNCubePositionRotated = Vec3.multiplyQbyV(rotationInverse, scaleRBNCubePosition); + var stretchPanelZDimensions = Vec3.subtract(scaleRTFCubePositionRotated, scaleRBNCubePositionRotated); + var tempX = Math.abs(stretchPanelZDimensions.x); + stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); + stretchPanelZDimensions.y = tempX; + stretchPanelZDimensions.z = 0.01; + var stretchPanelZPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:dimensions.z / 2 })); + Overlays.editOverlay(handleStretchZPanel, { + position: stretchPanelZPosition, + rotation: rotationX, + dimensions: stretchPanelZDimensions + }); + + // UPDATE SELECTION BOX (CURRENTLY INVISIBLE WITH 0 ALPHA FOR TRANSLATE XZ TOOL) + var inModeRotate = isActiveTool(handleRotatePitchRing) || + isActiveTool(handleRotateYawRing) || + isActiveTool(handleRotateRollRing); + Overlays.editOverlay(selectionBox, { + position: position, + rotation: rotation, + dimensions: dimensions, + visible: !inModeRotate + }); + + // UPDATE CLONER (CURRENTLY HIDDEN FOR NOW) + var handleClonerOffset = { + x:CLONER_OFFSET.x * dimensions.x, + y:CLONER_OFFSET.y * dimensions.y, + z:CLONER_OFFSET.z * dimensions.z + }; + var handleClonerPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, handleClonerOffset)); + Overlays.editOverlay(handleCloner, { + position: handleClonerPos, + rotation: rotation, + dimensions: scaleCubeDimensions + }); + } + + that.setHandleTranslateXVisible(!activeTool || isActiveTool(handleTranslateXCone) || isActiveTool(handleTranslateXCylinder)); + that.setHandleTranslateYVisible(!activeTool || isActiveTool(handleTranslateYCone) || isActiveTool(handleTranslateYCylinder)); + that.setHandleTranslateZVisible(!activeTool || isActiveTool(handleTranslateZCone) || isActiveTool(handleTranslateZCylinder)); + that.setHandleRotatePitchVisible(!activeTool || isActiveTool(handleRotatePitchRing)); + that.setHandleRotateYawVisible(!activeTool || isActiveTool(handleRotateYawRing)); + that.setHandleRotateRollVisible(!activeTool || isActiveTool(handleRotateRollRing)); + + var showScaleStretch = !activeTool && SelectionManager.selections.length === 1; + that.setHandleStretchXVisible(showScaleStretch || isActiveTool(handleStretchXSphere)); + that.setHandleStretchYVisible(showScaleStretch || isActiveTool(handleStretchYSphere)); + that.setHandleStretchZVisible(showScaleStretch || isActiveTool(handleStretchZSphere)); + that.setHandleScaleCubeVisible(showScaleStretch || isActiveTool(handleScaleLBNCube) || isActiveTool(handleScaleRBNCube) || isActiveTool(handleScaleLBFCube) || isActiveTool(handleScaleRBFCube) + || isActiveTool(handleScaleLTNCube) || isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) || isActiveTool(handleScaleRTFCube) + || isActiveTool(handleStretchXSphere) || isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere)); + that.setHandleScaleEdgeVisible(!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) && !isActiveTool(handleRotateRollRing)); + + //keep cloner always hidden for now since you can hold Alt to clone while dragging to translate - we may bring cloner back for HMD only later + //that.setHandleClonerVisible(!activeTool || isActiveTool(handleCloner)); + + if (wantDebug) { + print("====== Update Handles <======="); + } + }; + Script.update.connect(that.updateHandles); + + // FUNCTION: UPDATE ACTIVE ROTATE RING + that.updateActiveRotateRing = function() { + var activeRotateRing = null; + if (isActiveTool(handleRotatePitchRing)) { + activeRotateRing = handleRotatePitchRing; + } else if (isActiveTool(handleRotateYawRing)) { + activeRotateRing = handleRotateYawRing; + } else if (isActiveTool(handleRotateRollRing)) { + activeRotateRing = handleRotateRollRing; + } + if (activeRotateRing != null) { + var tickMarksAngle = ctrlPressed ? ROTATE_CTRL_SNAP_ANGLE : ROTATE_DEFAULT_TICK_MARKS_ANGLE; + Overlays.editOverlay(activeRotateRing, { majorTickMarksAngle: tickMarksAngle }); + } + }; + + // FUNCTION: SET OVERLAYS VISIBLE + that.setOverlaysVisible = function(isVisible) { + for (var i = 0; i < allOverlays.length; i++) { + Overlays.editOverlay(allOverlays[i], { visible: isVisible }); + } + }; + + // FUNCTION: SET HANDLE TRANSLATE VISIBLE + that.setHandleTranslateVisible = function(isVisible) { + that.setHandleTranslateXVisible(isVisible); + that.setHandleTranslateYVisible(isVisible); + that.setHandleTranslateZVisible(isVisible); + }; + + that.setHandleTranslateXVisible = function(isVisible) { + Overlays.editOverlay(handleTranslateXCone, { visible: isVisible }); + Overlays.editOverlay(handleTranslateXCylinder, { visible: isVisible }); + }; + + that.setHandleTranslateYVisible = function(isVisible) { + Overlays.editOverlay(handleTranslateYCone, { visible: isVisible }); + Overlays.editOverlay(handleTranslateYCylinder, { visible: isVisible }); + }; + + that.setHandleTranslateZVisible = function(isVisible) { + Overlays.editOverlay(handleTranslateZCone, { visible: isVisible }); + Overlays.editOverlay(handleTranslateZCylinder, { visible: isVisible }); + }; + + // FUNCTION: SET HANDLE ROTATE VISIBLE + that.setHandleRotateVisible = function(isVisible) { + that.setHandleRotatePitchVisible(isVisible); + that.setHandleRotateYawVisible(isVisible); + that.setHandleRotateRollVisible(isVisible); + }; + + that.setHandleRotatePitchVisible = function(isVisible) { + Overlays.editOverlay(handleRotatePitchRing, { visible: isVisible }); + }; + + that.setHandleRotateYawVisible = function(isVisible) { + Overlays.editOverlay(handleRotateYawRing, { visible: isVisible }); + }; + + that.setHandleRotateRollVisible = function(isVisible) { + Overlays.editOverlay(handleRotateRollRing, { visible: isVisible }); + }; + + // FUNCTION: SET HANDLE STRETCH VISIBLE + that.setHandleStretchVisible = function(isVisible) { + that.setHandleStretchXVisible(isVisible); + that.setHandleStretchYVisible(isVisible); + that.setHandleStretchZVisible(isVisible); + }; + + that.setHandleStretchXVisible = function(isVisible) { + Overlays.editOverlay(handleStretchXSphere, { visible: isVisible }); + }; + + that.setHandleStretchYVisible = function(isVisible) { + Overlays.editOverlay(handleStretchYSphere, { visible: isVisible }); + }; + + that.setHandleStretchZVisible = function(isVisible) { + Overlays.editOverlay(handleStretchZSphere, { visible: isVisible }); + }; + + // FUNCTION: SET HANDLE SCALE VISIBLE + that.setHandleScaleVisible = function(isVisible) { + that.setHandleScaleCubeVisible(isVisible); + that.setHandleScaleEdgeVisible(isVisible); + }; + + that.setHandleScaleCubeVisible = function(isVisible) { + Overlays.editOverlay(handleScaleLBNCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleRBNCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleLBFCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleRBFCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleLTNCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleRTNCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleLTFCube, { visible: isVisible }); + Overlays.editOverlay(handleScaleRTFCube, { visible: isVisible }); + }; + + that.setHandleScaleEdgeVisible = function(isVisible) { + Overlays.editOverlay(handleScaleTREdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleTLEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleTFEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleTNEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleBREdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleBLEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleBFEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleBNEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleNREdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleNLEdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleFREdge, { visible: isVisible }); + Overlays.editOverlay(handleScaleFLEdge, { visible: isVisible }); + }; + + // FUNCTION: SET HANDLE CLONER VISIBLE + that.setHandleClonerVisible = function(isVisible) { + Overlays.editOverlay(handleCloner, { visible: isVisible }); + }; + + // TOOL DEFINITION: TRANSLATE XZ TOOL + var initialXZPick = null; + var isConstrained = false; + var constrainMajorOnly = false; + var startPosition = null; + var duplicatedEntityIDs = null; + var translateXZTool = addHandleTool(selectionBox, { + mode: 'TRANSLATE_XZ', + pickPlanePosition: { x: 0, y: 0, z: 0 }, + greatestDimension: 0.0, + startingDistance: 0.0, + startingElevation: 0.0, + onBegin: function(event, pickRay, pickResult, doClone) { + var wantDebug = false; + if (wantDebug) { + print("================== TRANSLATE_XZ(Beg) -> ======================="); + Vec3.print(" pickRay", pickRay); + Vec3.print(" pickRay.origin", pickRay.origin); + Vec3.print(" pickResult.intersection", pickResult.intersection); + } + + SelectionManager.saveProperties(); + that.resetPreviousHandleColor(); + + that.setHandleTranslateVisible(false); + that.setHandleRotateVisible(false); + that.setHandleScaleCubeVisible(false); + that.setHandleStretchVisible(false); + that.setHandleClonerVisible(false); + + startPosition = SelectionManager.worldPosition; + + translateXZTool.pickPlanePosition = pickResult.intersection; + translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); + translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); + translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); + if (wantDebug) { + print(" longest dimension: " + translateXZTool.greatestDimension); + print(" starting distance: " + translateXZTool.startingDistance); + print(" starting elevation: " + translateXZTool.startingElevation); + } + + initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { + x: 0, + y: 1, + z: 0 + }); + + // Duplicate entities if alt is pressed. This will make a + // copy of the selected entities and move the _original_ entities, not + // the new ones. + if (event.isAlt || doClone) { + duplicatedEntityIDs = []; + for (var otherEntityID in SelectionManager.savedProperties) { + var properties = SelectionManager.savedProperties[otherEntityID]; + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties + }); + } + } + } else { + duplicatedEntityIDs = null; + } + + isConstrained = false; + if (wantDebug) { + print("================== TRANSLATE_XZ(End) <- ======================="); + } + }, + onEnd: function(event, reason) { + pushCommandForSelections(duplicatedEntityIDs); + }, + elevation: function(origin, intersection) { + return (origin.y - intersection.y) / Vec3.distance(origin, intersection); + }, + onMove: function(event) { + var wantDebug = false; + pickRay = generalComputePickRay(event.x, event.y); + + var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { + x: 0, + y: 1, + z: 0 + }); + + // If the pick ray doesn't hit the pick plane in this direction, do nothing. + // this will happen when someone drags across the horizon from the side they started on. + if (!pick) { + if (wantDebug) { + print(" "+ translateXZTool.mode + "Pick ray does not intersect XZ plane."); + } + + // EARLY EXIT--(Invalid ray detected.) + return; + } + + var vector = Vec3.subtract(pick, initialXZPick); + + // If the mouse is too close to the horizon of the pick plane, stop moving + var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it + var elevation = translateXZTool.elevation(pickRay.origin, pick); + if (wantDebug) { + print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); + } + if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || + (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { + if (wantDebug) { + print(" "+ translateXZTool.mode + " - too close to horizon!"); + } + + // EARLY EXIT--(Don't proceed past the reached limit.) + return; + } + + // If the angular size of the object is too small, stop moving + var MIN_ANGULAR_SIZE = 0.01; // Radians + if (translateXZTool.greatestDimension > 0) { + var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); + if (wantDebug) { + print("Angular size = " + angularSize); + } + if (angularSize < MIN_ANGULAR_SIZE) { + return; + } + } + + // If shifted, constrain to one axis + if (event.isShifted) { + if (Math.abs(vector.x) > Math.abs(vector.z)) { + vector.z = 0; + } else { + vector.x = 0; + } + if (!isConstrained) { + isConstrained = true; + } + } else { + if (isConstrained) { + isConstrained = false; + } + } + + constrainMajorOnly = event.isControl; + var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, SelectionManager.worldDimensions)); + vector = Vec3.subtract( + grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), + cornerPosition); + + + for (var i = 0; i < SelectionManager.selections.length; i++) { + var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; + if (!properties) { + continue; + } + var newPosition = Vec3.sum(properties.position, { + x: vector.x, + y: 0, + z: vector.z + }); + Entities.editEntity(SelectionManager.selections[i], { + position: newPosition + }); + + if (wantDebug) { + print("translateXZ... "); + Vec3.print(" vector:", vector); + Vec3.print(" newPosition:", properties.position); + Vec3.print(" newPosition:", newPosition); + } + } + + SelectionManager._update(); + } + }); + + // TOOL DEFINITION: HANDLE TRANSLATE TOOL + function addHandleTranslateTool(overlay, mode, direction) { var pickNormal = null; var lastPick = null; var projectionVector = null; - addGrabberTool(overlay, { + addHandleTool(overlay, { mode: mode, onBegin: function(event, pickRay, pickResult) { if (direction === TRANSLATE_DIRECTION.X) { @@ -665,13 +1622,13 @@ SelectionDisplay = (function() { SelectionManager.saveProperties(); that.resetPreviousHandleColor(); - that.setGrabberTranslateXVisible(direction === TRANSLATE_DIRECTION.X); - that.setGrabberTranslateYVisible(direction === TRANSLATE_DIRECTION.Y); - that.setGrabberTranslateZVisible(direction === TRANSLATE_DIRECTION.Z); - that.setGrabberRotateVisible(false); - that.setGrabberStretchVisible(false); - that.setGrabberScaleVisible(false); - that.setGrabberClonerVisible(false); + that.setHandleTranslateXVisible(direction === TRANSLATE_DIRECTION.X); + that.setHandleTranslateYVisible(direction === TRANSLATE_DIRECTION.Y); + that.setHandleTranslateZVisible(direction === TRANSLATE_DIRECTION.Z); + that.setHandleRotateVisible(false); + that.setHandleStretchVisible(false); + that.setHandleScaleCubeVisible(false); + that.setHandleClonerVisible(false); // Duplicate entities if alt is pressed. This will make a // copy of the selected entities and move the _original_ entities, not @@ -747,7 +1704,8 @@ SelectionDisplay = (function() { }; }; - function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, scaleGrabber) { + // TOOL DEFINITION: HANDLE STRETCH TOOL + function makeStretchTool(stretchMode, directionEnum, directionVec, pivot, offset, stretchPanel, scaleHandle) { var directionFor3DStretch = directionVec; var distanceFor3DStretch = 0; var DISTANCE_INFLUENCE_THRESHOLD = 1.2; @@ -931,13 +1889,13 @@ SelectionDisplay = (function() { distanceFor3DStretch = Vec3.length(Vec3.subtract(pickRayPosition3D, pickRay.origin)); } - that.setGrabberTranslateVisible(false); - that.setGrabberRotateVisible(false); - that.setGrabberScaleVisible(true); - that.setGrabberStretchXVisible(directionEnum === STRETCH_DIRECTION.X); - that.setGrabberStretchYVisible(directionEnum === STRETCH_DIRECTION.Y); - that.setGrabberStretchZVisible(directionEnum === STRETCH_DIRECTION.Z); - that.setGrabberClonerVisible(false); + that.setHandleTranslateVisible(false); + that.setHandleRotateVisible(false); + that.setHandleScaleCubeVisible(true); + that.setHandleStretchXVisible(directionEnum === STRETCH_DIRECTION.X); + that.setHandleStretchYVisible(directionEnum === STRETCH_DIRECTION.Y); + that.setHandleStretchZVisible(directionEnum === STRETCH_DIRECTION.Z); + that.setHandleClonerVisible(false); SelectionManager.saveProperties(); that.resetPreviousHandleColor(); @@ -945,8 +1903,8 @@ SelectionDisplay = (function() { if (stretchPanel != null) { Overlays.editOverlay(stretchPanel, { visible: true }); } - if (scaleGrabber != null) { - Overlays.editOverlay(scaleGrabber, { color: GRABBER_SCALE_CUBE_SELECTED_COLOR }); + if (scaleHandle != null) { + Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE_SELECTED }); } }; @@ -954,8 +1912,8 @@ SelectionDisplay = (function() { if (stretchPanel != null) { Overlays.editOverlay(stretchPanel, { visible: false }); } - if (scaleGrabber != null) { - Overlays.editOverlay(scaleGrabber, { color: GRABBER_SCALE_CUBE_IDLE_COLOR }); + if (scaleHandle != null) { + Overlays.editOverlay(scaleHandle, { color: COLOR_SCALE_CUBE }); } pushCommandForSelections(); }; @@ -1008,7 +1966,6 @@ SelectionDisplay = (function() { vector = Vec3.multiplyQbyV(Quat.inverse(rotation), vector); vector = vec3Mult(mask, vector); - } vector = grid.snapToSpacing(vector); @@ -1016,7 +1973,9 @@ SelectionDisplay = (function() { var changeInDimensions = Vec3.multiply(-1, vec3Mult(localSigns, vector)); if (directionEnum === STRETCH_DIRECTION.ALL) { - changeInDimensions = Vec3.multiply(changeInDimensions, STRETCH_DIRECTION_ALL_FACTOR); + var toCameraDistance = getDistanceToCamera(position); + var dimensionsMultiple = toCameraDistance * STRETCH_DIRECTION_ALL_CAMERA_DISTANCE_MULTIPLE; + changeInDimensions = Vec3.multiply(changeInDimensions, dimensionsMultiple); } var newDimensions; @@ -1083,76 +2042,74 @@ SelectionDisplay = (function() { }; } - function addGrabberStretchTool(overlay, mode, directionEnum) { - var directionVec, pivot, offset, stretchPanel; + function addHandleStretchTool(overlay, mode, directionEnum) { + var directionVec, offset, stretchPanel; if (directionEnum === STRETCH_DIRECTION.X) { - stretchPanel = grabberStretchXPanel; + stretchPanel = handleStretchXPanel; directionVec = { x:-1, y:0, z:0 }; } else if (directionEnum === STRETCH_DIRECTION.Y) { - stretchPanel = grabberStretchYPanel; + stretchPanel = handleStretchYPanel; directionVec = { x:0, y:-1, z:0 }; } else if (directionEnum === STRETCH_DIRECTION.Z) { - stretchPanel = grabberStretchZPanel + stretchPanel = handleStretchZPanel directionVec = { x:0, y:0, z:-1 }; } - pivot = directionVec; offset = Vec3.multiply(directionVec, -1); - var tool = makeStretchTool(mode, directionEnum, directionVec, pivot, offset, stretchPanel, null); - return addGrabberTool(overlay, tool); + var tool = makeStretchTool(mode, directionEnum, directionVec, directionVec, offset, stretchPanel, null); + return addHandleTool(overlay, tool); } - function addGrabberScaleTool(overlay, mode, directionEnum) { - var directionVec, pivot, offset, selectedGrabber; + // TOOL DEFINITION: HANDLE SCALE TOOL + function addHandleScaleTool(overlay, mode, directionEnum) { + var directionVec, offset, selectedHandle; if (directionEnum === SCALE_DIRECTION.LBN) { directionVec = { x:1, y:1, z:1 }; - selectedGrabber = grabberScaleLBNCube; + selectedHandle = handleScaleLBNCube; } else if (directionEnum === SCALE_DIRECTION.RBN) { directionVec = { x:1, y:1, z:-1 }; - selectedGrabber = grabberScaleRBNCube; + selectedHandle = handleScaleRBNCube; } else if (directionEnum === SCALE_DIRECTION.LBF) { directionVec = { x:-1, y:1, z:1 }; - selectedGrabber = grabberScaleLBFCube; + selectedHandle = handleScaleLBFCube; } else if (directionEnum === SCALE_DIRECTION.RBF) { directionVec = { x:-1, y:1, z:-1 }; - selectedGrabber = grabberScaleRBFCube; + selectedHandle = handleScaleRBFCube; } else if (directionEnum === SCALE_DIRECTION.LTN) { directionVec = { x:1, y:-1, z:1 }; - selectedGrabber = grabberScaleLTNCube; + selectedHandle = handleScaleLTNCube; } else if (directionEnum === SCALE_DIRECTION.RTN) { directionVec = { x:1, y:-1, z:-1 }; - selectedGrabber = grabberScaleRTNCube; + selectedHandle = handleScaleRTNCube; } else if (directionEnum === SCALE_DIRECTION.LTF) { directionVec = { x:-1, y:-1, z:1 }; - selectedGrabber = grabberScaleLTFCube; + selectedHandle = handleScaleLTFCube; } else if (directionEnum === SCALE_DIRECTION.RTF) { directionVec = { x:-1, y:-1, z:-1 }; - selectedGrabber = grabberScaleRTFCube; + selectedHandle = handleScaleRTFCube; } - pivot = directionVec; offset = Vec3.multiply(directionVec, -1); - var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVec, pivot, offset, null, selectedGrabber); - return addGrabberTool(overlay, tool); + var tool = makeStretchTool(mode, STRETCH_DIRECTION.ALL, directionVec, directionVec, offset, null, selectedHandle); + return addHandleTool(overlay, tool); } // FUNCTION: UPDATE ROTATION DEGREES OVERLAY function updateRotationDegreesOverlay(angleFromZero, position) { var angle = angleFromZero * (Math.PI / 180); - var cameraPosition = Camera.getPosition(); - var entityToCameraDistance = Vec3.length(Vec3.subtract(cameraPosition, position)); + var toCameraDistance = getDistanceToCamera(position); var overlayProps = { position: position, dimensions: { - x: entityToCameraDistance * ROTATION_DISPLAY_SIZE_X_MULTIPLIER, - y: entityToCameraDistance * ROTATION_DISPLAY_SIZE_Y_MULTIPLIER + x: toCameraDistance * ROTATE_DISPLAY_SIZE_X_MULTIPLIER, + y: toCameraDistance * ROTATE_DISPLAY_SIZE_Y_MULTIPLIER }, - lineHeight: entityToCameraDistance * ROTATION_DISPLAY_LINE_HEIGHT_MULTIPLIER, + lineHeight: toCameraDistance * ROTATE_DISPLAY_LINE_HEIGHT_MULTIPLIER, text: normalizeDegrees(-angleFromZero) + "°" }; Overlays.editOverlay(rotationDegreesDisplay, overlayProps); } // FUNCTION DEF: updateSelectionsRotation - // Helper func used by rotation grabber tools + // Helper func used by rotation handle tools function updateSelectionsRotation(rotationChange) { if (!rotationChange) { print("ERROR: entitySelectionTool.updateSelectionsRotation - Invalid arg specified!!"); @@ -1173,61 +2130,76 @@ SelectionDisplay = (function() { rotation: Quat.multiply(rotationChange, initialProperties.rotation) }; + Quat.print("OldRotation ", initialProperties.rotation); + Quat.print("NewRotation ", newProperties.rotation); + if (reposition) { var dPos = Vec3.subtract(initialProperties.position, SelectionManager.worldPosition); + Vec3.print("SelectionManager.worldPosition ", SelectionManager.worldPosition); + Vec3.print("initialProperties.position ", initialProperties.position); + Vec3.print("dPos 1 ", dPos); dPos = Vec3.multiplyQbyV(rotationChange, dPos); + Vec3.print("dPos 2 ", dPos); newProperties.position = Vec3.sum(SelectionManager.worldPosition, dPos); + Vec3.print("newProperties.position ", newProperties.position); } Entities.editEntity(entityID, newProperties); } } - function addGrabberRotateTool(overlay, mode, direction) { - var selectedGrabber = null; + // TOOL DEFINITION: HANDLE ROTATION TOOL + function addHandleRotateTool(overlay, mode, direction) { + var selectedHandle = null; var worldRotation = null; - addGrabberTool(overlay, { + var rotationCenter = null; + addHandleTool(overlay, { mode: mode, onBegin: function(event, pickRay, pickResult) { + var wantDebug = false; + if (wantDebug) { + print("================== " + getMode() + "(addHandleRotateTool onBegin) -> ======================="); + } + SelectionManager.saveProperties(); that.resetPreviousHandleColor(); - that.setGrabberTranslateVisible(false); - that.setGrabberRotatePitchVisible(direction === ROTATE_DIRECTION.PITCH); - that.setGrabberRotateYawVisible(direction === ROTATE_DIRECTION.YAW); - that.setGrabberRotateRollVisible(direction === ROTATE_DIRECTION.ROLL); - that.setGrabberStretchVisible(false); - that.setGrabberScaleVisible(false); - that.setGrabberClonerVisible(false); + that.setHandleTranslateVisible(false); + that.setHandleRotatePitchVisible(direction === ROTATE_DIRECTION.PITCH); + that.setHandleRotateYawVisible(direction === ROTATE_DIRECTION.YAW); + that.setHandleRotateRollVisible(direction === ROTATE_DIRECTION.ROLL); + that.setHandleStretchVisible(false); + that.setHandleScaleCubeVisible(false); + that.setHandleClonerVisible(false); if (direction === ROTATE_DIRECTION.PITCH) { rotationNormal = { x: 1, y: 0, z: 0 }; worldRotation = worldRotationY; - selectedGrabber = grabberRotatePitchRing; + selectedHandle = handleRotatePitchRing; } else if (direction === ROTATE_DIRECTION.YAW) { rotationNormal = { x: 0, y: 1, z: 0 }; worldRotation = worldRotationZ; - selectedGrabber = grabberRotateYawRing; + selectedHandle = handleRotateYawRing; } else if (direction === ROTATE_DIRECTION.ROLL) { rotationNormal = { x: 0, y: 0, z: 1 }; worldRotation = worldRotationX; - selectedGrabber = grabberRotateRollRing; + selectedHandle = handleRotateRollRing; } - Overlays.editOverlay(selectedGrabber, { + Overlays.editOverlay(selectedHandle, { hasTickMarks: true, solid: false, - innerRadius: ROTATION_RING_SELECTED_INNER_RADIUS + innerRadius: ROTATE_RING_SELECTED_INNER_RADIUS }); var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; rotationNormal = Vec3.multiplyQbyV(rotation, rotationNormal); - var rotCenter = SelectionManager.worldPosition; + rotationCenter = SelectionManager.worldPosition; Overlays.editOverlay(rotationDegreesDisplay, { visible: true }); - Overlays.editOverlay(grabberRotateCurrentRing, { - position: rotCenter, + Overlays.editOverlay(handleRotateCurrentRing, { + position: rotationCenter, rotation: worldRotation, startAt: 0, endAt: 0, @@ -1236,47 +2208,78 @@ SelectionDisplay = (function() { // editOverlays may not have committed rotation changes. // Compute zero position based on where the overlay will be eventually. - var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); + var result = rayPlaneIntersection(pickRay, rotationCenter, rotationNormal); // In case of a parallel ray, this will be null, which will cause early-out // in the onMove helper. - rotZero = result; + rotationZero = result; - var rotCenterToZero = Vec3.subtract(rotZero, rotCenter); - var rotCenterToZeroLength = Vec3.length(rotCenterToZero); - rotDegreePos = Vec3.sum(rotCenter, Vec3.multiply(Vec3.normalize(rotCenterToZero), rotCenterToZeroLength * 1.75)); - updateRotationDegreesOverlay(0, rotDegreePos); + var rotationCenterToZero = Vec3.subtract(rotationZero, rotationCenter); + var rotationCenterToZeroLength = Vec3.length(rotationCenterToZero); + rotationDegreesPosition = Vec3.sum(rotationCenter, Vec3.multiply(Vec3.normalize(rotationCenterToZero), rotationCenterToZeroLength * 1.75)); + updateRotationDegreesOverlay(0, rotationDegreesPosition); + + if (wantDebug) { + print("================== " + getMode() + "(addHandleRotateTool onBegin) <- ======================="); + } }, onEnd: function(event, reason) { + var wantDebug = false; + if (wantDebug) { + print("================== " + getMode() + "(addHandleRotateTool onEnd) -> ======================="); + } Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); - Overlays.editOverlay(selectedGrabber, { + Overlays.editOverlay(selectedHandle, { hasTickMarks: false, solid: true, - innerRadius: ROTATION_RING_IDLE_INNER_RADIUS + innerRadius: ROTATE_RING_IDLE_INNER_RADIUS }); - Overlays.editOverlay(grabberRotateCurrentRing, { visible: false }); + Overlays.editOverlay(handleRotateCurrentRing, { visible: false }); pushCommandForSelections(); + if (wantDebug) { + print("================== " + getMode() + "(addHandleRotateTool onEnd) <- ======================="); + } }, onMove: function(event) { - if (!rotZero) { - print("ERROR: entitySelectionTool.handleRotationHandleOnMove - Invalid RotationZero Specified (missed rotation target plane?)"); - + if (!rotationZero) { + print("ERROR: entitySelectionTool.addHandleRotateTool.onMove - Invalid RotationZero Specified (missed rotation target plane?)"); + // EARLY EXIT return; } + + var wantDebug = true; + if (wantDebug) { + print("================== "+ getMode() + "(addHandleRotateTool onMove) -> ======================="); + Vec3.print(" rotationZero: ", rotationZero); + } + var pickRay = generalComputePickRay(event.x, event.y); - var rotCenter = SelectionManager.worldPosition; - var result = rayPlaneIntersection(pickRay, rotCenter, rotationNormal); + var result = rayPlaneIntersection(pickRay, rotationCenter, rotationNormal); if (result) { - var centerToZero = Vec3.subtract(rotZero, rotCenter); - var centerToIntersect = Vec3.subtract(result, rotCenter); + var centerToZero = Vec3.subtract(rotationZero, rotationCenter); + var centerToIntersect = Vec3.subtract(result, rotationCenter); + + if (wantDebug) { + Vec3.print(" RotationNormal: ", rotationNormal); + Vec3.print(" rotationZero: ", rotationZero); + Vec3.print(" rotationCenter: ", rotationCenter); + Vec3.print(" intersect: ", result); + Vec3.print(" centerToZero: ", centerToZero); + Vec3.print(" centerToIntersect: ", centerToIntersect); + } + // Note: orientedAngle which wants normalized centerToZero and centerToIntersect // handles that internally, so it's to pass unnormalized vectors here. var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal); - var snapAngle = ctrlPressed ? ROTATION_CTRL_SNAP_ANGLE : ROTATION_DEFAULT_SNAP_ANGLE; + var snapAngle = ctrlPressed ? ROTATE_CTRL_SNAP_ANGLE : ROTATE_DEFAULT_SNAP_ANGLE; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; var rotChange = Quat.angleAxis(angleFromZero, rotationNormal); + if (wantDebug) { + Quat.print(" rotChange: ", rotChange) + print(" angleFromZero: ", angleFromZero); + } updateSelectionsRotation(rotChange); - updateRotationDegreesOverlay(-angleFromZero, rotDegreePos); + updateRotationDegreesOverlay(-angleFromZero, rotationDegreesPosition); var startAtCurrent = 0; var endAtCurrent = angleFromZero; @@ -1284,692 +2287,26 @@ SelectionDisplay = (function() { startAtCurrent = 360 + angleFromZero; endAtCurrent = 360; } - Overlays.editOverlay(grabberRotateCurrentRing, { + Overlays.editOverlay(handleRotateCurrentRing, { startAt: startAtCurrent, endAt: endAtCurrent }); + // not sure why but this seems to be needed to fix an reverse rotation for yaw ring only if (direction === ROTATE_DIRECTION.YAW) { - Overlays.editOverlay(grabberRotateCurrentRing, { rotation: worldRotationZ }); + Overlays.editOverlay(handleRotateCurrentRing, { rotation: worldRotationZ }); } + } + if (wantDebug) { + print("================== "+ getMode() + "(addHandleRotateTool onMove) <- ======================="); } } }); } - // @param: toolHandle: The overlayID associated with the tool - // that correlates to the tool you wish to query. - // @note: If toolHandle is null or undefined then activeTool - // will be checked against those values as opposed to - // the tool registered under toolHandle. Null & Undefined - // are treated as separate values. - // @return: bool - Indicates if the activeTool is that queried. - function isActiveTool(toolHandle) { - if (!toolHandle) { - // Allow isActiveTool(null) and similar to return true if there's - // no active tool - return (activeTool === toolHandle); - } - - if (!grabberTools.hasOwnProperty(toolHandle)) { - print("WARNING: entitySelectionTool.isActiveTool - Encountered unknown grabberToolHandle: " + toolHandle + ". Tools should be registered via addGrabberTool."); - // EARLY EXIT - return false; - } - - return (activeTool === grabberTools[ toolHandle ]); - } - - // @return string - The mode of the currently active tool; - // otherwise, "UNKNOWN" if there's no active tool. - function getMode() { - return (activeTool ? activeTool.mode : "UNKNOWN"); - } - - that.cleanup = function() { - for (var i = 0; i < allOverlays.length; i++) { - Overlays.deleteOverlay(allOverlays[i]); - } - }; - - that.highlightSelectable = function(entityID) { - }; - - that.unhighlightSelectable = function(entityID) { - }; - - that.select = function(entityID, event) { - var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - - lastCameraPosition = Camera.getPosition(); - lastCameraOrientation = Camera.getOrientation(); - - if (event !== false) { - pickRay = generalComputePickRay(event.x, event.y); - - var wantDebug = false; - if (wantDebug) { - print("select() with EVENT...... "); - print(" event.y:" + event.y); - Vec3.print(" current position:", properties.position); - } - } - - that.updateGrabbers(); - }; - - // FUNCTION: SET SPACE MODE - that.setSpaceMode = function(newSpaceMode) { - var wantDebug = false; - if (wantDebug) { - print("======> SetSpaceMode called. ========"); - } - - if (spaceMode !== newSpaceMode) { - if (wantDebug) { - print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode); - } - spaceMode = newSpaceMode; - that.updateGrabbers(); - } else if (wantDebug) { - print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " + spaceMode + " DesiredMode: " + newSpaceMode); - } - if (wantDebug) { - print("====== SetSpaceMode called. <========"); - } - }; - - // FUNCTION: UPDATE GRABBERS - that.updateGrabbers = function() { - var wantDebug = false; - if (wantDebug) { - print("======> Update Grabbers ======="); - print(" Selections Count: " + SelectionManager.selections.length); - print(" SpaceMode: " + spaceMode); - print(" DisplayMode: " + getMode()); - } - - if (SelectionManager.selections.length === 0) { - that.setOverlaysVisible(false); - return; - } - - if (SelectionManager.hasSelection()) { - var position = SelectionManager.worldPosition; - var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation; - var dimensions = spaceMode === SPACE_LOCAL ? SelectionManager.localDimensions : SelectionManager.worldDimensions; - var rotationInverse = Quat.inverse(rotation); - - var cameraPosition = Camera.getPosition(); - var entityToCameraDistance = Vec3.length(Vec3.subtract(cameraPosition, position)); - - var localRotationX = Quat.fromPitchYawRollDegrees(0, 0, -90); - rotationX = Quat.multiply(rotation, localRotationX); - worldRotationX = rotationX; - var localRotationY = Quat.fromPitchYawRollDegrees(0, 90, 0); - rotationY = Quat.multiply(rotation, localRotationY); - worldRotationY = rotationY; - var localRotationZ = Quat.fromPitchYawRollDegrees(90, 0, 0); - rotationZ = Quat.multiply(rotation, localRotationZ); - worldRotationZ = rotationZ; - - var arrowCylinderDimension = entityToCameraDistance * GRABBER_TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE; - var arrowCylinderDimensions = { x:arrowCylinderDimension, y:arrowCylinderDimension * GRABBER_TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE, z:arrowCylinderDimension }; - var arrowConeDimension = entityToCameraDistance * GRABBER_TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE; - var arrowConeDimensions = { x:arrowConeDimension, y:arrowConeDimension, z:arrowConeDimension }; - var cylinderXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance, y:0, z:0 })); - Overlays.editOverlay(grabberTranslateXCylinder, { - position: cylinderXPos, - rotation: rotationX, - dimensions: arrowCylinderDimensions - }); - var cylinderXDiff = Vec3.subtract(cylinderXPos, position); - var coneXPos = Vec3.sum(cylinderXPos, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowCylinderDimensions.y * 0.83)); - Overlays.editOverlay(grabberTranslateXCone, { - position: coneXPos, - rotation: rotationX, - dimensions: arrowConeDimensions - }); - var cylinderYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance, z:0 })); - Overlays.editOverlay(grabberTranslateYCylinder, { - position: cylinderYPos, - rotation: rotationY, - dimensions: arrowCylinderDimensions - }); - var cylinderYDiff = Vec3.subtract(cylinderYPos, position); - var coneYPos = Vec3.sum(cylinderYPos, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowCylinderDimensions.y * 0.83)); - Overlays.editOverlay(grabberTranslateYCone, { - position: coneYPos, - rotation: rotationY, - dimensions: arrowConeDimensions - }); - var cylinderZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:GRABBER_TRANSLATE_ARROW_CYLINDER_OFFSET * entityToCameraDistance })); - Overlays.editOverlay(grabberTranslateZCylinder, { - position: cylinderZPos, - rotation: rotationZ, - dimensions: arrowCylinderDimensions - }); - var cylinderZDiff = Vec3.subtract(cylinderZPos, position); - var coneZPos = Vec3.sum(cylinderZPos, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowCylinderDimensions.y * 0.83)); - Overlays.editOverlay(grabberTranslateZCone, { - position: coneZPos, - rotation: rotationZ, - dimensions: arrowConeDimensions - }); - - var grabberScaleCubeOffsetX = GRABBER_SCALE_CUBE_OFFSET * dimensions.x; - var grabberScaleCubeOffsetY = GRABBER_SCALE_CUBE_OFFSET * dimensions.y; - var grabberScaleCubeOffsetZ = GRABBER_SCALE_CUBE_OFFSET * dimensions.z; - var scaleDimension = entityToCameraDistance * GRABBER_SCALE_CUBE_CAMERA_DISTANCE_MULTIPLE; - var scaleDimensions = { x:scaleDimension, y:scaleDimension, z:scaleDimension }; - var grabberScaleLBNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleLBNCube, { - position: grabberScaleLBNCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleRBNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleRBNCube, { - position: grabberScaleRBNCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleLBFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleLBFCube, { - position: grabberScaleLBFCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleRBFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:-grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleRBFCube, { - position: grabberScaleRBFCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleLTNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleLTNCube, { - position: grabberScaleLTNCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleRTNCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:-grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleRTNCube, { - position: grabberScaleRTNCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleLTFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:-grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleLTFCube, { - position: grabberScaleLTFCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - var grabberScaleRTFCubePos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:grabberScaleCubeOffsetX, y:grabberScaleCubeOffsetY, z:grabberScaleCubeOffsetZ })); - Overlays.editOverlay(grabberScaleRTFCube, { - position: grabberScaleRTFCubePos, - rotation: rotation, - dimensions: scaleDimensions - }); - - Overlays.editOverlay(grabberScaleTREdge, { start: grabberScaleRTNCubePos, end: grabberScaleRTFCubePos }); - Overlays.editOverlay(grabberScaleTLEdge, { start: grabberScaleLTNCubePos, end: grabberScaleLTFCubePos }); - Overlays.editOverlay(grabberScaleTFEdge, { start: grabberScaleLTFCubePos, end: grabberScaleRTFCubePos }); - Overlays.editOverlay(grabberScaleTNEdge, { start: grabberScaleLTNCubePos, end: grabberScaleRTNCubePos }); - Overlays.editOverlay(grabberScaleBREdge, { start: grabberScaleRBNCubePos, end: grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleBLEdge, { start: grabberScaleLBNCubePos, end: grabberScaleLBFCubePos }); - Overlays.editOverlay(grabberScaleBFEdge, { start: grabberScaleLBFCubePos, end: grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleBNEdge, { start: grabberScaleLBNCubePos, end: grabberScaleRBNCubePos }); - Overlays.editOverlay(grabberScaleNREdge, { start: grabberScaleRTNCubePos, end: grabberScaleRBNCubePos }); - Overlays.editOverlay(grabberScaleNLEdge, { start: grabberScaleLTNCubePos, end: grabberScaleLBNCubePos }); - Overlays.editOverlay(grabberScaleFREdge, { start: grabberScaleRTFCubePos, end: grabberScaleRBFCubePos }); - Overlays.editOverlay(grabberScaleFLEdge, { start: grabberScaleLTFCubePos, end: grabberScaleLBFCubePos }); - - var stretchSphereDimension = entityToCameraDistance * GRABBER_STRETCH_SPHERE_CAMERA_DISTANCE_MULTIPLE; - var stretchSphereDimensions = { x:stretchSphereDimension, y:stretchSphereDimension, z:stretchSphereDimension }; - var stretchXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance, y:0, z:0 })); - Overlays.editOverlay(grabberStretchXSphere, { - position: stretchXPos, - dimensions: stretchSphereDimensions - }); - var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleLTFCubePos); - var grabberScaleRBFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRBFCubePos); - var stretchPanelXDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRBFCubePosRot); - var tempY = Math.abs(stretchPanelXDimensions.y); - stretchPanelXDimensions.x = 0.01; - stretchPanelXDimensions.y = Math.abs(stretchPanelXDimensions.z); - stretchPanelXDimensions.z = tempY; - var stretchPanelXPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:dimensions.x / 2, y:0, z:0 })); - Overlays.editOverlay(grabberStretchXPanel, { - position: stretchPanelXPos, - rotation: rotationZ, - dimensions: stretchPanelXDimensions - }); - var stretchYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance, z:0 })); - Overlays.editOverlay(grabberStretchYSphere, { - position: stretchYPos, - dimensions: stretchSphereDimensions - }); - var grabberScaleLTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleLTNCubePos); - var grabberScaleRTNCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRTFCubePos); - var stretchPanelYDimensions = Vec3.subtract(grabberScaleLTFCubePosRot, grabberScaleRTNCubePosRot); - var tempX = Math.abs(stretchPanelYDimensions.x); - stretchPanelYDimensions.x = Math.abs(stretchPanelYDimensions.z); - stretchPanelYDimensions.y = 0.01; - stretchPanelYDimensions.z = tempX; - var stretchPanelYPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:dimensions.y / 2, z:0 })); - Overlays.editOverlay(grabberStretchYPanel, { - position: stretchPanelYPos, - rotation: rotationY, - dimensions: stretchPanelYDimensions - }); - var stretchZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:GRABBER_STRETCH_SPHERE_OFFSET * entityToCameraDistance })); - Overlays.editOverlay(grabberStretchZSphere, { - position: stretchZPos, - dimensions: stretchSphereDimensions - }); - var grabberScaleRTFCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRTFCubePos); - var grabberScaleRBNCubePosRot = Vec3.multiplyQbyV(rotationInverse, grabberScaleRBNCubePos); - var stretchPanelZDimensions = Vec3.subtract(grabberScaleRTFCubePosRot, grabberScaleRBNCubePosRot); - var tempX = Math.abs(stretchPanelZDimensions.x); - stretchPanelZDimensions.x = Math.abs(stretchPanelZDimensions.y); - stretchPanelZDimensions.y = tempX; - stretchPanelZDimensions.z = 0.01; - var stretchPanelZPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, { x:0, y:0, z:dimensions.z / 2 })); - Overlays.editOverlay(grabberStretchZPanel, { - position: stretchPanelZPos, - rotation: rotationX, - dimensions: stretchPanelZDimensions - }); - - var rotateDimension = entityToCameraDistance * GRABBER_ROTATE_RINGS_CAMERA_DISTANCE_MULTIPLE; - var rotateDimensions = { x:rotateDimension, y:rotateDimension, z:rotateDimension }; - if (!isActiveTool(grabberRotatePitchRing)) { - Overlays.editOverlay(grabberRotatePitchRing, { - position: position, - rotation: rotationY, - dimensions: rotateDimensions, - majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE - }); - } - if (!isActiveTool(grabberRotateYawRing)) { - Overlays.editOverlay(grabberRotateYawRing, { - position: position, - rotation: rotationZ, - dimensions: rotateDimensions, - majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE - }); - } - if (!isActiveTool(grabberRotateRollRing)) { - Overlays.editOverlay(grabberRotateRollRing, { - position: position, - rotation: rotationX, - dimensions: rotateDimensions, - majorTickMarksAngle: ROTATION_DEFAULT_TICK_MARKS_ANGLE - }); - } - Overlays.editOverlay(grabberRotateCurrentRing, { dimensions: rotateDimensions }); - that.updateActiveRotateRing(); - - var inModeRotate = isActiveTool(grabberRotatePitchRing) || isActiveTool(grabberRotateYawRing) || isActiveTool(grabberRotateRollRing); - var inModeTranslate = isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder) || - isActiveTool(grabberTranslateYCone) || isActiveTool(grabberTranslateYCylinder) || - isActiveTool(grabberTranslateZCone) || isActiveTool(grabberTranslateZCylinder) || - isActiveTool(grabberCloner) || isActiveTool(selectionBox); - - Overlays.editOverlay(selectionBox, { - position: position, - rotation: rotation, - dimensions: dimensions, - visible: !inModeRotate - }); - - var grabberClonerOffset = { x:GRABBER_CLONER_OFFSET.x * dimensions.x, y:GRABBER_CLONER_OFFSET.y * dimensions.y, z:GRABBER_CLONER_OFFSET.z * dimensions.z }; - var grabberClonerPos = Vec3.sum(position, Vec3.multiplyQbyV(rotation, grabberClonerOffset)); - Overlays.editOverlay(grabberCloner, { - position: grabberClonerPos, - rotation: rotation, - dimensions: scaleDimensions - }); - } - - that.setGrabberTranslateXVisible(!activeTool || isActiveTool(grabberTranslateXCone) || isActiveTool(grabberTranslateXCylinder)); - that.setGrabberTranslateYVisible(!activeTool || isActiveTool(grabberTranslateYCone) || isActiveTool(grabberTranslateYCylinder)); - that.setGrabberTranslateZVisible(!activeTool || isActiveTool(grabberTranslateZCone) || isActiveTool(grabberTranslateZCylinder)); - that.setGrabberRotatePitchVisible(!activeTool || isActiveTool(grabberRotatePitchRing)); - that.setGrabberRotateYawVisible(!activeTool || isActiveTool(grabberRotateYawRing)); - that.setGrabberRotateRollVisible(!activeTool || isActiveTool(grabberRotateRollRing)); - that.setGrabberStretchXVisible(!activeTool || isActiveTool(grabberStretchXSphere)); - that.setGrabberStretchYVisible(!activeTool || isActiveTool(grabberStretchYSphere)); - that.setGrabberStretchZVisible(!activeTool || isActiveTool(grabberStretchZSphere)); - that.setGrabberScaleVisible(!activeTool || isActiveTool(grabberScaleLBNCube) || isActiveTool(grabberScaleRBNCube) || isActiveTool(grabberScaleLBFCube) || isActiveTool(grabberScaleRBFCube) - || isActiveTool(grabberScaleLTNCube) || isActiveTool(grabberScaleRTNCube) || isActiveTool(grabberScaleLTFCube) || isActiveTool(grabberScaleRTFCube) - || isActiveTool(grabberStretchXSphere) || isActiveTool(grabberStretchYSphere) || isActiveTool(grabberStretchZSphere)); - //keep cloner always hidden for now since you can hold Alt to clone while dragging to translate - we may bring cloner back for HMD only later - //that.setGrabberClonerVisible(!activeTool || isActiveTool(grabberCloner)); - - if (wantDebug) { - print("====== Update Grabbers <======="); - } - }; - Script.update.connect(that.updateGrabbers); - - that.updateActiveRotateRing = function() { - var activeRotateRing = null; - if (isActiveTool(grabberRotatePitchRing)) { - activeRotateRing = grabberRotatePitchRing; - } else if (isActiveTool(grabberRotateYawRing)) { - activeRotateRing = grabberRotateYawRing; - } else if (isActiveTool(grabberRotateRollRing)) { - activeRotateRing = grabberRotateRollRing; - } - if (activeRotateRing != null) { - var tickMarksAngle = ctrlPressed ? ROTATION_CTRL_SNAP_ANGLE : ROTATION_DEFAULT_TICK_MARKS_ANGLE; - Overlays.editOverlay(activeRotateRing, { majorTickMarksAngle: tickMarksAngle }); - } - }; - - // FUNCTION: SET OVERLAYS VISIBLE - that.setOverlaysVisible = function(isVisible) { - for (var i = 0; i < allOverlays.length; i++) { - Overlays.editOverlay(allOverlays[i], { visible: isVisible }); - } - }; - - // FUNCTION: SET GRABBER TRANSLATE VISIBLE - that.setGrabberTranslateVisible = function(isVisible) { - that.setGrabberTranslateXVisible(isVisible); - that.setGrabberTranslateYVisible(isVisible); - that.setGrabberTranslateZVisible(isVisible); - }; - - that.setGrabberTranslateXVisible = function(isVisible) { - Overlays.editOverlay(grabberTranslateXCone, { visible: isVisible }); - Overlays.editOverlay(grabberTranslateXCylinder, { visible: isVisible }); - }; - - that.setGrabberTranslateYVisible = function(isVisible) { - Overlays.editOverlay(grabberTranslateYCone, { visible: isVisible }); - Overlays.editOverlay(grabberTranslateYCylinder, { visible: isVisible }); - }; - - that.setGrabberTranslateZVisible = function(isVisible) { - Overlays.editOverlay(grabberTranslateZCone, { visible: isVisible }); - Overlays.editOverlay(grabberTranslateZCylinder, { visible: isVisible }); - }; - - // FUNCTION: SET GRABBER ROTATE VISIBLE - that.setGrabberRotateVisible = function(isVisible) { - that.setGrabberRotatePitchVisible(isVisible); - that.setGrabberRotateYawVisible(isVisible); - that.setGrabberRotateRollVisible(isVisible); - }; - - that.setGrabberRotatePitchVisible = function(isVisible) { - Overlays.editOverlay(grabberRotatePitchRing, { visible: isVisible }); - }; - - that.setGrabberRotateYawVisible = function(isVisible) { - Overlays.editOverlay(grabberRotateYawRing, { visible: isVisible }); - }; - - that.setGrabberRotateRollVisible = function(isVisible) { - Overlays.editOverlay(grabberRotateRollRing, { visible: isVisible }); - }; - - // FUNCTION: SET GRABBER STRETCH VISIBLE - that.setGrabberStretchVisible = function(isVisible) { - that.setGrabberStretchXVisible(isVisible); - that.setGrabberStretchYVisible(isVisible); - that.setGrabberStretchZVisible(isVisible); - }; - - that.setGrabberStretchXVisible = function(isVisible) { - Overlays.editOverlay(grabberStretchXSphere, { visible: isVisible }); - }; - - that.setGrabberStretchYVisible = function(isVisible) { - Overlays.editOverlay(grabberStretchYSphere, { visible: isVisible }); - }; - - that.setGrabberStretchZVisible = function(isVisible) { - Overlays.editOverlay(grabberStretchZSphere, { visible: isVisible }); - }; - - // FUNCTION: SET GRABBER SCALE VISIBLE - that.setGrabberScaleVisible = function(isVisible) { - Overlays.editOverlay(grabberScaleLBNCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleRBNCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleLBFCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleRBFCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleLTNCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleRTNCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleLTFCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleRTFCube, { visible: isVisible }); - Overlays.editOverlay(grabberScaleTREdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleTLEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleTFEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleTNEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleBREdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleBLEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleBFEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleBNEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleNREdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleNLEdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleFREdge, { visible: isVisible }); - Overlays.editOverlay(grabberScaleFLEdge, { visible: isVisible }); - }; - - // FUNCTION: SET GRABBER CLONER VISIBLE - that.setGrabberClonerVisible = function(isVisible) { - Overlays.editOverlay(grabberCloner, { visible: isVisible }); - }; - - var initialXZPick = null; - var isConstrained = false; - var constrainMajorOnly = false; - var startPosition = null; - var duplicatedEntityIDs = null; - - // TOOL DEFINITION: TRANSLATE XZ TOOL - var translateXZTool = addGrabberTool(selectionBox, { - mode: 'TRANSLATE_XZ', - pickPlanePosition: { x: 0, y: 0, z: 0 }, - greatestDimension: 0.0, - startingDistance: 0.0, - startingElevation: 0.0, - onBegin: function(event, pickRay, pickResult, doClone) { - var wantDebug = false; - if (wantDebug) { - print("================== TRANSLATE_XZ(Beg) -> ======================="); - Vec3.print(" pickRay", pickRay); - Vec3.print(" pickRay.origin", pickRay.origin); - Vec3.print(" pickResult.intersection", pickResult.intersection); - } - - SelectionManager.saveProperties(); - that.resetPreviousHandleColor(); - - that.setGrabberTranslateVisible(false); - that.setGrabberRotateVisible(false); - that.setGrabberScaleVisible(false); - that.setGrabberStretchVisible(false); - that.setGrabberClonerVisible(false); - - startPosition = SelectionManager.worldPosition; - - translateXZTool.pickPlanePosition = pickResult.intersection; - translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); - translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); - translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); - if (wantDebug) { - print(" longest dimension: " + translateXZTool.greatestDimension); - print(" starting distance: " + translateXZTool.startingDistance); - print(" starting elevation: " + translateXZTool.startingElevation); - } - - initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, { - x: 0, - y: 1, - z: 0 - }); - - // Duplicate entities if alt is pressed. This will make a - // copy of the selected entities and move the _original_ entities, not - // the new ones. - if (event.isAlt || doClone) { - duplicatedEntityIDs = []; - for (var otherEntityID in SelectionManager.savedProperties) { - var properties = SelectionManager.savedProperties[otherEntityID]; - if (!properties.locked) { - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties - }); - } - } - } else { - duplicatedEntityIDs = null; - } - - isConstrained = false; - if (wantDebug) { - print("================== TRANSLATE_XZ(End) <- ======================="); - } - }, - onEnd: function(event, reason) { - pushCommandForSelections(duplicatedEntityIDs); - }, - elevation: function(origin, intersection) { - return (origin.y - intersection.y) / Vec3.distance(origin, intersection); - }, - onMove: function(event) { - var wantDebug = false; - pickRay = generalComputePickRay(event.x, event.y); - - var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, { - x: 0, - y: 1, - z: 0 - }); - - // If the pick ray doesn't hit the pick plane in this direction, do nothing. - // this will happen when someone drags across the horizon from the side they started on. - if (!pick) { - if (wantDebug) { - print(" "+ translateXZTool.mode + "Pick ray does not intersect XZ plane."); - } - - // EARLY EXIT--(Invalid ray detected.) - return; - } - - var vector = Vec3.subtract(pick, initialXZPick); - - // If the mouse is too close to the horizon of the pick plane, stop moving - var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it - var elevation = translateXZTool.elevation(pickRay.origin, pick); - if (wantDebug) { - print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation); - } - if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) || - (translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) { - if (wantDebug) { - print(" "+ translateXZTool.mode + " - too close to horizon!"); - } - - // EARLY EXIT--(Don't proceed past the reached limit.) - return; - } - - // If the angular size of the object is too small, stop moving - var MIN_ANGULAR_SIZE = 0.01; // Radians - if (translateXZTool.greatestDimension > 0) { - var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick)); - if (wantDebug) { - print("Angular size = " + angularSize); - } - if (angularSize < MIN_ANGULAR_SIZE) { - return; - } - } - - // If shifted, constrain to one axis - if (event.isShifted) { - if (Math.abs(vector.x) > Math.abs(vector.z)) { - vector.z = 0; - } else { - vector.x = 0; - } - if (!isConstrained) { - isConstrained = true; - } - } else { - if (isConstrained) { - isConstrained = false; - } - } - - constrainMajorOnly = event.isControl; - var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, SelectionManager.worldDimensions)); - vector = Vec3.subtract( - grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), - cornerPosition); - - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; - if (!properties) { - continue; - } - var newPosition = Vec3.sum(properties.position, { - x: vector.x, - y: 0, - z: vector.z - }); - Entities.editEntity(SelectionManager.selections[i], { - position: newPosition - }); - - if (wantDebug) { - print("translateXZ... "); - Vec3.print(" vector:", vector); - Vec3.print(" newPosition:", properties.position); - Vec3.print(" newPosition:", newPosition); - } - } - - SelectionManager._update(); - } - }); - - addGrabberTranslateTool(grabberTranslateXCone, "TRANSLATE_X", TRANSLATE_DIRECTION.X); - addGrabberTranslateTool(grabberTranslateXCylinder, "TRANSLATE_X", TRANSLATE_DIRECTION.X); - addGrabberTranslateTool(grabberTranslateYCone, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); - addGrabberTranslateTool(grabberTranslateYCylinder, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); - addGrabberTranslateTool(grabberTranslateZCone, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); - addGrabberTranslateTool(grabberTranslateZCylinder, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); - - addGrabberRotateTool(grabberRotatePitchRing, "ROTATE_PITCH", ROTATE_DIRECTION.PITCH); - addGrabberRotateTool(grabberRotateYawRing, "ROTATE_YAW", ROTATE_DIRECTION.YAW); - addGrabberRotateTool(grabberRotateRollRing, "ROTATE_ROLL", ROTATE_DIRECTION.ROLL); - - addGrabberStretchTool(grabberStretchXSphere, "STRETCH_X", STRETCH_DIRECTION.X); - addGrabberStretchTool(grabberStretchYSphere, "STRETCH_Y", STRETCH_DIRECTION.Y); - addGrabberStretchTool(grabberStretchZSphere, "STRETCH_Z", STRETCH_DIRECTION.Z); - - addGrabberScaleTool(grabberScaleLBNCube, "SCALE_LBN", SCALE_DIRECTION.LBN); - addGrabberScaleTool(grabberScaleRBNCube, "SCALE_RBN", SCALE_DIRECTION.RBN); - addGrabberScaleTool(grabberScaleLBFCube, "SCALE_LBF", SCALE_DIRECTION.LBF); - addGrabberScaleTool(grabberScaleRBFCube, "SCALE_RBF", SCALE_DIRECTION.RBF); - addGrabberScaleTool(grabberScaleLTNCube, "SCALE_LTN", SCALE_DIRECTION.LTN); - addGrabberScaleTool(grabberScaleRTNCube, "SCALE_RTN", SCALE_DIRECTION.RTN); - addGrabberScaleTool(grabberScaleLTFCube, "SCALE_LTF", SCALE_DIRECTION.LTF); - addGrabberScaleTool(grabberScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF); - - // GRABBER TOOL: GRABBER CLONER - addGrabberTool(grabberCloner, { + // TOOL DEFINITION: HANDLE CLONER + addHandleTool(handleCloner, { mode: "CLONE", onBegin: function(event, pickRay, pickResult) { var doClone = true; @@ -1988,267 +2325,29 @@ SelectionDisplay = (function() { } }); - // FUNCTION: CHECK MOVE - that.checkMove = function() { - }; + addHandleTranslateTool(handleTranslateXCone, "TRANSLATE_X", TRANSLATE_DIRECTION.X); + addHandleTranslateTool(handleTranslateXCylinder, "TRANSLATE_X", TRANSLATE_DIRECTION.X); + addHandleTranslateTool(handleTranslateYCone, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); + addHandleTranslateTool(handleTranslateYCylinder, "TRANSLATE_Y", TRANSLATE_DIRECTION.Y); + addHandleTranslateTool(handleTranslateZCone, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); + addHandleTranslateTool(handleTranslateZCylinder, "TRANSLATE_Z", TRANSLATE_DIRECTION.Z); - that.checkControllerMove = function() { - if (SelectionManager.hasSelection()) { - var controllerPose = getControllerWorldLocation(activeHand, true); - var hand = (activeHand === Controller.Standard.LeftHand) ? 0 : 1; - if (controllerPose.valid && lastControllerPoses[hand].valid) { - if (!Vec3.equal(controllerPose.position, lastControllerPoses[hand].position) || - !Vec3.equal(controllerPose.rotation, lastControllerPoses[hand].rotation)) { - that.mouseMoveEvent({}); - } - } - lastControllerPoses[hand] = controllerPose; - } - }; + addHandleRotateTool(handleRotatePitchRing, "ROTATE_PITCH", ROTATE_DIRECTION.PITCH); + addHandleRotateTool(handleRotateYawRing, "ROTATE_YAW", ROTATE_DIRECTION.YAW); + addHandleRotateTool(handleRotateRollRing, "ROTATE_ROLL", ROTATE_DIRECTION.ROLL); - // FUNCTION DEF(s): Intersection Check Helpers - function testRayIntersect(queryRay, overlayIncludes, overlayExcludes) { - var wantDebug = false; - if ((queryRay === undefined) || (queryRay === null)) { - if (wantDebug) { - print("testRayIntersect - EARLY EXIT -> queryRay is undefined OR null!"); - } - return null; - } + addHandleStretchTool(handleStretchXSphere, "STRETCH_X", STRETCH_DIRECTION.X); + addHandleStretchTool(handleStretchYSphere, "STRETCH_Y", STRETCH_DIRECTION.Y); + addHandleStretchTool(handleStretchZSphere, "STRETCH_Z", STRETCH_DIRECTION.Z); - var intersectObj = Overlays.findRayIntersection(queryRay, true, overlayIncludes, overlayExcludes); - - if (wantDebug) { - if (!overlayIncludes) { - print("testRayIntersect - no overlayIncludes provided."); - } - if (!overlayExcludes) { - print("testRayIntersect - no overlayExcludes provided."); - } - print("testRayIntersect - Hit: " + intersectObj.intersects); - print(" intersectObj.overlayID:" + intersectObj.overlayID + "[" + overlayNames[intersectObj.overlayID] + "]"); - print(" OverlayName: " + overlayNames[intersectObj.overlayID]); - print(" intersectObj.distance:" + intersectObj.distance); - print(" intersectObj.face:" + intersectObj.face); - Vec3.print(" intersectObj.intersection:", intersectObj.intersection); - } - - return intersectObj; - } - - // FUNCTION: MOUSE PRESS EVENT - that.mousePressEvent = function (event) { - var wantDebug = false; - if (wantDebug) { - print("=============== eST::MousePressEvent BEG ======================="); - } - if (!event.isLeftButton && !that.triggered) { - // EARLY EXIT-(if another mouse button than left is pressed ignore it) - return false; - } - - 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]; - for (var key in grabberTools) { - if (grabberTools.hasOwnProperty(key)) { - interactiveOverlays.push(key); - } - } - - // Start with unknown mode, in case no tool can handle this. - activeTool = null; - - var results = testRayIntersect(pickRay, interactiveOverlays); - if (results.intersects) { - var hitOverlayID = results.overlayID; - if ((hitOverlayID === HMD.tabletID) || (hitOverlayID === HMD.tabletScreenID) || (hitOverlayID === HMD.homeButtonID)) { - // EARLY EXIT-(mouse clicks on the tablet should override the edit affordances) - return false; - } - - entityIconOverlayManager.setIconsSelectable(SelectionManager.selections, true); - - var hitTool = grabberTools[ hitOverlayID ]; - if (hitTool) { - activeTool = hitTool; - if (activeTool.onBegin) { - activeTool.onBegin(event, pickRay, results); - } else { - print("ERROR: entitySelectionTool.mousePressEvent - ActiveTool(" + activeTool.mode + ") missing onBegin"); - } - } else { - print("ERROR: entitySelectionTool.mousePressEvent - Hit unexpected object, check interactiveOverlays"); - }// End_if (hitTool) - }// End_If(results.intersects) - - if (wantDebug) { - print(" DisplayMode: " + getMode()); - print("=============== eST::MousePressEvent END ======================="); - } - - // If mode is known then we successfully handled this; - // otherwise, we're missing a tool. - return activeTool; - }; - - that.resetPreviousHandleColor = function() { - if (previousHandle != null) { - Overlays.editOverlay(previousHandle, { color: previousHandleColor }); - previousHandle = null; - } - if (previousHandleHelper != null) { - Overlays.editOverlay(previousHandleHelper, { color: previousHandleColor }); - previousHandleHelper = null; - } - }; - - that.getHandleHelper = function(overlay) { - if (overlay === grabberTranslateXCone) { - return grabberTranslateXCylinder; - } else if (overlay === grabberTranslateXCylinder) { - return grabberTranslateXCone; - } else if (overlay === grabberTranslateYCone) { - return grabberTranslateYCylinder; - } else if (overlay === grabberTranslateYCylinder) { - return grabberTranslateYCone; - } else if (overlay === grabberTranslateZCone) { - return grabberTranslateZCylinder; - } else if (overlay === grabberTranslateZCylinder) { - return grabberTranslateZCone; - } - }; - - // FUNCTION: MOUSE MOVE EVENT - that.mouseMoveEvent = function(event) { - var wantDebug = false; - if (wantDebug) { - print("=============== eST::MouseMoveEvent BEG ======================="); - } - if (activeTool) { - if (wantDebug) { - print(" Trigger ActiveTool(" + activeTool.mode + ")'s onMove"); - } - activeTool.onMove(event); - - if (wantDebug) { - print(" Trigger SelectionManager::update"); - } - SelectionManager._update(); - - if (wantDebug) { - print("=============== eST::MouseMoveEvent END ======================="); - } - // EARLY EXIT--(Move handled via active tool) - return true; - } - - // if no tool is active, then just look for handles to highlight... - var pickRay = generalComputePickRay(event.x, event.y); - var result = Overlays.findRayIntersection(pickRay); - var pickedColor; - var highlightNeeded = false; - - if (result.intersects) { - switch (result.overlayID) { - case grabberTranslateXCone: - case grabberTranslateXCylinder: - case grabberRotatePitchRing: - case grabberStretchXSphere: - pickedColor = COLOR_RED; - highlightNeeded = true; - break; - case grabberTranslateYCone: - case grabberTranslateYCylinder: - case grabberRotateYawRing: - case grabberStretchYSphere: - pickedColor = COLOR_GREEN; - highlightNeeded = true; - break; - case grabberTranslateZCone: - case grabberTranslateZCylinder: - case grabberRotateRollRing: - case grabberStretchZSphere: - pickedColor = COLOR_BLUE; - highlightNeeded = true; - break; - case grabberScaleLBNCube: - case grabberScaleRBNCube: - case grabberScaleLBFCube: - case grabberScaleRBFCube: - case grabberScaleLTNCube: - case grabberScaleRTNCube: - case grabberScaleLTFCube: - case grabberScaleRTFCube: - pickedColor = GRABBER_SCALE_CUBE_IDLE_COLOR; - highlightNeeded = true; - break; - default: - that.resetPreviousHandleColor(); - break; - } - - if (highlightNeeded) { - that.resetPreviousHandleColor(); - Overlays.editOverlay(result.overlayID, { color: GRABBER_HOVER_COLOR }); - previousHandle = result.overlayID; - previousHandleHelper = that.getHandleHelper(result.overlayID); - if (previousHandleHelper != null) { - Overlays.editOverlay(previousHandleHelper, { color: GRABBER_HOVER_COLOR }); - } - previousHandleColor = pickedColor; - } - - } else { - that.resetPreviousHandleColor(); - } - - if (wantDebug) { - print("=============== eST::MouseMoveEvent END ======================="); - } - return false; - }; - - // FUNCTION: MOUSE RELEASE EVENT - that.mouseReleaseEvent = function(event) { - var wantDebug = false; - if (wantDebug) { - print("=============== eST::MouseReleaseEvent BEG ======================="); - } - var showHandles = false; - if (activeTool) { - if (activeTool.onEnd) { - if (wantDebug) { - print(" Triggering ActiveTool(" + activeTool.mode + ")'s onEnd"); - } - activeTool.onEnd(event); - } else if (wantDebug) { - print(" ActiveTool(" + activeTool.mode + ")'s missing onEnd"); - } - } - - showHandles = activeTool; // base on prior tool value - activeTool = null; - - // if something is selected, then reset the "original" properties for any potential next click+move operation - if (SelectionManager.hasSelection()) { - if (showHandles) { - if (wantDebug) { - print(" Triggering that.select"); - } - that.select(SelectionManager.selections[0], event); - } - } - - if (wantDebug) { - print("=============== eST::MouseReleaseEvent END ======================="); - } - }; - - // NOTE: mousePressEvent and mouseMoveEvent from the main script should call us., so we don't hook these: - // Controller.mousePressEvent.connect(that.mousePressEvent); - // Controller.mouseMoveEvent.connect(that.mouseMoveEvent); - Controller.mouseReleaseEvent.connect(that.mouseReleaseEvent); + addHandleScaleTool(handleScaleLBNCube, "SCALE_LBN", SCALE_DIRECTION.LBN); + addHandleScaleTool(handleScaleRBNCube, "SCALE_RBN", SCALE_DIRECTION.RBN); + addHandleScaleTool(handleScaleLBFCube, "SCALE_LBF", SCALE_DIRECTION.LBF); + addHandleScaleTool(handleScaleRBFCube, "SCALE_RBF", SCALE_DIRECTION.RBF); + addHandleScaleTool(handleScaleLTNCube, "SCALE_LTN", SCALE_DIRECTION.LTN); + addHandleScaleTool(handleScaleRTNCube, "SCALE_RTN", SCALE_DIRECTION.RTN); + addHandleScaleTool(handleScaleLTFCube, "SCALE_LTF", SCALE_DIRECTION.LTF); + addHandleScaleTool(handleScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF); return that; }()); \ No newline at end of file From 55f55cd78bdc52c5c2529d27b26dccb0e19f13eb Mon Sep 17 00:00:00 2001 From: David Back Date: Thu, 1 Feb 2018 17:59:38 -0800 Subject: [PATCH 061/272] few more updates --- .../system/libraries/entitySelectionTool.js | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index c68fb6e71c..d294fecf21 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -248,6 +248,7 @@ SelectionDisplay = (function() { var TRANSLATE_ARROW_CYLINDER_CAMERA_DISTANCE_MULTIPLE = 0.005; var TRANSLATE_ARROW_CYLINDER_Y_MULTIPLE = 7.5; var TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE = 0.025; + var TRANSLATE_ARROW_CONE_OFFSET_CYLINDER_DIMENSION_MULTIPLE = 0.83; var ROTATE_RING_CAMERA_DISTANCE_MULTIPLE = 0.15; var ROTATE_CTRL_SNAP_ANGLE = 22.5; @@ -257,7 +258,7 @@ SelectionDisplay = (function() { var ROTATE_RING_SELECTED_INNER_RADIUS = 0.9; // These are multipliers for sizing the rotation degrees display while rotating an entity - var ROTATE_DISPLAY_DISTANCE_MULTIPLIER = 1.0; + var ROTATE_DISPLAY_DISTANCE_MULTIPLIER = 1.75; var ROTATE_DISPLAY_SIZE_X_MULTIPLIER = 0.3; var ROTATE_DISPLAY_SIZE_Y_MULTIPLIER = 0.09; var ROTATE_DISPLAY_LINE_HEIGHT_MULTIPLIER = 0.07; @@ -674,7 +675,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 ((hitOverlayID === HMD.tabletID) || (hitOverlayID === HMD.tabletScreenID) || + (hitOverlayID === HMD.homeButtonID)) { // EARLY EXIT-(mouse clicks on the tablet should override the edit affordances) return false; } @@ -1036,6 +1038,7 @@ SelectionDisplay = (function() { }; var arrowConeDimension = toCameraDistance * TRANSLATE_ARROW_CONE_CAMERA_DISTANCE_MULTIPLE; var arrowConeDimensions = { x:arrowConeDimension, y:arrowConeDimension, z:arrowConeDimension }; + var arrowConeOffset = arrowCylinderDimensions.y * TRANSLATE_ARROW_CONE_OFFSET_CYLINDER_DIMENSION_MULTIPLE; var cylinderXPosition = { x:TRANSLATE_ARROW_CYLINDER_OFFSET * toCameraDistance, y:0, z:0 }; cylinderXPosition = Vec3.sum(position, Vec3.multiplyQbyV(rotation, cylinderXPosition)); Overlays.editOverlay(handleTranslateXCylinder, { @@ -1044,7 +1047,7 @@ SelectionDisplay = (function() { dimensions: arrowCylinderDimensions }); var cylinderXDiff = Vec3.subtract(cylinderXPosition, position); - var coneXPosition = Vec3.sum(cylinderXPosition, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowCylinderDimensions.y * 0.83)); + var coneXPosition = Vec3.sum(cylinderXPosition, Vec3.multiply(Vec3.normalize(cylinderXDiff), arrowConeOffset)); Overlays.editOverlay(handleTranslateXCone, { position: coneXPosition, rotation: rotationX, @@ -1058,7 +1061,7 @@ SelectionDisplay = (function() { dimensions: arrowCylinderDimensions }); var cylinderYDiff = Vec3.subtract(cylinderYPosition, position); - var coneYPosition = Vec3.sum(cylinderYPosition, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowCylinderDimensions.y * 0.83)); + var coneYPosition = Vec3.sum(cylinderYPosition, Vec3.multiply(Vec3.normalize(cylinderYDiff), arrowConeOffset)); Overlays.editOverlay(handleTranslateYCone, { position: coneYPosition, rotation: rotationY, @@ -1072,7 +1075,7 @@ SelectionDisplay = (function() { dimensions: arrowCylinderDimensions }); var cylinderZDiff = Vec3.subtract(cylinderZPosition, position); - var coneZPosition = Vec3.sum(cylinderZPosition, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowCylinderDimensions.y * 0.83)); + var coneZPosition = Vec3.sum(cylinderZPosition, Vec3.multiply(Vec3.normalize(cylinderZDiff), arrowConeOffset)); Overlays.editOverlay(handleTranslateZCone, { position: coneZPosition, rotation: rotationZ, @@ -1275,9 +1278,12 @@ SelectionDisplay = (function() { }); } - that.setHandleTranslateXVisible(!activeTool || isActiveTool(handleTranslateXCone) || isActiveTool(handleTranslateXCylinder)); - that.setHandleTranslateYVisible(!activeTool || isActiveTool(handleTranslateYCone) || isActiveTool(handleTranslateYCylinder)); - that.setHandleTranslateZVisible(!activeTool || isActiveTool(handleTranslateZCone) || isActiveTool(handleTranslateZCylinder)); + that.setHandleTranslateXVisible(!activeTool || isActiveTool(handleTranslateXCone) || + isActiveTool(handleTranslateXCylinder)); + that.setHandleTranslateYVisible(!activeTool || isActiveTool(handleTranslateYCone) || + isActiveTool(handleTranslateYCylinder)); + that.setHandleTranslateZVisible(!activeTool || isActiveTool(handleTranslateZCone) || + isActiveTool(handleTranslateZCylinder)); that.setHandleRotatePitchVisible(!activeTool || isActiveTool(handleRotatePitchRing)); that.setHandleRotateYawVisible(!activeTool || isActiveTool(handleRotateYawRing)); that.setHandleRotateRollVisible(!activeTool || isActiveTool(handleRotateRollRing)); @@ -1286,10 +1292,14 @@ SelectionDisplay = (function() { that.setHandleStretchXVisible(showScaleStretch || isActiveTool(handleStretchXSphere)); that.setHandleStretchYVisible(showScaleStretch || isActiveTool(handleStretchYSphere)); that.setHandleStretchZVisible(showScaleStretch || isActiveTool(handleStretchZSphere)); - that.setHandleScaleCubeVisible(showScaleStretch || isActiveTool(handleScaleLBNCube) || isActiveTool(handleScaleRBNCube) || isActiveTool(handleScaleLBFCube) || isActiveTool(handleScaleRBFCube) - || isActiveTool(handleScaleLTNCube) || isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) || isActiveTool(handleScaleRTFCube) - || isActiveTool(handleStretchXSphere) || isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere)); - that.setHandleScaleEdgeVisible(!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) && !isActiveTool(handleRotateRollRing)); + that.setHandleScaleCubeVisible(showScaleStretch || isActiveTool(handleScaleLBNCube) || + isActiveTool(handleScaleRBNCube) || isActiveTool(handleScaleLBFCube) || + isActiveTool(handleScaleRBFCube) || isActiveTool(handleScaleLTNCube) || + isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) || + isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) || + isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere)); + that.setHandleScaleEdgeVisible(!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) && + !isActiveTool(handleRotateRollRing)); //keep cloner always hidden for now since you can hold Alt to clone while dragging to translate - we may bring cloner back for HMD only later //that.setHandleClonerVisible(!activeTool || isActiveTool(handleCloner)); @@ -1453,7 +1463,9 @@ SelectionDisplay = (function() { startPosition = SelectionManager.worldPosition; translateXZTool.pickPlanePosition = pickResult.intersection; - translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y), SelectionManager.worldDimensions.z); + translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, + SelectionManager.worldDimensions.y), + SelectionManager.worldDimensions.z); translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position); translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition); if (wantDebug) { @@ -2215,7 +2227,8 @@ SelectionDisplay = (function() { var rotationCenterToZero = Vec3.subtract(rotationZero, rotationCenter); var rotationCenterToZeroLength = Vec3.length(rotationCenterToZero); - rotationDegreesPosition = Vec3.sum(rotationCenter, Vec3.multiply(Vec3.normalize(rotationCenterToZero), rotationCenterToZeroLength * 1.75)); + rotationDegreesPosition = Vec3.sum(rotationCenter, Vec3.multiply(Vec3.normalize(rotationCenterToZero), + rotationCenterToZeroLength * ROTATE_DISPLAY_DISTANCE_MULTIPLIER)); updateRotationDegreesOverlay(0, rotationDegreesPosition); if (wantDebug) { @@ -2350,4 +2363,4 @@ SelectionDisplay = (function() { addHandleScaleTool(handleScaleRTFCube, "SCALE_RTF", SCALE_DIRECTION.RTF); return that; -}()); \ No newline at end of file +}()); From 3804917cf46abb3f9919e252d68ad41a0aa5b6c3 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 09:40:57 +0100 Subject: [PATCH 062/272] Orthographic octree selection seems to be working --- libraries/gpu/src/gpu/Framebuffer.cpp | 2 +- libraries/octree/src/OctreeUtils.cpp | 8 +- libraries/octree/src/OctreeUtils.h | 3 +- .../render-utils/src/RenderShadowTask.cpp | 50 +++++++++---- libraries/render-utils/src/RenderShadowTask.h | 10 +-- libraries/render-utils/src/Shadow.slh | 5 -- libraries/render-utils/src/ShadowCore.slh | 4 +- libraries/render/src/render/CullTask.cpp | 30 +++++--- libraries/render/src/render/CullTask.h | 3 +- .../render/src/render/DrawSceneOctree.cpp | 2 +- .../src/render/RenderFetchCullSortTask.cpp | 2 +- libraries/render/src/render/SpatialTree.cpp | 74 +++++++++++++------ libraries/render/src/render/SpatialTree.h | 31 ++++---- libraries/shared/src/ViewFrustum.cpp | 4 + libraries/shared/src/ViewFrustum.h | 1 + 15 files changed, 152 insertions(+), 77 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 4fcc9ab0f9..8bb9be4a76 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -62,7 +62,7 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) { samplerDesc._wrapModeU = Sampler::WRAP_BORDER; samplerDesc._wrapModeV = Sampler::WRAP_BORDER; samplerDesc._filter = Sampler::FILTER_MIN_MAG_LINEAR; - samplerDesc._comparisonFunc = LESS_EQUAL; + samplerDesc._comparisonFunc = LESS; depthTexture->setSampler(Sampler(samplerDesc)); framebuffer->setDepthStencilBuffer(depthTexture, depthFormat); diff --git a/libraries/octree/src/OctreeUtils.cpp b/libraries/octree/src/OctreeUtils.cpp index c55016d8e2..ca15324d4e 100644 --- a/libraries/octree/src/OctreeUtils.cpp +++ b/libraries/octree/src/OctreeUtils.cpp @@ -64,8 +64,14 @@ float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeSc return voxelSizeScale / powf(2.0f, renderLevel); } -float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) { +float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust) { const float maxScale = (float)TREE_SCALE; float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / OCTREE_TO_MESH_RATIO; return atan(maxScale / visibleDistanceAtMaxScale); } + +float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust) { + // Smallest visible element is 1cm + const float smallestSize = 0.01f; + return (smallestSize * MAX_VISIBILITY_DISTANCE_FOR_UNIT_ELEMENT) / boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale); +} diff --git a/libraries/octree/src/OctreeUtils.h b/libraries/octree/src/OctreeUtils.h index c257bcd5f1..0f87bb6f68 100644 --- a/libraries/octree/src/OctreeUtils.h +++ b/libraries/octree/src/OctreeUtils.h @@ -25,7 +25,8 @@ float calculateRenderAccuracy(const glm::vec3& position, float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale); -float getAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust); +float getPerspectiveAccuracyAngle(float octreeSizeScale, int boundaryLevelAdjust); +float getOrthographicAccuracySize(float octreeSizeScale, int boundaryLevelAdjust); // MIN_ELEMENT_ANGULAR_DIAMETER = angular diameter of 1x1x1m cube at 400m = sqrt(3) / 400 = 0.0043301 radians ~= 0.25 degrees const float MIN_ELEMENT_ANGULAR_DIAMETER = 0.0043301f; // radians diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index c9df67dad1..b576bf774c 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -214,9 +214,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende } const auto setupOutput = task.addJob("ShadowSetup"); + const auto queryResolution = setupOutput.getN(2); // Fetch and cull the items from the scene static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - const auto fetchInput = render::Varying(shadowCasterFilter); + const auto fetchInput = FetchSpatialTree::Inputs(shadowCasterFilter, queryResolution).asVarying(); const auto shadowSelection = task.addJob("FetchShadowTree", fetchInput); const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying(); const auto shadowItems = task.addJob("FetchShadowSelection", selectionInputs); @@ -281,14 +282,15 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O output.edit0() = args->_renderMode; output.edit1() = args->_sizeScale; + output.edit2() = glm::ivec2(0, 0); const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); - auto& firstCascadeFrustum = globalShadow->getCascade(0).getFrustum(); + + auto& firstCascade = globalShadow->getCascade(0); + auto& firstCascadeFrustum = firstCascade.getFrustum(); unsigned int cascadeIndex; - _coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition()); - _coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation()); // Adjust each cascade frustum for (cascadeIndex = 0; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) { @@ -297,19 +299,29 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, bias._constant, bias._slope); } + // Now adjust coarse frustum bounds - auto left = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight()); - auto right = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight()); - auto top = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp()); - auto bottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp()); + auto frustumPosition = firstCascadeFrustum->getPosition(); + auto farTopLeft = firstCascadeFrustum->getFarTopLeft() - frustumPosition; + auto farBottomRight = firstCascadeFrustum->getFarBottomRight() - frustumPosition; + + auto left = glm::dot(farTopLeft, firstCascadeFrustum->getRight()); + auto right = glm::dot(farBottomRight, firstCascadeFrustum->getRight()); + auto top = glm::dot(farTopLeft, firstCascadeFrustum->getUp()); + auto bottom = glm::dot(farBottomRight, firstCascadeFrustum->getUp()); auto near = firstCascadeFrustum->getNearClip(); auto far = firstCascadeFrustum->getFarClip(); + for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) { auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum(); - auto cascadeLeft = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getRight()); - auto cascadeRight = glm::dot(cascadeFrustum->getFarTopRight(), cascadeFrustum->getRight()); - auto cascadeTop = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getUp()); - auto cascadeBottom = glm::dot(cascadeFrustum->getFarBottomRight(), cascadeFrustum->getUp()); + + farTopLeft = cascadeFrustum->getFarTopLeft() - frustumPosition; + farBottomRight = cascadeFrustum->getFarBottomRight() - frustumPosition; + + auto cascadeLeft = glm::dot(farTopLeft, cascadeFrustum->getRight()); + auto cascadeRight = glm::dot(farBottomRight, cascadeFrustum->getRight()); + auto cascadeTop = glm::dot(farTopLeft, cascadeFrustum->getUp()); + auto cascadeBottom = glm::dot(farBottomRight, cascadeFrustum->getUp()); auto cascadeNear = cascadeFrustum->getNearClip(); auto cascadeFar = cascadeFrustum->getFarClip(); left = glm::min(left, cascadeLeft); @@ -319,6 +331,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O near = glm::min(near, cascadeNear); far = glm::max(far, cascadeFar); } + + _coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition()); + _coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation()); _coarseShadowFrustum->setProjection(glm::ortho(left, right, bottom, top, near, far)); _coarseShadowFrustum->calculate(); @@ -326,10 +341,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O args->pushViewFrustum(*_coarseShadowFrustum); args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; - if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) { - // Set to ridiculously high amount to prevent solid angle culling in octree selection - args->_sizeScale = 1e16f; - } + + // We want for the octree query enough resolution to catch the details in the lowest cascade. So compute + // the desired resolution for the first cascade frustum and extrapolate it to the coarse frustum. + glm::ivec2 queryResolution = firstCascade.framebuffer->getSize(); + queryResolution.x = int(queryResolution.x * _coarseShadowFrustum->getWidth() / firstCascadeFrustum->getWidth()); + queryResolution.y = int(queryResolution.y * _coarseShadowFrustum->getHeight() / firstCascadeFrustum->getHeight()); + output.edit2() = queryResolution; } } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 1736d07fd5..ce4c3047d8 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -71,10 +71,10 @@ public: float constantBias1{ 0.15f }; float constantBias2{ 0.15f }; float constantBias3{ 0.15f }; - float slopeBias0{ 0.55f }; - float slopeBias1{ 0.55f }; - float slopeBias2{ 0.55f }; - float slopeBias3{ 0.55f }; + float slopeBias0{ 0.6f }; + float slopeBias1{ 0.6f }; + float slopeBias2{ 0.6f }; + float slopeBias3{ 0.6f }; signals: void dirty(); @@ -82,7 +82,7 @@ signals: class RenderShadowSetup { public: - using Outputs = render::VaryingSet2; + using Outputs = render::VaryingSet3; using Config = RenderShadowSetupConfig; using JobModel = render::Job::ModelO; diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 6575e68090..e87519b5f4 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -79,15 +79,10 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[2]) + fetchShadow(cascadeIndex, shadowTexcoord.xyz + offsets.points[3]) ); - return shadowAttenuation; } float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) { - if (!isShadowCascadeProjectedOnPixel(shadowTexcoord)) { - // If a point is not in the map, do not attenuate - return 1.0; - } float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL; return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias); } diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index 782e2bc2b8..e49e8d638f 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -53,8 +53,8 @@ vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) { } bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) { - bvec2 greaterThanZero = greaterThanEqual(cascadeTexCoords.xy, vec2(0)); - bvec2 lessThanOne = lessThanEqual(cascadeTexCoords.xy, vec2(1)); + bvec2 greaterThanZero = greaterThan(cascadeTexCoords.xy, vec2(0)); + bvec2 lessThanOne = lessThan(cascadeTexCoords.xy, vec2(1)); return all(greaterThanZero) && all(lessThanOne); } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index c6ff224560..b3efc4f1a8 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -14,8 +14,8 @@ #include #include -#include #include +#include using namespace render; @@ -33,7 +33,7 @@ struct Test { _renderDetails(renderDetails) { // FIXME: Keep this code here even though we don't use it yet /*_eyePos = _args->getViewFrustum().getPosition(); - float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); + float a = glm::degrees(Octree::getPerspectiveAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree auto tanAlpha = tan(angle); @@ -130,7 +130,8 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu // start fresh outSelection.clear(); - auto& filter = inputs; + auto& filter = inputs.get0(); + auto frustumResolution = inputs.get1(); if (!filter.selectsNothing()) { assert(renderContext->args); @@ -149,8 +150,19 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu } // Octree selection! - float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); - scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, angle); + float threshold = 0.0f; + if (queryFrustum.isPerspective()) { + threshold = getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust); + if (frustumResolution.y > 0) { + threshold = glm::max(queryFrustum.getFieldOfView() / frustumResolution.y, threshold); + } + } else { + threshold = getOrthographicAccuracySize(args->_sizeScale, args->_boundaryLevelAdjust); + glm::vec2 frustumSize = glm::vec2(queryFrustum.getWidth(), queryFrustum.getHeight()); + const auto pixelResolution = frustumResolution.x > 0 ? frustumResolution : glm::ivec2(2048, 2048); + threshold = glm::max(threshold, glm::min(frustumSize.x / pixelResolution.x, frustumSize.y / pixelResolution.y)); + } + scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, threshold); } } @@ -371,7 +383,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext, // Now get the bound, and // filter individually against the _filter - // inside & fit items: filter only, culling is disabled + // inside & fit items: filter only { PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { @@ -383,7 +395,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext, } } - // inside & subcell items: filter only, culling is disabled + // inside & subcell items: filter only { PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { @@ -395,7 +407,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext, } } - // partial & fit items: filter only, culling is disabled + // partial & fit items: filter only { PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { @@ -407,7 +419,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext, } } - // partial & subcell items: filter only, culling is disabled + // partial & subcell items: filter only { PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index a140a86aee..53d46d11b4 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -53,9 +53,10 @@ namespace render { bool _justFrozeFrustum{ false }; ViewFrustum _frozenFrustum; float _lodAngle; + public: using Config = FetchSpatialTreeConfig; - using Inputs = ItemFilter; + using Inputs = render::VaryingSet2; using JobModel = Job::ModelIO; FetchSpatialTree() {} diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 36663a454a..08d6340e43 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -148,7 +148,7 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS } // Draw the LOD Reticle { - float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); + float angle = glm::degrees(getPerspectiveAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); Transform crosshairModel; crosshairModel.setTranslation(glm::vec3(0.0, 0.0, -1000.0)); crosshairModel.setScale(1000.0f * tanf(glm::radians(angle))); // Scaling at the actual tan of the lod angle => Multiplied by TWO diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index a1b4f079e7..23935851b3 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -23,7 +23,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin // CPU jobs: // Fetch and cull the items from the scene const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); - const auto fetchInput = render::Varying(filter); + const auto fetchInput = FetchSpatialTree::Inputs(filter, glm::ivec2(0,0)).asVarying(); const auto spatialSelection = task.addJob("FetchSceneSelection", fetchInput); const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying(); const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); diff --git a/libraries/render/src/render/SpatialTree.cpp b/libraries/render/src/render/SpatialTree.cpp index 1bb3538521..c9f810ebc5 100644 --- a/libraries/render/src/render/SpatialTree.cpp +++ b/libraries/render/src/render/SpatialTree.cpp @@ -12,9 +12,26 @@ #include - using namespace render; +void Octree::PerspectiveSelector::setAngle(float a) { + const float MAX_LOD_ANGLE = glm::radians(45.0f); + const float MIN_LOD_ANGLE = glm::radians(1.0f / 60.0f); + + angle = std::max(MIN_LOD_ANGLE, std::min(MAX_LOD_ANGLE, a)); + auto tanAlpha = tan(angle); + squareTanAlpha = (float)(tanAlpha * tanAlpha); +} + +float Octree::PerspectiveSelector::testThreshold(const Coord3f& point, float size) const { + auto eyeToPoint = point - eyePos; + return (size * size / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha; +} + +float Octree::OrthographicSelector::testThreshold(const Coord3f& point, float size) const { + return (size * size) - squareMinSize; +} + const float Octree::INV_DEPTH_DIM[] = { 1.0f, @@ -520,10 +537,9 @@ int Octree::selectTraverse(Index cellID, CellSelection& selection, const Frustum // Test for lod auto cellLocation = cell.getlocation(); - float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth)); - if (lod < 0.0f) { + float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth)); + if (test < 0.0f) { return 0; - break; } // Select this cell partially in frustum @@ -543,13 +559,13 @@ int Octree::selectTraverse(Index cellID, CellSelection& selection, const Frustum } -int Octree::selectBranch(Index cellID, CellSelection& selection, const FrustumSelector& selector) const { +int Octree::selectBranch(Index cellID, CellSelection& selection, const FrustumSelector& selector) const { int numSelectedsIn = (int) selection.size(); auto cell = getConcreteCell(cellID); auto cellLocation = cell.getlocation(); - float lod = selector.testSolidAngle(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth)); - if (lod < 0.0f) { + float test = selector.testThreshold(cellLocation.getCenter(), Octree::getCoordSubcellWidth(cellLocation.depth)); + if (test < 0.0f) { return 0; } @@ -580,24 +596,40 @@ int Octree::selectCellBrick(Index cellID, CellSelection& selection, bool inside) return (int) selection.size() - numSelectedsIn; } - -int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const { +int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float threshold) const { auto worldPlanes = frustum.getPlanes(); - FrustumSelector selector; - for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) { - ::Plane octPlane; - octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH)); - selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient()); + if (frustum.isPerspective()) { + PerspectiveSelector selector; + for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) { + ::Plane octPlane; + octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH)); + selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient()); + } + + selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH); + selector.setAngle(threshold); + + return Octree::select(selection, selector); + } else { + OrthographicSelector selector; + for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) { + ::Plane octPlane; + octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH)); + selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient()); + } + + // Divide the threshold (which is in world distance units) by the dimension of the octree + // as all further computations will be done in normalized octree units + threshold *= getInvCellWidth(ROOT_DEPTH); + selector.setSize(threshold); + + return Octree::select(selection, selector); } - - selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH); - selector.setAngle(glm::radians(lodAngle)); - - return Octree::select(selection, selector); } -int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, float lodAngle) const { - selectCells(selection.cellSelection, frustum, lodAngle); +int ItemSpatialTree::selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, + float threshold) const { + selectCells(selection.cellSelection, frustum, threshold); // Just grab the items in every selected bricks for (auto brickId : selection.cellSelection.insideBricks) { diff --git a/libraries/render/src/render/SpatialTree.h b/libraries/render/src/render/SpatialTree.h index a89b9847e6..b06053344d 100644 --- a/libraries/render/src/render/SpatialTree.h +++ b/libraries/render/src/render/SpatialTree.h @@ -312,23 +312,27 @@ namespace render { class FrustumSelector { public: Coord4f frustum[6]; + + virtual ~FrustumSelector() {} + virtual float testThreshold(const Coord3f& point, float size) const = 0; + }; + + class PerspectiveSelector : public FrustumSelector { + public: Coord3f eyePos; float angle; float squareTanAlpha; - const float MAX_LOD_ANGLE = glm::radians(45.0f); - const float MIN_LOD_ANGLE = glm::radians(1.0f / 60.0f); + void setAngle(float a); + float testThreshold(const Coord3f& point, float size) const override; + }; - void setAngle(float a) { - angle = std::max(MIN_LOD_ANGLE, std::min(MAX_LOD_ANGLE, a)); - auto tanAlpha = tan(angle); - squareTanAlpha = (float)(tanAlpha * tanAlpha); - } + class OrthographicSelector : public FrustumSelector { + public: + float squareMinSize; - float testSolidAngle(const Coord3f& point, float size) const { - auto eyeToPoint = point - eyePos; - return (size * size / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha; - } + void setSize(float a) { squareMinSize = a * a; } + float testThreshold(const Coord3f& point, float size) const override; }; int select(CellSelection& selection, const FrustumSelector& selector) const; @@ -443,7 +447,7 @@ namespace render { Index resetItem(Index oldCell, const ItemKey& oldKey, const AABox& bound, const ItemID& item, ItemKey& newKey); // Selection and traverse - int selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const; + int selectCells(CellSelection& selection, const ViewFrustum& frustum, float threshold) const; class ItemSelection { public: @@ -469,7 +473,8 @@ namespace render { } }; - int selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, float lodAngle) const; + int selectCellItems(ItemSelection& selection, const ItemFilter& filter, const ViewFrustum& frustum, + float threshold) const; }; } diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 5b016d4e91..0f98e8020c 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -847,3 +847,7 @@ void ViewFrustum::tesselateSides(const glm::vec3 points[8], Triangle triangles[8 triangle.v2 = points[vertexIndices[2]]; } } + +bool ViewFrustum::isPerspective() const { + return _projection[3][2] != 0.0f && _projection[2][3] != 0.0f && _projection[3][3] == 0.0f; +} diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index b55fe8b327..859b5c49c5 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -49,6 +49,7 @@ public: // setters for lens attributes void setProjection(const glm::mat4 & projection); void setFocalLength(float focalLength) { _focalLength = focalLength; } + bool isPerspective() const; // getters for lens attributes const glm::mat4& getProjection() const { return _projection; } From 1f4671ba175547f00ccce78b30627bba9de321b6 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 11:09:28 +0100 Subject: [PATCH 063/272] Cleaned up orthographic shadow culling functor --- interface/src/SecondaryCamera.cpp | 2 +- .../render-utils/src/RenderShadowTask.cpp | 25 ++++++++++--------- libraries/render-utils/src/RenderShadowTask.h | 20 ++++++++++++--- libraries/render-utils/src/RenderViewTask.cpp | 8 +----- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 5db34c9441..c4199f15b2 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -19,7 +19,7 @@ using RenderArgsPointer = std::shared_ptr; void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { - task.addJob("RenderShadowTask", cullFunctor); + task.addJob("RenderShadowTask"); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); if (!isDeferred) { diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index b576bf774c..da7f6d97fa 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -200,8 +200,10 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con }); } -void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { - cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; }; +void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { + ::CullFunctor cullFunctor = [this](const RenderArgs* args, const AABox& bounds) { + return _cullFunctor(args, bounds); + }; // Prepare the ShapePipeline ShapePlumberPointer shapePlumber = std::make_shared(); @@ -229,7 +231,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); - const auto shadowFilter = task.addJob(jobName, i); + const auto shadowFilter = task.addJob(jobName, i, _cullFunctor); // CPU jobs: finer grained culling const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying(); @@ -281,8 +283,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O RenderArgs* args = renderContext->args; output.edit0() = args->_renderMode; - output.edit1() = args->_sizeScale; - output.edit2() = glm::ivec2(0, 0); + output.edit1() = glm::ivec2(0, 0); const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { @@ -347,7 +348,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O glm::ivec2 queryResolution = firstCascade.framebuffer->getSize(); queryResolution.x = int(queryResolution.x * _coarseShadowFrustum->getWidth() / firstCascadeFrustum->getWidth()); queryResolution.y = int(queryResolution.y * _coarseShadowFrustum->getHeight() / firstCascadeFrustum->getHeight()); - output.edit2() = queryResolution; + output.edit1() = queryResolution; } } @@ -365,11 +366,12 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon auto& cascade = globalShadow->getCascade(_cascadeIndex); auto& cascadeFrustum = cascade.getFrustum(); args->pushViewFrustum(*cascadeFrustum); - // Set the cull threshold to 2 shadow texels. - auto texelSize = glm::max(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x; - texelSize *= 2.0f; - // SizeScale is used in the shadow cull function defined ine RenderViewTask - args->_sizeScale = texelSize * texelSize; + auto texelSize = glm::min(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x; + // Set the cull threshold to 16 shadow texels. + const auto minTexelCount = 16.0f; + // TODO : maybe adapt that with LOD management system? + texelSize *= minTexelCount; + _cullFunctor._minSquareSize = texelSize * texelSize; } else { output = ItemFilter::Builder::nothing(); } @@ -393,5 +395,4 @@ void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext assert(args->hasViewFrustum()); // Reset the render args args->_renderMode = input.get0(); - args->_sizeScale = input.get1(); } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index ce4c3047d8..15651354f1 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -50,9 +50,22 @@ public: using JobModel = render::Task::Model; RenderShadowTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); void configure(const Config& configuration); + + struct CullFunctor { + float _minSquareSize{ 0.0f }; + + bool operator()(const RenderArgs* args, const AABox& bounds) const { + // Cull only objects that are too small relatively to shadow frustum + const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions()); + return boundsSquareRadius > _minSquareSize; + } + }; + + CullFunctor _cullFunctor; + }; class RenderShadowSetupConfig : public render::Job::Config { @@ -82,7 +95,7 @@ signals: class RenderShadowSetup { public: - using Outputs = render::VaryingSet3; + using Outputs = render::VaryingSet2; using Config = RenderShadowSetupConfig; using JobModel = render::Job::ModelO; @@ -107,12 +120,13 @@ public: using Outputs = render::ItemFilter; using JobModel = render::Job::ModelO; - RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} + RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor) : _cascadeIndex{ cascadeIndex }, _cullFunctor{ cullFunctor } {} void run(const render::RenderContextPointer& renderContext, Outputs& output); private: unsigned int _cascadeIndex; + RenderShadowTask::CullFunctor& _cullFunctor; }; class RenderShadowCascadeTeardown { diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index c2e43582cd..68585ac437 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -17,13 +17,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) { // auto items = input.get(); - // Shadows use an orthographic projection because they are linked to sunlights - // but the cullFunctor passed is probably tailored for perspective projection and culls too much. - task.addJob("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) { - // Cull only objects that are too small relatively to shadow frustum - const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions()); - return boundsSquareRadius > args->_sizeScale; - }); + task.addJob("RenderShadowTask"); const auto items = task.addJob("FetchCullSort", cullFunctor); assert(items.canCast()); From 234cb1e3e612a1fe4b19ac516840b771a020f0da Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 12:15:43 +0100 Subject: [PATCH 064/272] Added anti frustum test to remove lower cascade objects from higher shadow cascades --- .../render-utils/src/RenderShadowTask.cpp | 24 ++++++++++--- libraries/render-utils/src/RenderShadowTask.h | 2 +- libraries/render/src/render/CullTask.cpp | 36 ++++++++++++++----- libraries/render/src/render/CullTask.h | 2 +- libraries/shared/src/ViewFrustum.cpp | 12 +++++++ libraries/shared/src/ViewFrustum.h | 1 + 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index da7f6d97fa..829c0fbcf2 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -228,13 +228,26 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto sortedPipelines = task.addJob("PipelineSortShadow", shadowItems); const auto sortedShapes = task.addJob("DepthSortShadow", sortedPipelines, true); + render::Varying cascadeFrustums[SHADOW_CASCADE_MAX_COUNT] = { + ViewFrustumPointer(), + ViewFrustumPointer(), + ViewFrustumPointer(), + ViewFrustumPointer() + }; + for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); - const auto shadowFilter = task.addJob(jobName, i, _cullFunctor); + const auto cascadeSetupOutput = task.addJob(jobName, i, _cullFunctor); + const auto shadowFilter = cascadeSetupOutput.getN(0); + auto antiFrustum = render::Varying(ViewFrustumPointer()); + cascadeFrustums[i] = cascadeSetupOutput.getN(1); + if (i > 1) { + antiFrustum = cascadeFrustums[i - 2]; + } // CPU jobs: finer grained culling - const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying(); + const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter, antiFrustum).asVarying(); const auto culledShadowItemsAndBounds = task.addJob("CullShadowCascade", cullInputs, cullFunctor, RenderDetails::SHADOW); // GPU jobs: Render to shadow map @@ -360,7 +373,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); + output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); @@ -372,8 +385,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon // TODO : maybe adapt that with LOD management system? texelSize *= minTexelCount; _cullFunctor._minSquareSize = texelSize * texelSize; + + output.edit1() = cascadeFrustum; } else { - output = ItemFilter::Builder::nothing(); + output.edit0() = ItemFilter::Builder::nothing(); + output.edit1() = ViewFrustumPointer(); } } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 15651354f1..975f755a48 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -117,7 +117,7 @@ private: class RenderShadowCascadeSetup { public: - using Outputs = render::ItemFilter; + using Outputs = render::VaryingSet2; using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor) : _cascadeIndex{ cascadeIndex }, _cullFunctor{ cullFunctor } {} diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index b3efc4f1a8..633465dba3 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -24,13 +24,15 @@ struct Test { CullFunctor _functor; RenderArgs* _args; RenderDetails::Item& _renderDetails; + ViewFrustumPointer _antiFrustum; glm::vec3 _eyePos; float _squareTanAlpha; - Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) : + Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails, ViewFrustumPointer antiFrustum = nullptr) : _functor(functor), _args(pargs), - _renderDetails(renderDetails) { + _renderDetails(renderDetails), + _antiFrustum(antiFrustum) { // FIXME: Keep this code here even though we don't use it yet /*_eyePos = _args->getViewFrustum().getPosition(); float a = glm::degrees(Octree::getPerspectiveAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); @@ -49,6 +51,15 @@ struct Test { return true; } + bool antiFrustumTest(const AABox& bound) { + assert(_antiFrustum); + if (_antiFrustum->boxInsideFrustum(bound)) { + _renderDetails._outOfView++; + return false; + } + return true; + } + bool solidAngleTest(const AABox& bound) { // FIXME: Keep this code here even though we don't use it yet //auto eyeToPoint = bound.calcCenter() - _eyePos; @@ -331,6 +342,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input const auto& inShapes = inputs.get0(); const auto& filter = inputs.get1(); + const auto& antiFrustum = inputs.get2(); auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); @@ -339,7 +351,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (!filter.selectsNothing()) { auto& details = args->_details.edit(_detailType); - Test test(_cullFunctor, args, details); + Test test(_cullFunctor, args, details, antiFrustum); for (auto& inItems : inShapes) { auto key = inItems.first; @@ -351,13 +363,21 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input details._considered += (int)inItems.second.size(); - for (auto& item : inItems.second) { - if (test.frustumTest(item.bound) && test.solidAngleTest(item.bound)) { - outItems->second.emplace_back(item); - outBounds += item.bound; + if (antiFrustum == nullptr) { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { + outItems->second.emplace_back(item); + outBounds += item.bound; + } + } + } else { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { + outItems->second.emplace_back(item); + outBounds += item.bound; + } } } - details._rendered += (int)outItems->second.size(); } diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 53d46d11b4..a9695d6281 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -110,7 +110,7 @@ namespace render { class CullShapeBounds { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Outputs = render::VaryingSet2; using JobModel = Job::ModelIO; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 0f98e8020c..2a2eebc0a7 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -280,6 +280,18 @@ bool ViewFrustum::boxIntersectsFrustum(const AABox& box) const { return true; } +bool ViewFrustum::boxInsideFrustum(const AABox& box) const { + // only check against frustum + for (int i = 0; i < NUM_FRUSTUM_PLANES; i++) { + const glm::vec3& normal = _planes[i].getNormal(); + // check distance to nearest box point + if (_planes[i].distance(box.getNearestVertex(normal)) < 0.0f) { + return false; + } + } + return true; +} + bool ViewFrustum::sphereIntersectsKeyhole(const glm::vec3& center, float radius) const { // check positive touch against central sphere if (glm::length(center - _position) <= (radius + _centerSphereRadius)) { diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 859b5c49c5..981aabe70c 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -104,6 +104,7 @@ public: bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; + bool boxInsideFrustum(const AABox& box) const; bool sphereIntersectsKeyhole(const glm::vec3& center, float radius) const; bool cubeIntersectsKeyhole(const AACube& cube) const; From e9747e9d85336baa56c12f664aa0dcda54ee2e6b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 15:06:22 +0100 Subject: [PATCH 065/272] Small optimisations in shadow shader --- libraries/render-utils/src/RenderShadowTask.cpp | 4 ++-- libraries/render-utils/src/RenderShadowTask.h | 8 ++++---- libraries/render-utils/src/Shadow.slh | 2 +- libraries/render-utils/src/ShadowCore.slh | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 829c0fbcf2..f3797edc11 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -380,8 +380,8 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon auto& cascadeFrustum = cascade.getFrustum(); args->pushViewFrustum(*cascadeFrustum); auto texelSize = glm::min(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x; - // Set the cull threshold to 16 shadow texels. - const auto minTexelCount = 16.0f; + // Set the cull threshold to 24 shadow texels. This is totally arbitrary + const auto minTexelCount = 24.0f; // TODO : maybe adapt that with LOD management system? texelSize *= minTexelCount; _cullFunctor._minSquareSize = texelSize * texelSize; diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 975f755a48..87d78ffe51 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -82,12 +82,12 @@ public: float constantBias0{ 0.15f }; float constantBias1{ 0.15f }; - float constantBias2{ 0.15f }; - float constantBias3{ 0.15f }; + float constantBias2{ 0.175f }; + float constantBias3{ 0.2f }; float slopeBias0{ 0.6f }; float slopeBias1{ 0.6f }; - float slopeBias2{ 0.6f }; - float slopeBias3{ 0.6f }; + float slopeBias2{ 0.7f }; + float slopeBias3{ 0.82f }; signals: void dirty(); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index e87519b5f4..abb04a4498 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -89,7 +89,7 @@ float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDepth, vec3 worldNormal) { ShadowSampleOffsets offsets = evalShadowFilterOffsets(worldPosition); - vec4 cascadeShadowCoords[2]; + vec4 cascadeShadowCoords[2] = { vec4(0), vec4(0) }; ivec2 cascadeIndices; float cascadeMix = determineShadowCascadesOnPixel(worldPosition, viewDepth, cascadeShadowCoords, cascadeIndices); diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index e49e8d638f..a787c54ca0 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -82,10 +82,10 @@ float evalShadowCascadeWeight(vec4 cascadeTexCoords) { float determineShadowCascadesOnPixel(vec4 worldPosition, float viewDepth, out vec4 cascadeShadowCoords[2], out ivec2 cascadeIndices) { cascadeIndices.x = getFirstShadowCascadeOnPixel(0, worldPosition, cascadeShadowCoords[0]); cascadeIndices.y = cascadeIndices.x+1; - if (cascadeIndices.x < (getShadowCascadeCount()-1)) { + float firstCascadeWeight = evalShadowCascadeWeight(cascadeShadowCoords[0]); + if (firstCascadeWeight<1.0 && cascadeIndices.x < (getShadowCascadeCount()-1)) { cascadeIndices.y = getFirstShadowCascadeOnPixel(cascadeIndices.y, worldPosition, cascadeShadowCoords[1]); - float firstCascadeWeight = evalShadowCascadeWeight(cascadeShadowCoords[0]); float secondCascadeWeight = evalShadowCascadeWeight(cascadeShadowCoords[1]); // Returns the mix amount between first and second cascade. return ((1.0-firstCascadeWeight) * secondCascadeWeight) / (firstCascadeWeight + secondCascadeWeight); From 8a011036ef4f9be5b5412936a3f0cfe6a0de208b Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 18:07:35 +0100 Subject: [PATCH 066/272] Removed warnings on mac and ubuntu --- libraries/render-utils/src/LightStage.cpp | 2 -- libraries/render/src/render/CullTask.cpp | 1 - 2 files changed, 3 deletions(-) diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 259d0dd665..854ff71e20 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -208,8 +208,6 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, // Position the keylight frustum auto position = viewFrustum.getPosition() - (nearDepth + farDepth)*lightDirection; - // Update the buffer - auto& schema = _schemaBuffer.edit(); for (auto& cascade : _cascades) { cascade._frustum->setOrientation(orientation); cascade._frustum->setPosition(position); diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 633465dba3..c745220ab8 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -390,7 +390,6 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input void FetchSpatialSelection::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems) { assert(renderContext->args); - RenderArgs* args = renderContext->args; auto& scene = renderContext->_scene; auto& inSelection = inputs.get0(); From 3a7290c3ede88e7e402c1547d6133621c19c62fa Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Mon, 8 Jan 2018 12:15:13 -0800 Subject: [PATCH 067/272] starting 2d image entity type --- libraries/entities/src/EntityTypes.h | 1 + libraries/entities/src/FlatImageEntity.cpp | 74 ++++++++++++++++++++++ libraries/entities/src/FlatImageEntity.h | 41 ++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 libraries/entities/src/FlatImageEntity.cpp create mode 100644 libraries/entities/src/FlatImageEntity.h diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 316bf2b813..dac36f28dd 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -49,6 +49,7 @@ public: PolyVox, PolyLine, Shape, + Image, LAST = Shape } EntityType; diff --git a/libraries/entities/src/FlatImageEntity.cpp b/libraries/entities/src/FlatImageEntity.cpp new file mode 100644 index 0000000000..9eb3f64bcb --- /dev/null +++ b/libraries/entities/src/FlatImageEntity.cpp @@ -0,0 +1,74 @@ +// +// FlatImageEntity.cpp +// libraries/entities/src +// +// Created by Elisa Lupin-Jimenez on 1/3/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 + +#include +#include +#include +#include + +#include "EntitiesLogging.h" +#include "EntityItemProperties.h" +#include "EntityTree.h" +#include "EntityTreeElement.h" +#include "ResourceCache.h" +#include "ShapeEntityItem.h" +#include "FlatImageEntity.h" + +const QString FlatImageEntity::DEFAULT_IMAGE_URL = QString(""); + +EntityItemPointer FlatImageEntity::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + EntityItemPointer entity(new FlatImageEntity(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +FlatImageEntity::FlatImageEntity(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Image; +} + +EntityItemProperties FlatImageEntity::getProperties(EntityPropertyFlags desiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class + properties.setShape("Image"); + return properties; +} + +bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "FlatImageEntity::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties.getLastEdited()); + } + return somethingChanged; +} + +void FlatImageEntity::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_SHAPE, entity::stringFromShape(getShape())); +} + diff --git a/libraries/entities/src/FlatImageEntity.h b/libraries/entities/src/FlatImageEntity.h new file mode 100644 index 0000000000..08c13f8f9f --- /dev/null +++ b/libraries/entities/src/FlatImageEntity.h @@ -0,0 +1,41 @@ +// +// FlatImageEntity.h +// libraries/entities/src +// +// Created by Elisa Lupin-Jimenez on 1/3/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_FlatImageEntity_h +#define hifi_FlatImageEntity_h + +#include "EntityItem.h" + +class FlatImageEntity : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + FlatImageEntity(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; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const override; + + static const QString DEFAULT_IMAGE_URL; + +}; + +#endif // hifi_FlatImageEntity_h From fdca8ab93eef09e21af8883e20b5072441300b80 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 9 Jan 2018 17:46:24 -0800 Subject: [PATCH 068/272] added image button to edit.js, working on connecting to cpp --- .../resources/qml/hifi/tablet/EditTabView.qml | 12 ++++++ .../entities/src/EntityItemProperties.cpp | 4 ++ libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 3 ++ libraries/entities/src/EntityTypes.cpp | 1 + libraries/entities/src/EntityTypes.h | 2 +- libraries/entities/src/FlatImageEntity.cpp | 43 +++++++++++++++++-- libraries/entities/src/FlatImageEntity.h | 12 ++++++ scripts/system/edit.js | 14 +++++- 9 files changed, 87 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index e94325f399..482469d355 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -101,6 +101,18 @@ TabView { } } + // for image + NewEntityButton { + icon: "icons/create-icons/25-web-1-01.svg" + text: "IMAGE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newImageButton" } + }); + editTabView.currentIndex = 2 + } + } + NewEntityButton { icon: "icons/create-icons/25-web-1-01.svg" text: "WEB" diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index e2a5ddf8b5..a1c51b650f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1369,6 +1369,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI()); } + if (properties.getType() == EntityTypes::Image) { + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); + } + if (properties.getType() == EntityTypes::Text) { APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3e0770f386..5bd6836336 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -194,6 +194,7 @@ public: DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); + DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 90438ab01c..4768ebed86 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -42,6 +42,9 @@ enum EntityPropertyList { PROP_ANIMATION_ALLOW_TRANSLATION, PROP_RELAY_PARENT_JOINTS, + // for image + PROP_IMAGE_URL, + // these properties are supported by the EntityItem base class PROP_REGISTRATION_POINT, PROP_ANGULAR_VELOCITY, diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index cb17c28fd7..e53b9d02f6 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -89,6 +89,7 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { + qCDebug(entities) << "type: " << entityType; factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index dac36f28dd..8d986c8090 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -48,8 +48,8 @@ public: Line, PolyVox, PolyLine, - Shape, Image, + Shape, LAST = Shape } EntityType; diff --git a/libraries/entities/src/FlatImageEntity.cpp b/libraries/entities/src/FlatImageEntity.cpp index 9eb3f64bcb..66a5702747 100644 --- a/libraries/entities/src/FlatImageEntity.cpp +++ b/libraries/entities/src/FlatImageEntity.cpp @@ -38,14 +38,14 @@ FlatImageEntity::FlatImageEntity(const EntityItemID& entityItemID) : EntityItem( EntityItemProperties FlatImageEntity::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - properties.setShape("Image"); + properties.setShape("Quad"); return properties; } bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); if (somethingChanged) { bool wantDebug = false; @@ -60,6 +60,13 @@ bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { return somethingChanged; } +// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time +EntityPropertyFlags FlatImageEntity::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + + return requestedProperties; +} + void FlatImageEntity::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, @@ -69,6 +76,36 @@ void FlatImageEntity::appendSubclassData(OctreePacketData* packetData, EncodeBit OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_SHAPE, entity::stringFromShape(getShape())); + // Using "Quad" shape as defined in ShapeEntityItem.cpp + APPEND_ENTITY_PROPERTY(PROP_SHAPE, "Quad"); +} + +int FlatImageEntity::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + return bytesRead; +} + +void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float MAX_FLAT_DIMENSION = 0.0001f; + if (value.y > MAX_FLAT_DIMENSION) { + // enforce flatness in Y + glm::vec3 newDimensions = value; + newDimensions.y = MAX_FLAT_DIMENSION; + EntityItem::setUnscaledDimensions(newDimensions); + } else { + EntityItem::setUnscaledDimensions(value); + } +} + +QString FlatImageEntity::getImageURL() const { + return resultWithReadLock([&] { + return _imageURL; + }); } diff --git a/libraries/entities/src/FlatImageEntity.h b/libraries/entities/src/FlatImageEntity.h index 08c13f8f9f..4dd91b1215 100644 --- a/libraries/entities/src/FlatImageEntity.h +++ b/libraries/entities/src/FlatImageEntity.h @@ -26,6 +26,8 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; + EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, @@ -34,7 +36,17 @@ public: int& propertyCount, OctreeElement::AppendState& appendState) const override; + int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) override; + + static const QString DEFAULT_IMAGE_URL; + QString getImageURL() const; + +protected: + QString _imageURL; }; diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 863c185cb4..4241468de1 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -251,7 +251,8 @@ var toolBar = (function () { // Align entity with Avatar orientation. properties.rotation = MyAvatar.orientation; - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; + // added image here + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. @@ -286,6 +287,7 @@ var toolBar = (function () { properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } }); } + print("properties.type: " + properties.type); entityID = Entities.addEntity(properties); if (properties.type === "ParticleEffect") { @@ -538,6 +540,16 @@ var toolBar = (function () { }); }); + // for image button + addButton("newImageButton", "web-01.svg", function () { + print("new image message is received"); + createNewEntity({ + type: "Image", + dimensions: DEFAULT_DIMENSIONS, + sourceUrl: "https://highfidelity.com/" + }); + }); + addButton("newWebButton", "web-01.svg", function () { createNewEntity({ type: "Web", From fc0e87d5eaa13cf7c97a1ab2ab8a8eac264576d5 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 10 Jan 2018 17:08:55 -0800 Subject: [PATCH 069/272] more infrastructure links --- .../entities/src/EntityItemProperties.cpp | 9 ++++ .../entities/src/EntityScriptingInterface.cpp | 2 + libraries/entities/src/EntityTree.cpp | 1 + libraries/entities/src/EntityTypes.cpp | 4 +- ...latImageEntity.cpp => ImageEntityItem.cpp} | 42 ++++++++++++------- .../{FlatImageEntity.h => ImageEntityItem.h} | 13 +++--- scripts/system/edit.js | 2 +- 7 files changed, 51 insertions(+), 22 deletions(-) rename libraries/entities/src/{FlatImageEntity.cpp => ImageEntityItem.cpp} (70%) rename libraries/entities/src/{FlatImageEntity.h => ImageEntityItem.h} (85%) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a1c51b650f..fc8ca18fb6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -590,6 +590,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); } + // Image only + if (_type == EntityTypes::Image) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); + } + // Web only if (_type == EntityTypes::Web) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); @@ -1734,6 +1739,10 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI); } + if (properties.getType() == EntityTypes::Image) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); + } + if (properties.getType() == EntityTypes::Text) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4342f0e683..cab4251d97 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -266,6 +266,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties bool success = true; if (_entityTree) { _entityTree->withWriteLock([&] { + propertiesWithSimID.getType(); + qCDebug(entities) << "check 2 type: " << propertiesWithSimID.getType(); EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); if (entity) { if (propertiesWithSimID.queryAACubeRelatedPropertyChanged()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bf29f3bec9..56c3aa216c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -514,6 +514,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti // construct the instance of the entity EntityTypes::EntityType type = props.getType(); + qCDebug(entities) << "check 3 type: " << type; result = EntityTypes::constructEntityItem(type, entityID, props); if (result) { diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index e53b9d02f6..2e4a0e89a9 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -28,6 +28,7 @@ #include "LineEntityItem.h" #include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" +#include "ImageEntityItem.h" #include "ShapeEntityItem.h" QMap EntityTypes::_typeToNameMap; @@ -47,6 +48,7 @@ REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyVox) REGISTER_ENTITY_TYPE(PolyLine) +REGISTER_ENTITY_TYPE(Image) REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) @@ -89,7 +91,7 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { - qCDebug(entities) << "type: " << entityType; + qCDebug(entities) << "check 4 type: " << entityType; factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/FlatImageEntity.cpp b/libraries/entities/src/ImageEntityItem.cpp similarity index 70% rename from libraries/entities/src/FlatImageEntity.cpp rename to libraries/entities/src/ImageEntityItem.cpp index 66a5702747..a94374f7b5 100644 --- a/libraries/entities/src/FlatImageEntity.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -1,5 +1,5 @@ // -// FlatImageEntity.cpp +// ImageEntityItem.cpp // libraries/entities/src // // Created by Elisa Lupin-Jimenez on 1/3/18. @@ -22,27 +22,27 @@ #include "EntityTreeElement.h" #include "ResourceCache.h" #include "ShapeEntityItem.h" -#include "FlatImageEntity.h" +#include "ImageEntityItem.h" -const QString FlatImageEntity::DEFAULT_IMAGE_URL = QString(""); +const QString ImageEntityItem::DEFAULT_IMAGE_URL = QString(""); -EntityItemPointer FlatImageEntity::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer entity(new FlatImageEntity(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); +EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + EntityItemPointer entity(new ImageEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); return entity; } -FlatImageEntity::FlatImageEntity(const EntityItemID& entityItemID) : EntityItem(entityItemID) { +ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Image; } -EntityItemProperties FlatImageEntity::getProperties(EntityPropertyFlags desiredProperties) const { +EntityItemProperties ImageEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties.setShape("Quad"); return properties; } -bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { +bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class //SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); @@ -52,7 +52,7 @@ bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { if (wantDebug) { uint64_t now = usecTimestampNow(); int elapsed = now - getLastEdited(); - qCDebug(entities) << "FlatImageEntity::setProperties() AFTER update... edited AGO=" << elapsed << + qCDebug(entities) << "ImageEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << "now=" << now << " getLastEdited()=" << getLastEdited(); } setLastEdited(properties.getLastEdited()); @@ -61,13 +61,13 @@ bool FlatImageEntity::setProperties(const EntityItemProperties& properties) { } // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time -EntityPropertyFlags FlatImageEntity::getEntityProperties(EncodeBitstreamParams& params) const { +EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); return requestedProperties; } -void FlatImageEntity::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, +void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, @@ -80,7 +80,7 @@ void FlatImageEntity::appendSubclassData(OctreePacketData* packetData, EncodeBit APPEND_ENTITY_PROPERTY(PROP_SHAPE, "Quad"); } -int FlatImageEntity::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, +int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) { @@ -91,7 +91,7 @@ int FlatImageEntity::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { +/*void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; if (value.y > MAX_FLAT_DIMENSION) { // enforce flatness in Y @@ -101,9 +101,23 @@ void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { } else { EntityItem::setUnscaledDimensions(value); } +}*/ + +void ImageEntityItem::setImageURL(const QString& value) { + withWriteLock([&] { + if (_imageURL != value) { + auto newURL = QUrl::fromUserInput(value); + + if (newURL.isValid()) { + _imageURL = newURL.toDisplayString(); + } else { + qCDebug(entities) << "Clearing image entity source URL since" << value << "cannot be parsed to a valid URL."; + } + } + }); } -QString FlatImageEntity::getImageURL() const { +QString ImageEntityItem::getImageURL() const { return resultWithReadLock([&] { return _imageURL; }); diff --git a/libraries/entities/src/FlatImageEntity.h b/libraries/entities/src/ImageEntityItem.h similarity index 85% rename from libraries/entities/src/FlatImageEntity.h rename to libraries/entities/src/ImageEntityItem.h index 4dd91b1215..55e8fc7b36 100644 --- a/libraries/entities/src/FlatImageEntity.h +++ b/libraries/entities/src/ImageEntityItem.h @@ -1,5 +1,5 @@ // -// FlatImageEntity.h +// ImageEntityItem.h // libraries/entities/src // // Created by Elisa Lupin-Jimenez on 1/3/18. @@ -9,16 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_FlatImageEntity_h -#define hifi_FlatImageEntity_h +#ifndef hifi_ImageEntityItem_h +#define hifi_ImageEntityItem_h #include "EntityItem.h" -class FlatImageEntity : public EntityItem { +class ImageEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - FlatImageEntity(const EntityItemID& entityItemID); + ImageEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated @@ -43,6 +43,7 @@ public: static const QString DEFAULT_IMAGE_URL; + virtual void setImageURL(const QString& value); QString getImageURL() const; protected: @@ -50,4 +51,4 @@ protected: }; -#endif // hifi_FlatImageEntity_h +#endif // hifi_ImageEntityItem_h diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 4241468de1..bcd39ab0a5 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -287,7 +287,7 @@ var toolBar = (function () { properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } }); } - print("properties.type: " + properties.type); + print("check 1 type: " + properties.type); entityID = Entities.addEntity(properties); if (properties.type === "ParticleEffect") { From 72d8f90ec1b8950dc06bacff76ff84c114df07f7 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 11 Jan 2018 14:43:19 -0800 Subject: [PATCH 070/272] not sure why entities don't render with these changes --- libraries/entities/src/EntityItemProperties.h | 1 + libraries/entities/src/EntityTypes.cpp | 2 +- libraries/entities/src/ImageEntityItem.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5bd6836336..e121332374 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -67,6 +67,7 @@ class EntityItemProperties { 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 ImageEntityItem; 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 diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 2e4a0e89a9..47ec408374 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -91,7 +91,7 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { - qCDebug(entities) << "check 4 type: " << entityType; + qCDebug(entities) << "check 4 type: " << entityType << ", name: " << properties.getName(); factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index a94374f7b5..2e6432ba19 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -24,7 +24,7 @@ #include "ShapeEntityItem.h" #include "ImageEntityItem.h" -const QString ImageEntityItem::DEFAULT_IMAGE_URL = QString(""); +const QString ImageEntityItem::DEFAULT_IMAGE_URL(""); EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity(new ImageEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); From 3d000d3d011396aee7ae664d8c64f7f2ffaf77d8 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 11 Jan 2018 16:11:01 -0800 Subject: [PATCH 071/272] changed packet number --- libraries/networking/src/udt/PacketHeaders.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index c48c6bfc0b..1ceb9b8e73 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -31,7 +31,6 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityData: case PacketType::EntityPhysics: return static_cast(EntityVersion::SoftEntities); - case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); case PacketType::AvatarIdentity: From 6f76650789ba9454e8d8634098e7519d1a3daa43 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 16 Jan 2018 12:17:39 -0800 Subject: [PATCH 072/272] updated with master --- libraries/entities/src/ImageEntityItem.cpp | 9 +++++++-- libraries/entities/src/ImageEntityItem.h | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index 2e6432ba19..41bd55ee85 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -38,6 +38,8 @@ ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem( EntityItemProperties ImageEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class + COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); + // Using "Quad" shape as defined in ShapeEntityItem.cpp properties.setShape("Quad"); return properties; } @@ -45,7 +47,7 @@ EntityItemProperties ImageEntityItem::getProperties(EntityPropertyFlags desiredP bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); if (somethingChanged) { bool wantDebug = false; @@ -63,7 +65,7 @@ bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { // TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - + requestedProperties += PROP_IMAGE_URL; return requestedProperties; } @@ -78,6 +80,7 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit bool successPropertyFits = true; // Using "Quad" shape as defined in ShapeEntityItem.cpp APPEND_ENTITY_PROPERTY(PROP_SHAPE, "Quad"); + APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, _imageURL); } int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, @@ -88,6 +91,8 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; + READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL); + return bytesRead; } diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h index 55e8fc7b36..229b6f190f 100644 --- a/libraries/entities/src/ImageEntityItem.h +++ b/libraries/entities/src/ImageEntityItem.h @@ -13,6 +13,7 @@ #define hifi_ImageEntityItem_h #include "EntityItem.h" +#include "ShapeEntityItem.h" class ImageEntityItem : public EntityItem { public: @@ -49,6 +50,9 @@ public: protected: QString _imageURL; + entity::Shape _shape{ entity::Shape::Quad }; + ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_BOX }; + }; #endif // hifi_ImageEntityItem_h From c9c55af66153882bc6fec49cbfd736b2d3308bf8 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 16 Jan 2018 17:37:49 -0800 Subject: [PATCH 073/272] setting up properties page (not complete) --- libraries/entities/src/ImageEntityItem.cpp | 16 +++++++++++++--- libraries/entities/src/ImageEntityItem.h | 4 ++++ scripts/system/html/entityProperties.html | 9 +++++++++ scripts/system/html/js/entityProperties.js | 11 +++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index 41bd55ee85..1a6ab1e146 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -79,7 +79,6 @@ void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit bool successPropertyFits = true; // Using "Quad" shape as defined in ShapeEntityItem.cpp - APPEND_ENTITY_PROPERTY(PROP_SHAPE, "Quad"); APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, _imageURL); } @@ -96,7 +95,7 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -/*void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { +void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; if (value.y > MAX_FLAT_DIMENSION) { // enforce flatness in Y @@ -106,7 +105,7 @@ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, } else { EntityItem::setUnscaledDimensions(value); } -}*/ +} void ImageEntityItem::setImageURL(const QString& value) { withWriteLock([&] { @@ -128,3 +127,14 @@ QString ImageEntityItem::getImageURL() const { }); } +/*void ImageEntityItem::computeShapeInfo(ShapeInfo& info) { + // This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc) + // is set. + + EntityItem::computeShapeInfo(info); +}*/ + +// This value specifies how the shape should be treated by physics calculations. +ShapeType ImageEntityItem::getShapeType() const { + return _collisionShapeType; +} diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h index 229b6f190f..f3f4fbe6c7 100644 --- a/libraries/entities/src/ImageEntityItem.h +++ b/libraries/entities/src/ImageEntityItem.h @@ -42,11 +42,15 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) override; + void setUnscaledDimensions(const glm::vec3& value) override; static const QString DEFAULT_IMAGE_URL; virtual void setImageURL(const QString& value); QString getImageURL() const; + //virtual void computeShapeInfo(ShapeInfo& info) override; + virtual ShapeType getShapeType() const override; + protected: QString _imageURL; diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index b93974ee77..6e8178d408 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -714,6 +714,15 @@ +
+ + ImageM + +
+ + +
+
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 7008d0df66..05a1b2576b 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -133,6 +133,11 @@ function createEmitGroupNumberPropertyUpdateFunction(group, propertyName) { }; } +function createImageURLUpdateFunction(propertyName) { + return function() { + updateProperty(propertyName, this.value); + } +} function createEmitTextPropertyUpdateFunction(propertyName) { return function() { @@ -621,6 +626,8 @@ function loaded() { var elModelTextures = document.getElementById("property-model-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures"); + var elImageURL = document.getElementById("property-image-url"); + var elWebSourceURL = document.getElementById("property-web-source-url"); var elWebDPI = document.getElementById("property-web-dpi"); @@ -985,6 +992,8 @@ function loaded() { } else if (properties.type === "Web") { elWebSourceURL.value = properties.sourceUrl; elWebDPI.value = properties.dpi; + } else if (properties.type === "Image") { + elImageURL.value = properties.imageURL; } else if (properties.type === "Text") { elTextText.value = properties.text; elTextLineHeight.value = properties.lineHeight.toFixed(4); @@ -1352,6 +1361,8 @@ function loaded() { elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape')); + elImageURL.addEventListener('change', createImageURLUpdateFunction('imageURL')); + elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi', 0)); From ecb53192add37a7bb70c88d2c00b6568aab0db7d Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 17 Jan 2018 11:57:40 -0800 Subject: [PATCH 074/272] edit properties reflect image members --- scripts/system/html/css/edit-style.css | 49 +++++++++++++++++++++- scripts/system/html/js/entityProperties.js | 7 ++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 736d42d593..58acc317bd 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, .image-section, .hyperlink-section, .text-section, .zone-section { display: table; } @@ -564,6 +564,7 @@ hr { .text-group[collapsed="true"] ~ .text-group, .zone-group[collapsed="true"] ~ .zone-group, +.image-group[collapsed="true"] ~ .image-group, .web-group[collapsed="true"] ~ .web-group, .hyperlink-group[collapsed="true"] ~ .hyperlink-group, .spatial-group[collapsed="true"] ~ .spatial-group, @@ -1466,6 +1467,9 @@ input#reset-to-natural-dimensions { #properties-list.ShapeMenu #text, #properties-list.BoxMenu #text, #properties-list.SphereMenu #text, +#properties-list.ShapeMenu #image, +#properties-list.BoxMenu #image, +#properties-list.SphereMenu #image, #properties-list.ShapeMenu #web, #properties-list.BoxMenu #web, #properties-list.SphereMenu #web { @@ -1497,6 +1501,7 @@ input#reset-to-natural-dimensions { #properties-list.ParticleEffectMenu #shape-list, #properties-list.ParticleEffectMenu #text, #properties-list.ParticleEffectMenu #web, +#properties-list.ParticleEffectMenu #image, #properties-list.ParticleEffectMenu #zone { display: none; } @@ -1527,6 +1532,7 @@ input#reset-to-natural-dimensions { #properties-list.LightMenu #model, #properties-list.LightMenu #zone, #properties-list.LightMenu #text, +#properties-list.LightMenu #image, #properties-list.LightMenu #web { display: none; } @@ -1563,6 +1569,7 @@ input#reset-to-natural-dimensions { #properties-list.ModelMenu #light, #properties-list.ModelMenu #zone, #properties-list.ModelMenu #text, +#properties-list.ModelMenu #image, #properties-list.ModelMenu #web { display: none; } @@ -1599,6 +1606,7 @@ input#reset-to-natural-dimensions { #properties-list.ZoneMenu #light, #properties-list.ZoneMenu #model, #properties-list.ZoneMenu #text, +#properties-list.ZoneMenu #image, #properties-list.ZoneMenu #web { display: none; } @@ -1609,6 +1617,43 @@ input#reset-to-natural-dimensions { } +/* ----- Order of Menu items for Image ----- */ +#properties-list.ImageMenu #general { + order: 1; +} +#properties-list.ImageMenu #image { + order: 2; +} +#properties-list.ImageMenu #collision-info { + order: 3; +} +#properties-list.ImageMenu #physical { + order: 4; +} +#properties-list.ImageMenu #spatial { + order: 5; +} +#properties-list.ImageMenu #behavior { + order: 6; +} +#properties-list.ImageMenu #hyperlink { + order: 7; +} +/* sections to hide */ +#properties-list.ImageMenu #light, +#properties-list.ImageMenu #model, +#properties-list.ImageMenu #zone, +#properties-list.ImageMenu #web, +#properties-list.ImageMenu #text { + display: none; +} +/* items to hide */ +#properties-list.ImageMenu #shape-list, +#properties-list.ImageMenu #base-color-section { + display: none; +} + + /* ----- Order of Menu items for Web ----- */ #properties-list.WebMenu #general { order: 1; @@ -1635,6 +1680,7 @@ input#reset-to-natural-dimensions { #properties-list.WebMenu #light, #properties-list.WebMenu #model, #properties-list.WebMenu #zone, +#properties-list.WebMenu #image, #properties-list.WebMenu #text { display: none; } @@ -1672,6 +1718,7 @@ input#reset-to-natural-dimensions { #properties-list.TextMenu #light, #properties-list.TextMenu #model, #properties-list.TextMenu #zone, +#properties-list.TextMenu #image, #properties-list.TextMenu #web { display: none; } diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 05a1b2576b..54b50de106 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -19,6 +19,7 @@ var ICON_FOR_TYPE = { ParticleEffect: "", Model: "", Web: "q", + Image: "q", // what do? Text: "l", Light: "p", Zone: "o", @@ -134,9 +135,9 @@ function createEmitGroupNumberPropertyUpdateFunction(group, propertyName) { } function createImageURLUpdateFunction(propertyName) { - return function() { + return function () { updateProperty(propertyName, this.value); - } + }; } function createEmitTextPropertyUpdateFunction(propertyName) { @@ -1735,7 +1736,7 @@ function loaded() { } // Dropdowns - // For each dropdown the following replacement is created in place of the oriringal dropdown... + // For each dropdown the following replacement is created in place of the original dropdown... // Structure created: //
//
display textcarat
From dc5f29aa58268a9abdc9b82f6a9bc41828c28832 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 17 Jan 2018 17:57:09 -0800 Subject: [PATCH 075/272] entity item properties hooked up for image --- libraries/entities/src/EntityItemProperties.cpp | 9 +++++++++ scripts/system/edit.js | 2 +- scripts/system/html/js/entityProperties.js | 3 ++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index fc8ca18fb6..3729c75f3d 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -350,6 +350,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); + CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); + CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData); @@ -785,6 +787,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData); @@ -945,6 +949,8 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); + COPY_PROPERTY_IF_CHANGED(imageURL); + COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); COPY_PROPERTY_IF_CHANGED(voxelData); @@ -1138,6 +1144,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); + ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); ADD_PROPERTY_TO_MAP(PROP_LINE_WIDTH, LineWidth, lineWidth, float); ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); @@ -2060,6 +2067,8 @@ void EntityItemProperties::markAllChanged() { _skybox.markAllChanged(); _haze.markAllChanged(); + _imageURLChanged = true; + _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; _voxelDataChanged = true; diff --git a/scripts/system/edit.js b/scripts/system/edit.js index bcd39ab0a5..5f976e07d3 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -546,7 +546,7 @@ var toolBar = (function () { createNewEntity({ type: "Image", dimensions: DEFAULT_DIMENSIONS, - sourceUrl: "https://highfidelity.com/" + imageURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }); }); diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 54b50de106..7c3af548ba 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -19,7 +19,7 @@ var ICON_FOR_TYPE = { ParticleEffect: "", Model: "", Web: "q", - Image: "q", // what do? + Image: "q", // change this when image type icon added Text: "l", Light: "p", Zone: "o", @@ -995,6 +995,7 @@ function loaded() { elWebDPI.value = properties.dpi; } else if (properties.type === "Image") { elImageURL.value = properties.imageURL; + //elImageURL.value = properties.sourceURL; } else if (properties.type === "Text") { elTextText.value = properties.text; elTextLineHeight.value = properties.lineHeight.toFixed(4); From 576d683d3bb62baef14c4ddc2f3696ca71679258 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 18 Jan 2018 14:40:33 -0800 Subject: [PATCH 076/272] initial changes to incorporate snap model --- libraries/entities/src/EntityScriptingInterface.cpp | 2 -- libraries/entities/src/EntityTree.cpp | 1 - libraries/entities/src/EntityTypes.cpp | 4 +++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index cab4251d97..4342f0e683 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -266,8 +266,6 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties bool success = true; if (_entityTree) { _entityTree->withWriteLock([&] { - propertiesWithSimID.getType(); - qCDebug(entities) << "check 2 type: " << propertiesWithSimID.getType(); EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID); if (entity) { if (propertiesWithSimID.queryAACubeRelatedPropertyChanged()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 56c3aa216c..bf29f3bec9 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -514,7 +514,6 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti // construct the instance of the entity EntityTypes::EntityType type = props.getType(); - qCDebug(entities) << "check 3 type: " << type; result = EntityTypes::constructEntityItem(type, entityID, props); if (result) { diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 47ec408374..6326df3cc1 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -91,7 +91,9 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { - qCDebug(entities) << "check 4 type: " << entityType << ", name: " << properties.getName(); + if (getEntityTypeName(entityType) == "Image") { + entityType = getEntityTypeFromName("Web"); + } factory = _factories[entityType]; } if (factory) { From ceb621a52151d20bfa66dd4eb09779c45f003901 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Mon, 22 Jan 2018 11:36:58 -0800 Subject: [PATCH 077/272] reverted protocol change for images --- libraries/entities/src/EntityItemProperties.cpp | 16 ++++++++-------- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/EntityPropertyFlags.h | 4 ++-- libraries/entities/src/EntityTypes.cpp | 7 ++----- libraries/entities/src/EntityTypes.h | 2 +- libraries/entities/src/ImageEntityItem.cpp | 8 ++++++-- libraries/entities/src/ImageEntityItem.h | 4 ++++ scripts/system/edit.js | 10 +++++++++- 8 files changed, 33 insertions(+), 20 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 3729c75f3d..48ad9601ba 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -350,7 +350,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); - CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); + //CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); @@ -593,9 +593,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool } // Image only - if (_type == EntityTypes::Image) { + /*if (_type == EntityTypes::Image) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); - } + }*/ // Web only if (_type == EntityTypes::Web) { @@ -1144,7 +1144,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); - ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); + //ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); ADD_PROPERTY_TO_MAP(PROP_LINE_WIDTH, LineWidth, lineWidth, float); ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); @@ -1381,9 +1381,9 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI()); } - if (properties.getType() == EntityTypes::Image) { + /*if (properties.getType() == EntityTypes::Image) { APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); - } + }*/ if (properties.getType() == EntityTypes::Text) { APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); @@ -1746,9 +1746,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI); } - if (properties.getType() == EntityTypes::Image) { + /*if (properties.getType() == EntityTypes::Image) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); - } + }*/ if (properties.getType() == EntityTypes::Text) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index e121332374..14544cd4d1 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -67,7 +67,7 @@ class EntityItemProperties { 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 ImageEntityItem; + //friend class ImageEntityItem; 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 diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 4768ebed86..ec8f4e08c8 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -42,8 +42,8 @@ enum EntityPropertyList { PROP_ANIMATION_ALLOW_TRANSLATION, PROP_RELAY_PARENT_JOINTS, - // for image - PROP_IMAGE_URL, + /*// for image + PROP_IMAGE_URL,*/ // these properties are supported by the EntityItem base class PROP_REGISTRATION_POINT, diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 6326df3cc1..6bf5a176a7 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -28,7 +28,7 @@ #include "LineEntityItem.h" #include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" -#include "ImageEntityItem.h" +//#include "ImageEntityItem.h" #include "ShapeEntityItem.h" QMap EntityTypes::_typeToNameMap; @@ -48,7 +48,7 @@ REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyVox) REGISTER_ENTITY_TYPE(PolyLine) -REGISTER_ENTITY_TYPE(Image) +//REGISTER_ENTITY_TYPE(Image) REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) @@ -91,9 +91,6 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer newEntityItem = NULL; EntityTypeFactory factory = NULL; if (entityType >= 0 && entityType <= LAST) { - if (getEntityTypeName(entityType) == "Image") { - entityType = getEntityTypeFromName("Web"); - } factory = _factories[entityType]; } if (factory) { diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 8d986c8090..6fe4274820 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -48,7 +48,7 @@ public: Line, PolyVox, PolyLine, - Image, + //Image, Shape, LAST = Shape } EntityType; diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index 1a6ab1e146..e30d85257e 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* NOT IN USE + #include #include @@ -127,14 +129,16 @@ QString ImageEntityItem::getImageURL() const { }); } -/*void ImageEntityItem::computeShapeInfo(ShapeInfo& info) { +void ImageEntityItem::computeShapeInfo(ShapeInfo& info) { // This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc) // is set. EntityItem::computeShapeInfo(info); -}*/ +} // This value specifies how the shape should be treated by physics calculations. ShapeType ImageEntityItem::getShapeType() const { return _collisionShapeType; } + +*/ diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h index f3f4fbe6c7..276d21e6f0 100644 --- a/libraries/entities/src/ImageEntityItem.h +++ b/libraries/entities/src/ImageEntityItem.h @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* NOT IN USE + #ifndef hifi_ImageEntityItem_h #define hifi_ImageEntityItem_h @@ -60,3 +62,5 @@ protected: }; #endif // hifi_ImageEntityItem_h + +*/ diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 5f976e07d3..1d02fed787 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -540,7 +540,7 @@ var toolBar = (function () { }); }); - // for image button + /*// for image button addButton("newImageButton", "web-01.svg", function () { print("new image message is received"); createNewEntity({ @@ -548,6 +548,14 @@ var toolBar = (function () { dimensions: DEFAULT_DIMENSIONS, imageURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }); + });*/ + addButton("newImageButton", "web-01.svg", function () { + createNewEntity({ + type: "Model", + dimensions: DEFAULT_DIMENSIONS, + modelURL: "http://hifi-content.s3.amazonaws.com/alan/dev/Test/snapshot.fbx", + textures: JSON.stringify({ "tex.picture": "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }) + }); }); addButton("newWebButton", "web-01.svg", function () { From 308e481e63f5d19db4f8548c3a8689d60a22958f Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Mon, 22 Jan 2018 17:46:12 -0800 Subject: [PATCH 078/272] switch to image property list not working --- scripts/system/edit.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1d02fed787..6f48e1167a 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -252,7 +252,7 @@ var toolBar = (function () { properties.rotation = MyAvatar.orientation; // added image here - var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web"]; + var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. @@ -287,7 +287,6 @@ var toolBar = (function () { properties.userData = JSON.stringify({ grabbableKey: { grabbable: false } }); } - print("check 1 type: " + properties.type); entityID = Entities.addEntity(properties); if (properties.type === "ParticleEffect") { @@ -540,20 +539,21 @@ var toolBar = (function () { }); }); - /*// for image button - addButton("newImageButton", "web-01.svg", function () { - print("new image message is received"); - createNewEntity({ - type: "Image", - dimensions: DEFAULT_DIMENSIONS, - imageURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" - }); - });*/ addButton("newImageButton", "web-01.svg", function () { createNewEntity({ type: "Model", - dimensions: DEFAULT_DIMENSIONS, + // make constant for this later + dimensions: { + x: 4.16, + y: 0.02, + z: 2.58 + }, modelURL: "http://hifi-content.s3.amazonaws.com/alan/dev/Test/snapshot.fbx", + imageURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg", + // will this work? + /*get textures() { + return JSON.stringify({ "tex.picture": this.imageURL }); + }*/ textures: JSON.stringify({ "tex.picture": "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }) }); }); From 42151b8fd47f6b32d3662d9d599096ec4d290408 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 23 Jan 2018 14:50:41 -0800 Subject: [PATCH 079/272] creating new image entity opens image property options --- .../entities/src/EntityItemProperties.cpp | 12 +- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/ImageEntityItem.cpp | 2 +- scripts/system/edit.js | 6 +- scripts/system/html/js/entityProperties.js | 123 ++++++++++++++++++ 5 files changed, 136 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 48ad9601ba..7fcfc00ee8 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -592,8 +592,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); } - // Image only - /*if (_type == EntityTypes::Image) { + + + /*// Image only + if (_type == EntityTypes::Image) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); }*/ @@ -787,7 +789,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); + //COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize); @@ -949,7 +951,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); - COPY_PROPERTY_IF_CHANGED(imageURL); + //COPY_PROPERTY_IF_CHANGED(imageURL); COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); @@ -2067,7 +2069,7 @@ void EntityItemProperties::markAllChanged() { _skybox.markAllChanged(); _haze.markAllChanged(); - _imageURLChanged = true; + //_imageURLChanged = true; _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 14544cd4d1..5ca28a12c5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -195,7 +195,7 @@ public: DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); - DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); + //DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp index e30d85257e..9969a39ed0 100644 --- a/libraries/entities/src/ImageEntityItem.cpp +++ b/libraries/entities/src/ImageEntityItem.cpp @@ -35,7 +35,7 @@ EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const E } ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Image; + //_type = EntityTypes::Image; } EntityItemProperties ImageEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 6f48e1167a..a5c236a6c9 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -253,6 +253,8 @@ var toolBar = (function () { // added image here var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; + //var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web"]; + if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { // Adjust position of entity per bounding box prior to creating it. @@ -539,6 +541,7 @@ var toolBar = (function () { }); }); + // for image button addButton("newImageButton", "web-01.svg", function () { createNewEntity({ type: "Model", @@ -548,8 +551,7 @@ var toolBar = (function () { y: 0.02, z: 2.58 }, - modelURL: "http://hifi-content.s3.amazonaws.com/alan/dev/Test/snapshot.fbx", - imageURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg", + modelURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx", // will this work? /*get textures() { return JSON.stringify({ "tex.picture": this.imageURL }); diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 7c3af548ba..2b90f8ddfa 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -511,6 +511,10 @@ function loaded() { var elPropertiesList = document.getElementById("properties-list"); var elID = document.getElementById("property-id"); var elType = document.getElementById("property-type"); +<<<<<<< HEAD +======= + debugPrint("the type is: " + JSON.stringify(elType)); +>>>>>>> creating new image entity opens image property options var elTypeIcon = document.getElementById("type-icon"); var elName = document.getElementById("property-name"); var elLocked = document.getElementById("property-locked"); @@ -661,16 +665,28 @@ function loaded() { var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); // Skybox +<<<<<<< HEAD var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); +======= + var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); + var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); + var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); +>>>>>>> creating new image entity opens image property options // Ambient light var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url"); +<<<<<<< HEAD var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled"); var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); +======= + var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); + var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled"); + var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); +>>>>>>> creating new image entity opens image property options var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity"); var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url"); @@ -787,7 +803,11 @@ function loaded() { } else { properties = data.selections[0].properties; +<<<<<<< HEAD +======= + debugPrint("props: " + JSON.stringify(properties)); +>>>>>>> creating new image entity opens image property options if (lastEntityID !== '"' + properties.id + '"' && lastEntityID !== null && editor !== null) { saveJSONUserData(true); } @@ -796,6 +816,14 @@ function loaded() { lastEntityID = '"' + properties.id + '"'; elID.value = properties.id; +<<<<<<< HEAD +======= + // image is not yet a separate entity type + if (properties.type === "Model" && properties.modelURL === "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx") { + properties.type = "Image"; + } + +>>>>>>> creating new image entity opens image property options // Create class name for css ruleset filtering elPropertiesList.className = properties.type + 'Menu'; @@ -1024,9 +1052,15 @@ function loaded() { } else if (properties.type === "Zone") { // Key light +<<<<<<< HEAD elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled'); elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); +======= + elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); + elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled'); + elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); +>>>>>>> creating new image entity opens image property options elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," + properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")"; @@ -1038,6 +1072,7 @@ function loaded() { elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2); // Skybox +<<<<<<< HEAD elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); @@ -1046,14 +1081,30 @@ function loaded() { elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled'); elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); +======= + elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); + elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); + elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); + + // Ambient light + elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); + elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled'); + elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); +>>>>>>> creating new image entity opens image property options elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2); elZoneAmbientLightURL.value = properties.ambientLight.ambientURL; // Haze +<<<<<<< HEAD elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled'); elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); +======= + elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); + elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled'); + elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); +>>>>>>> creating new image entity opens image property options elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0); elZoneHazeColor.style.backgroundColor = "rgb(" + @@ -1319,15 +1370,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-color-control2').attr('active', 'true'); }, onHide: function(colpick) { $('#property-color-control2').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1343,15 +1403,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-light-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1400,15 +1469,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-text-text-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-text-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options $(el).attr('active', 'false'); emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b); } @@ -1424,15 +1502,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-text-background-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-background-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b); } })); @@ -1449,15 +1536,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-key-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-key-light-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight'); } })); @@ -1518,15 +1614,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-haze-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1543,15 +1648,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1585,15 +1699,24 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', +<<<<<<< HEAD submit: false, // We don't want to have a submission button +======= +>>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-skybox-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-skybox-color').attr('active', 'false'); }, +<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); +======= + onSubmit: function(hsb, hex, rgb, el) { + $(el).css('background-color', '#' + hex); + $(el).colpickHide(); +>>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); } })); From fe3bc00baa0cb1bcaaa3090e5ca3e438ba47874a Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 23 Jan 2018 16:45:54 -0800 Subject: [PATCH 080/272] loading and rendering atp and http image files --- scripts/system/html/js/entityProperties.js | 131 ++------------------- 1 file changed, 7 insertions(+), 124 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 2b90f8ddfa..e7526fa2e0 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -136,7 +136,8 @@ function createEmitGroupNumberPropertyUpdateFunction(group, propertyName) { function createImageURLUpdateFunction(propertyName) { return function () { - updateProperty(propertyName, this.value); + var newTextures = JSON.stringify({ "tex.picture": this.value }); + updateProperty(propertyName, newTextures); }; } @@ -511,10 +512,6 @@ function loaded() { var elPropertiesList = document.getElementById("properties-list"); var elID = document.getElementById("property-id"); var elType = document.getElementById("property-type"); -<<<<<<< HEAD -======= - debugPrint("the type is: " + JSON.stringify(elType)); ->>>>>>> creating new image entity opens image property options var elTypeIcon = document.getElementById("type-icon"); var elName = document.getElementById("property-name"); var elLocked = document.getElementById("property-locked"); @@ -665,28 +662,16 @@ function loaded() { var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); // Skybox -<<<<<<< HEAD var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); -======= - var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); - var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); - var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); ->>>>>>> creating new image entity opens image property options // Ambient light var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url"); -<<<<<<< HEAD var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled"); var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); -======= - var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); - var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled"); - var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); ->>>>>>> creating new image entity opens image property options var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity"); var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url"); @@ -803,11 +788,6 @@ function loaded() { } else { properties = data.selections[0].properties; -<<<<<<< HEAD - -======= - debugPrint("props: " + JSON.stringify(properties)); ->>>>>>> creating new image entity opens image property options if (lastEntityID !== '"' + properties.id + '"' && lastEntityID !== null && editor !== null) { saveJSONUserData(true); } @@ -816,14 +796,11 @@ function loaded() { lastEntityID = '"' + properties.id + '"'; elID.value = properties.id; -<<<<<<< HEAD -======= - // image is not yet a separate entity type + // HTML workaround since image is not yet a separate entity type if (properties.type === "Model" && properties.modelURL === "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx") { properties.type = "Image"; } ->>>>>>> creating new image entity opens image property options // Create class name for css ruleset filtering elPropertiesList.className = properties.type + 'Menu'; @@ -1022,8 +999,9 @@ function loaded() { elWebSourceURL.value = properties.sourceUrl; elWebDPI.value = properties.dpi; } else if (properties.type === "Image") { - elImageURL.value = properties.imageURL; - //elImageURL.value = properties.sourceURL; + var imageLink = JSON.parse(properties.textures)["tex.picture"]; + debugPrint("image url is: " + imageLink); + elImageURL.value = imageLink; } else if (properties.type === "Text") { elTextText.value = properties.text; elTextLineHeight.value = properties.lineHeight.toFixed(4); @@ -1052,15 +1030,9 @@ function loaded() { } else if (properties.type === "Zone") { // Key light -<<<<<<< HEAD elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled'); elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); -======= - elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); - elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled'); - elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); ->>>>>>> creating new image entity opens image property options elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," + properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")"; @@ -1072,7 +1044,6 @@ function loaded() { elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2); // Skybox -<<<<<<< HEAD elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); @@ -1081,30 +1052,14 @@ function loaded() { elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled'); elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); -======= - elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); - elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); - elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); - - // Ambient light - elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); - elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled'); - elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); ->>>>>>> creating new image entity opens image property options elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2); elZoneAmbientLightURL.value = properties.ambientLight.ambientURL; // Haze -<<<<<<< HEAD elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled'); elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); -======= - elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); - elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled'); - elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); ->>>>>>> creating new image entity opens image property options elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0); elZoneHazeColor.style.backgroundColor = "rgb(" + @@ -1370,24 +1325,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-color-control2').attr('active', 'true'); }, onHide: function(colpick) { $('#property-color-control2').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1403,24 +1349,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-light-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1432,7 +1369,7 @@ function loaded() { elShape.addEventListener('change', createEmitTextPropertyUpdateFunction('shape')); - elImageURL.addEventListener('change', createImageURLUpdateFunction('imageURL')); + elImageURL.addEventListener('change', createImageURLUpdateFunction('textures')); elWebSourceURL.addEventListener('change', createEmitTextPropertyUpdateFunction('sourceUrl')); elWebDPI.addEventListener('change', createEmitNumberPropertyUpdateFunction('dpi', 0)); @@ -1469,24 +1406,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-text-text-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-text-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options $(el).attr('active', 'false'); emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b); } @@ -1502,24 +1430,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-text-background-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-background-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b); } })); @@ -1536,24 +1455,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-key-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-key-light-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight'); } })); @@ -1614,24 +1524,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-haze-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1648,24 +1549,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1699,24 +1591,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', -<<<<<<< HEAD submit: false, // We don't want to have a submission button -======= ->>>>>>> creating new image entity opens image property options onShow: function(colpick) { $('#property-zone-skybox-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-skybox-color').attr('active', 'false'); }, -<<<<<<< HEAD onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); -======= - onSubmit: function(hsb, hex, rgb, el) { - $(el).css('background-color', '#' + hex); - $(el).colpickHide(); ->>>>>>> creating new image entity opens image property options emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); } })); From d390e20139efdd55dea99abe44959bbf2e203a46 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 24 Jan 2018 11:31:47 -0800 Subject: [PATCH 081/272] removed extraneous commenting and image class --- .../resources/qml/hifi/tablet/EditTabView.qml | 1 - .../entities/src/EntityItemProperties.cpp | 24 --- libraries/entities/src/EntityItemProperties.h | 2 - libraries/entities/src/EntityPropertyFlags.h | 3 - libraries/entities/src/EntityTypes.cpp | 2 - libraries/entities/src/EntityTypes.h | 1 - libraries/entities/src/ImageEntityItem.cpp | 144 ------------------ libraries/entities/src/ImageEntityItem.h | 66 -------- scripts/system/edit.js | 9 +- scripts/system/html/js/entityProperties.js | 1 - 10 files changed, 1 insertion(+), 252 deletions(-) delete mode 100644 libraries/entities/src/ImageEntityItem.cpp delete mode 100644 libraries/entities/src/ImageEntityItem.h diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 482469d355..ea5762d00a 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -101,7 +101,6 @@ TabView { } } - // for image NewEntityButton { icon: "icons/create-icons/25-web-1-01.svg" text: "IMAGE" diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 7fcfc00ee8..e2a5ddf8b5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -350,8 +350,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); - //CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); - CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData); @@ -592,13 +590,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); } - - - /*// Image only - if (_type == EntityTypes::Image) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IMAGE_URL, imageURL); - }*/ - // Web only if (_type == EntityTypes::Web) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SOURCE_URL, sourceUrl); @@ -789,8 +780,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); - //COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData); @@ -951,8 +940,6 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(skyboxMode); - //COPY_PROPERTY_IF_CHANGED(imageURL); - COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); COPY_PROPERTY_IF_CHANGED(voxelData); @@ -1146,7 +1133,6 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); - //ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); ADD_PROPERTY_TO_MAP(PROP_LINE_WIDTH, LineWidth, lineWidth, float); ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); @@ -1383,10 +1369,6 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI()); } - /*if (properties.getType() == EntityTypes::Image) { - APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); - }*/ - if (properties.getType() == EntityTypes::Text) { APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); @@ -1748,10 +1730,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI); } - /*if (properties.getType() == EntityTypes::Image) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); - }*/ - if (properties.getType() == EntityTypes::Text) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); @@ -2069,8 +2047,6 @@ void EntityItemProperties::markAllChanged() { _skybox.markAllChanged(); _haze.markAllChanged(); - //_imageURLChanged = true; - _sourceUrlChanged = true; _voxelVolumeSizeChanged = true; _voxelDataChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5ca28a12c5..3e0770f386 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -67,7 +67,6 @@ class EntityItemProperties { 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 ImageEntityItem; 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 @@ -195,7 +194,6 @@ public: DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); - //DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector, QVector()); DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index ec8f4e08c8..90438ab01c 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -42,9 +42,6 @@ enum EntityPropertyList { PROP_ANIMATION_ALLOW_TRANSLATION, PROP_RELAY_PARENT_JOINTS, - /*// for image - PROP_IMAGE_URL,*/ - // these properties are supported by the EntityItem base class PROP_REGISTRATION_POINT, PROP_ANGULAR_VELOCITY, diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 6bf5a176a7..cb17c28fd7 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -28,7 +28,6 @@ #include "LineEntityItem.h" #include "PolyVoxEntityItem.h" #include "PolyLineEntityItem.h" -//#include "ImageEntityItem.h" #include "ShapeEntityItem.h" QMap EntityTypes::_typeToNameMap; @@ -48,7 +47,6 @@ REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyVox) REGISTER_ENTITY_TYPE(PolyLine) -//REGISTER_ENTITY_TYPE(Image) REGISTER_ENTITY_TYPE(Shape) REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory) diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 6fe4274820..316bf2b813 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -48,7 +48,6 @@ public: Line, PolyVox, PolyLine, - //Image, Shape, LAST = Shape } EntityType; diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp deleted file mode 100644 index 9969a39ed0..0000000000 --- a/libraries/entities/src/ImageEntityItem.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// -// ImageEntityItem.cpp -// libraries/entities/src -// -// Created by Elisa Lupin-Jimenez on 1/3/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 -// - -/* NOT IN USE - -#include - -#include -#include -#include -#include - -#include "EntitiesLogging.h" -#include "EntityItemProperties.h" -#include "EntityTree.h" -#include "EntityTreeElement.h" -#include "ResourceCache.h" -#include "ShapeEntityItem.h" -#include "ImageEntityItem.h" - -const QString ImageEntityItem::DEFAULT_IMAGE_URL(""); - -EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer entity(new ImageEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - //_type = EntityTypes::Image; -} - -EntityItemProperties ImageEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); - // Using "Quad" shape as defined in ShapeEntityItem.cpp - properties.setShape("Quad"); - return properties; -} - -bool ImageEntityItem::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); - - if (somethingChanged) { - bool wantDebug = false; - if (wantDebug) { - uint64_t now = usecTimestampNow(); - int elapsed = now - getLastEdited(); - qCDebug(entities) << "ImageEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << - "now=" << now << " getLastEdited()=" << getLastEdited(); - } - setLastEdited(properties.getLastEdited()); - } - return somethingChanged; -} - -// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time -EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_IMAGE_URL; - return requestedProperties; -} - -void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - // Using "Quad" shape as defined in ShapeEntityItem.cpp - APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, _imageURL); -} - -int ImageEntityItem::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_IMAGE_URL, QString, setImageURL); - - return bytesRead; -} - -void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float MAX_FLAT_DIMENSION = 0.0001f; - if (value.y > MAX_FLAT_DIMENSION) { - // enforce flatness in Y - glm::vec3 newDimensions = value; - newDimensions.y = MAX_FLAT_DIMENSION; - EntityItem::setUnscaledDimensions(newDimensions); - } else { - EntityItem::setUnscaledDimensions(value); - } -} - -void ImageEntityItem::setImageURL(const QString& value) { - withWriteLock([&] { - if (_imageURL != value) { - auto newURL = QUrl::fromUserInput(value); - - if (newURL.isValid()) { - _imageURL = newURL.toDisplayString(); - } else { - qCDebug(entities) << "Clearing image entity source URL since" << value << "cannot be parsed to a valid URL."; - } - } - }); -} - -QString ImageEntityItem::getImageURL() const { - return resultWithReadLock([&] { - return _imageURL; - }); -} - -void ImageEntityItem::computeShapeInfo(ShapeInfo& info) { - // This will be called whenever DIRTY_SHAPE flag (set by dimension change, etc) - // is set. - - EntityItem::computeShapeInfo(info); -} - -// This value specifies how the shape should be treated by physics calculations. -ShapeType ImageEntityItem::getShapeType() const { - return _collisionShapeType; -} - -*/ diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h deleted file mode 100644 index 276d21e6f0..0000000000 --- a/libraries/entities/src/ImageEntityItem.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// ImageEntityItem.h -// libraries/entities/src -// -// Created by Elisa Lupin-Jimenez on 1/3/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 -// - -/* NOT IN USE - -#ifndef hifi_ImageEntityItem_h -#define hifi_ImageEntityItem_h - -#include "EntityItem.h" -#include "ShapeEntityItem.h" - -class ImageEntityItem : public EntityItem { -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - ImageEntityItem(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; - - 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; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; - - void setUnscaledDimensions(const glm::vec3& value) override; - - static const QString DEFAULT_IMAGE_URL; - virtual void setImageURL(const QString& value); - QString getImageURL() const; - - //virtual void computeShapeInfo(ShapeInfo& info) override; - virtual ShapeType getShapeType() const override; - -protected: - QString _imageURL; - - entity::Shape _shape{ entity::Shape::Quad }; - ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_BOX }; - -}; - -#endif // hifi_ImageEntityItem_h - -*/ diff --git a/scripts/system/edit.js b/scripts/system/edit.js index a5c236a6c9..20425c7ea6 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -251,9 +251,7 @@ var toolBar = (function () { // Align entity with Avatar orientation. properties.rotation = MyAvatar.orientation; - // added image here var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"]; - //var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Image", "Web"]; if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) { @@ -541,21 +539,16 @@ var toolBar = (function () { }); }); - // for image button addButton("newImageButton", "web-01.svg", function () { createNewEntity({ type: "Model", - // make constant for this later dimensions: { x: 4.16, y: 0.02, z: 2.58 }, modelURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx", - // will this work? - /*get textures() { - return JSON.stringify({ "tex.picture": this.imageURL }); - }*/ + // change to another default image textures: JSON.stringify({ "tex.picture": "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }) }); }); diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index e7526fa2e0..59b54b1020 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1000,7 +1000,6 @@ function loaded() { elWebDPI.value = properties.dpi; } else if (properties.type === "Image") { var imageLink = JSON.parse(properties.textures)["tex.picture"]; - debugPrint("image url is: " + imageLink); elImageURL.value = imageLink; } else if (properties.type === "Text") { elTextText.value = properties.text; From bd7204e6efd507be41c4a45d3ec4e21d61d44db2 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 24 Jan 2018 12:01:59 -0800 Subject: [PATCH 082/272] image entity now has grabbable and dynamic options --- scripts/system/edit.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 20425c7ea6..c298da38bc 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -547,6 +547,7 @@ var toolBar = (function () { y: 0.02, z: 2.58 }, + shapeType: "box", modelURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx", // change to another default image textures: JSON.stringify({ "tex.picture": "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }) From 2ff47fa454b494ce64d2afa7e4396f0233e32ea7 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 25 Jan 2018 14:39:45 -0800 Subject: [PATCH 083/272] images auto-add to asset server, started asset browser add link --- interface/resources/qml/hifi/AssetServer.qml | 3 +- interface/src/Application.cpp | 42 ++++++++++++++++---- interface/src/Application.h | 1 + 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 37c3c2adab..6a4e703413 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -142,8 +142,9 @@ Windows.ScrollingWindow { }); } + // Elisa note - need to link this with specific add entity call function canAddToWorld(path) { - var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; + var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; if (selectedItems > 1) { return false; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 99bd4d5758..b53ba61e61 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -335,15 +335,17 @@ static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; // we will never drop below the 'min' value static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; -static const QString SNAPSHOT_EXTENSION = ".jpg"; -static const QString SVO_EXTENSION = ".svo"; +static const QString SNAPSHOT_EXTENSION = ".jpg"; +static const QString JPG_EXTENSION = ".jpg"; +static const QString PNG_EXTENSION = ".png"; +static const QString SVO_EXTENSION = ".svo"; static const QString SVO_JSON_EXTENSION = ".svo.json"; static const QString JSON_GZ_EXTENSION = ".json.gz"; static const QString JSON_EXTENSION = ".json"; -static const QString JS_EXTENSION = ".js"; -static const QString FST_EXTENSION = ".fst"; -static const QString FBX_EXTENSION = ".fbx"; -static const QString OBJ_EXTENSION = ".obj"; +static const QString JS_EXTENSION = ".js"; +static const QString FST_EXTENSION = ".fst"; +static const QString FBX_EXTENSION = ".fbx"; +static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString ZIP_EXTENSION = ".zip"; @@ -382,7 +384,9 @@ const QHash Application::_acceptedExtensi { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, - { ZIP_EXTENSION, &Application::importFromZIP } + { ZIP_EXTENSION, &Application::importFromZIP }, + { JPG_EXTENSION, &Application::importImage }, + { PNG_EXTENSION, &Application::importImage } }; class DeadlockWatchdogThread : public QThread { @@ -2899,6 +2903,27 @@ bool Application::importFromZIP(const QString& filePath) { return true; } +bool Application::importImage(const QString& urlString) { + qCDebug(interfaceapp) << "dragged image"; + QString filepath(urlString); + filepath.remove("file:///"); + //<> + addAssetToWorld(filepath, "", false, false); + //emit uploadRequest(urlString); + /*auto upload = DependencyManager::get()->createUpload(urlString); + QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { + if (upload->getError() != AssetUpload::NoError) { + QString errorInfo = "Could not upload model to the Asset Server."; + qWarning(interfaceapp) << "Error downloading model: " + errorInfo; + //addAssetToWorldError(filenameFromPath(urlString), errorInfo); + } else { + //addAssetToWorldSetMapping(urlString, QString("/" + filenameFromPath(urlString)), hash); + } + upload->deleteLater(); + });*/ + return true; +} + // thread-safe void Application::onPresent(quint32 frameCount) { bool expected = false; @@ -6403,6 +6428,7 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString filename = filenameFromPath(path); + qCDebug(interfaceapp) << "Filename is: " << filename; if (isZip || isBlocks) { QString assetName = zipFile.section("/", -1).remove(QRegExp("[.]zip(.*)$")); QString assetFolder = path.section("model_repo/", -1); @@ -6425,6 +6451,8 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo } void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) { + qCDebug(interfaceapp) << "mapping request is: " << mapping; + qCDebug(interfaceapp) << "file is located: " << filePath; auto request = DependencyManager::get()->createGetMappingRequest(mapping); QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable { diff --git a/interface/src/Application.h b/interface/src/Application.h index ddb8ce11e5..0e9bf95081 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -469,6 +469,7 @@ private: bool importJSONFromURL(const QString& urlString); bool importSVOFromURL(const QString& urlString); bool importFromZIP(const QString& filePath); + bool importImage(const QString& urlString); bool nearbyEntitiesAreReadyForPhysics(); int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); From 62437dcc2265886c5d0fb7349c4625d4e68d18d7 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Thu, 25 Jan 2018 15:26:26 -0800 Subject: [PATCH 084/272] drag and drop works --- interface/src/Application.cpp | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b53ba61e61..b203487547 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2904,23 +2904,10 @@ bool Application::importFromZIP(const QString& filePath) { } bool Application::importImage(const QString& urlString) { - qCDebug(interfaceapp) << "dragged image"; + qCDebug(interfaceapp) << "An image file has been dropped in"; QString filepath(urlString); filepath.remove("file:///"); - //<> addAssetToWorld(filepath, "", false, false); - //emit uploadRequest(urlString); - /*auto upload = DependencyManager::get()->createUpload(urlString); - QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { - if (upload->getError() != AssetUpload::NoError) { - QString errorInfo = "Could not upload model to the Asset Server."; - qWarning(interfaceapp) << "Error downloading model: " + errorInfo; - //addAssetToWorldError(filenameFromPath(urlString), errorInfo); - } else { - //addAssetToWorldSetMapping(urlString, QString("/" + filenameFromPath(urlString)), hash); - } - upload->deleteLater(); - });*/ return true; } @@ -6428,7 +6415,6 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget(). QString mapping; QString filename = filenameFromPath(path); - qCDebug(interfaceapp) << "Filename is: " << filename; if (isZip || isBlocks) { QString assetName = zipFile.section("/", -1).remove(QRegExp("[.]zip(.*)$")); QString assetFolder = path.section("model_repo/", -1); @@ -6451,8 +6437,6 @@ void Application::addAssetToWorld(QString path, QString zipFile, bool isZip, boo } void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) { - qCDebug(interfaceapp) << "mapping request is: " << mapping; - qCDebug(interfaceapp) << "file is located: " << filePath; auto request = DependencyManager::get()->createGetMappingRequest(mapping); QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable { @@ -6519,7 +6503,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // to prevent files that aren't models from being loaded into world automatically - if (filePath.endsWith(".obj") || filePath.endsWith(".fbx")) { + if (filePath.endsWith(OBJ_EXTENSION) || filePath.endsWith(FBX_EXTENSION) || + filePath.endsWith(JPG_EXTENSION) || filePath.endsWith(PNG_EXTENSION)) { addAssetToWorldAddEntity(filePath, mapping); } else { qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; @@ -6536,8 +6521,17 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { EntityItemProperties properties; properties.setType(EntityTypes::Model); properties.setName(mapping.right(mapping.length() - 1)); - properties.setModelURL("atp:" + mapping); - properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); + if (filePath.endsWith(PNG_EXTENSION) || filePath.endsWith(JPG_EXTENSION)) { + QJsonObject textures { + {"tex.picture", QString("atp:" + mapping) } + }; + properties.setModelURL("https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"); + properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); + properties.setShapeType(SHAPE_TYPE_BOX); + } else { + properties.setModelURL("atp:" + mapping); + properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); + } properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. glm::vec3 positionOffset = getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); From 9f8e2017ceab378aec06a75c6f447317f68b1e32 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Fri, 26 Jan 2018 14:39:04 -0800 Subject: [PATCH 085/272] can add image directly from asset server --- interface/resources/qml/hifi/AssetServer.qml | 167 ++++++++++-------- .../qml/hifi/dialogs/TabletAssetServer.qml | 167 ++++++++++-------- .../entities/src/EntityScriptingInterface.cpp | 5 +- .../entities/src/EntityScriptingInterface.h | 2 +- 4 files changed, 183 insertions(+), 158 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 6a4e703413..04fceec1f3 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -182,92 +182,103 @@ Windows.ScrollingWindow { return; } - var SHAPE_TYPE_NONE = 0; - var SHAPE_TYPE_SIMPLE_HULL = 1; - var SHAPE_TYPE_SIMPLE_COMPOUND = 2; - var SHAPE_TYPE_STATIC_MESH = 3; - var SHAPE_TYPE_BOX = 4; - var SHAPE_TYPE_SPHERE = 5; + if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { + var name = assetProxyModel.data(treeView.selection.currentIndex); + var modelURL = "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"; + var textures = JSON.stringify({ "tex.picture": defaultURL}); + var shapeType = "box"; + var dynamic = false; + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); + var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); + } else { + var SHAPE_TYPE_NONE = 0; + var SHAPE_TYPE_SIMPLE_HULL = 1; + var SHAPE_TYPE_SIMPLE_COMPOUND = 2; + var SHAPE_TYPE_STATIC_MESH = 3; + var SHAPE_TYPE_BOX = 4; + var SHAPE_TYPE_SPHERE = 5; - 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_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; - var DYNAMIC_DEFAULT = false; - var prompt = desktop.customInputDialog({ - textInput: { - label: "Model URL", - text: defaultURL - }, - comboBox: { - label: "Automatic Collisions", - index: SHAPE_TYPE_DEFAULT, - items: SHAPE_TYPES - }, - checkBox: { - label: "Dynamic", - checked: DYNAMIC_DEFAULT, - disableForItems: [ - SHAPE_TYPE_STATIC_MESH - ], - checkStateOnDisable: false, - warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" - } - }); - - prompt.selected.connect(function (jsonResult) { - if (jsonResult) { - var result = JSON.parse(jsonResult); - var url = result.textInput.trim(); - var shapeType; - switch (result.comboBox) { - case SHAPE_TYPE_SIMPLE_HULL: - shapeType = "simple-hull"; - break; - case SHAPE_TYPE_SIMPLE_COMPOUND: - shapeType = "simple-compound"; - break; - case SHAPE_TYPE_STATIC_MESH: - shapeType = "static-mesh"; - break; - case SHAPE_TYPE_BOX: - shapeType = "box"; - break; - case SHAPE_TYPE_SPHERE: - shapeType = "sphere"; - break; - default: - shapeType = "none"; + var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; + var DYNAMIC_DEFAULT = false; + var prompt = desktop.customInputDialog({ + textInput: { + label: "Model URL", + text: defaultURL + }, + comboBox: { + label: "Automatic Collisions", + index: SHAPE_TYPE_DEFAULT, + items: SHAPE_TYPES + }, + checkBox: { + label: "Dynamic", + checked: DYNAMIC_DEFAULT, + disableForItems: [ + SHAPE_TYPE_STATIC_MESH + ], + checkStateOnDisable: false, + warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" } + }); - var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; - if (shapeType === "static-mesh" && dynamic) { - // The prompt should prevent this case - print("Error: model cannot be both static mesh and dynamic. This should never happen."); - } else if (url) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity; - if (dynamic) { - // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a - // different scripting engine from QTScript. - gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); - } else { - gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + prompt.selected.connect(function (jsonResult) { + if (jsonResult) { + var result = JSON.parse(jsonResult); + var url = result.textInput.trim(); + var shapeType; + switch (result.comboBox) { + case SHAPE_TYPE_SIMPLE_HULL: + shapeType = "simple-hull"; + break; + case SHAPE_TYPE_SIMPLE_COMPOUND: + shapeType = "simple-compound"; + break; + case SHAPE_TYPE_STATIC_MESH: + shapeType = "static-mesh"; + break; + case SHAPE_TYPE_BOX: + shapeType = "box"; + break; + case SHAPE_TYPE_SPHERE: + shapeType = "sphere"; + break; + default: + shapeType = "none"; } - print("Asset browser - adding asset " + url + " (" + name + ") to world."); + var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; + if (shapeType === "static-mesh" && dynamic) { + // The prompt should prevent this case + print("Error: model cannot be both static mesh and dynamic. This should never happen."); + } else if (url) { + var name = assetProxyModel.data(treeView.selection.currentIndex); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); + var gravity; + if (dynamic) { + // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a + // different scripting engine from QTScript. + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); + } else { + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + } - // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, shapeType, dynamic, addPosition, gravity); + print("Asset browser - adding asset " + url + " (" + name + ") to world."); + + // Entities.addEntity doesn't work from QML, so we use this. + Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); + } } - } - }); + }); + } } function copyURLToClipboard(index) { diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a02496a252..ef4fb8d177 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -182,92 +182,103 @@ Rectangle { return; } - var SHAPE_TYPE_NONE = 0; - var SHAPE_TYPE_SIMPLE_HULL = 1; - var SHAPE_TYPE_SIMPLE_COMPOUND = 2; - var SHAPE_TYPE_STATIC_MESH = 3; - var SHAPE_TYPE_BOX = 4; - var SHAPE_TYPE_SPHERE = 5; + if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { + var name = assetProxyModel.data(treeView.selection.currentIndex); + var modelURL = "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"; + var textures = JSON.stringify({ "tex.picture": defaultURL}); + var shapeType = "box"; + var dynamic = false; + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); + var gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + Entities.addModelEntity(name, modelURL, textures, shapeType, dynamic, position, gravity); + } else { + var SHAPE_TYPE_NONE = 0; + var SHAPE_TYPE_SIMPLE_HULL = 1; + var SHAPE_TYPE_SIMPLE_COMPOUND = 2; + var SHAPE_TYPE_STATIC_MESH = 3; + var SHAPE_TYPE_BOX = 4; + var SHAPE_TYPE_SPHERE = 5; - 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_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; - var DYNAMIC_DEFAULT = false; - var prompt = tabletRoot.customInputDialog({ - textInput: { - label: "Model URL", - text: defaultURL - }, - comboBox: { - label: "Automatic Collisions", - index: SHAPE_TYPE_DEFAULT, - items: SHAPE_TYPES - }, - checkBox: { - label: "Dynamic", - checked: DYNAMIC_DEFAULT, - disableForItems: [ - SHAPE_TYPE_STATIC_MESH - ], - checkStateOnDisable: false, - warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" - } - }); - - prompt.selected.connect(function (jsonResult) { - if (jsonResult) { - var result = JSON.parse(jsonResult); - var url = result.textInput.trim(); - var shapeType; - switch (result.comboBox) { - case SHAPE_TYPE_SIMPLE_HULL: - shapeType = "simple-hull"; - break; - case SHAPE_TYPE_SIMPLE_COMPOUND: - shapeType = "simple-compound"; - break; - case SHAPE_TYPE_STATIC_MESH: - shapeType = "static-mesh"; - break; - case SHAPE_TYPE_BOX: - shapeType = "box"; - break; - case SHAPE_TYPE_SPHERE: - shapeType = "sphere"; - break; - default: - shapeType = "none"; + var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; + var DYNAMIC_DEFAULT = false; + var prompt = tabletRoot.customInputDialog({ + textInput: { + label: "Model URL", + text: defaultURL + }, + comboBox: { + label: "Automatic Collisions", + index: SHAPE_TYPE_DEFAULT, + items: SHAPE_TYPES + }, + checkBox: { + label: "Dynamic", + checked: DYNAMIC_DEFAULT, + disableForItems: [ + SHAPE_TYPE_STATIC_MESH + ], + checkStateOnDisable: false, + warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" } + }); - var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; - if (shapeType === "static-mesh" && dynamic) { - // The prompt should prevent this case - print("Error: model cannot be both static mesh and dynamic. This should never happen."); - } else if (url) { - var name = assetProxyModel.data(treeView.selection.currentIndex); - var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); - var gravity; - if (dynamic) { - // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a - // different scripting engine from QTScript. - gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); - } else { - gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + prompt.selected.connect(function (jsonResult) { + if (jsonResult) { + var result = JSON.parse(jsonResult); + var url = result.textInput.trim(); + var shapeType; + switch (result.comboBox) { + case SHAPE_TYPE_SIMPLE_HULL: + shapeType = "simple-hull"; + break; + case SHAPE_TYPE_SIMPLE_COMPOUND: + shapeType = "simple-compound"; + break; + case SHAPE_TYPE_STATIC_MESH: + shapeType = "static-mesh"; + break; + case SHAPE_TYPE_BOX: + shapeType = "box"; + break; + case SHAPE_TYPE_SPHERE: + shapeType = "sphere"; + break; + default: + shapeType = "none"; } - print("Asset browser - adding asset " + url + " (" + name + ") to world."); + var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; + if (shapeType === "static-mesh" && dynamic) { + // The prompt should prevent this case + print("Error: model cannot be both static mesh and dynamic. This should never happen."); + } else if (url) { + var name = assetProxyModel.data(treeView.selection.currentIndex); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); + var gravity; + if (dynamic) { + // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a + // different scripting engine from QTScript. + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 10); + } else { + gravity = Vec3.multiply(Vec3.fromPolar(Math.PI / 2, 0), 0); + } - // Entities.addEntity doesn't work from QML, so we use this. - Entities.addModelEntity(name, url, shapeType, dynamic, addPosition, gravity); + print("Asset browser - adding asset " + url + " (" + name + ") to world."); + + // Entities.addEntity doesn't work from QML, so we use this. + Entities.addModelEntity(name, url, "", shapeType, dynamic, addPosition, gravity); + } } - } - }); + }); + } } function copyURLToClipboard(index) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 4342f0e683..06a141a95e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -299,7 +299,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties } } -QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType, +QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, const glm::vec3& position, const glm::vec3& gravity) { _activityTracking.addedEntityCount++; @@ -311,6 +311,9 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin properties.setDynamic(dynamic); properties.setPosition(position); properties.setGravity(gravity); + if (!textures.isEmpty()) { + properties.setTextures(textures); + } return addEntity(properties); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d1b321dbca..919d0e3489 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -158,7 +158,7 @@ public slots: /// temporary method until addEntity can be used from QJSEngine /// Deliberately not adding jsdoc, only used internally. - Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType, bool dynamic, + Q_INVOKABLE QUuid addModelEntity(const QString& name, const QString& modelUrl, const QString& textures, const QString& shapeType, bool dynamic, const glm::vec3& position, const glm::vec3& gravity); /**jsdoc From cc4bafb46fdcd4b599e2d24d2fd09393bec555dd Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Fri, 26 Jan 2018 15:40:22 -0800 Subject: [PATCH 086/272] image entities shown as images in entity list --- interface/resources/qml/hifi/AssetServer.qml | 1 - scripts/system/html/js/entityList.js | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 04fceec1f3..b173b3826d 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -142,7 +142,6 @@ Windows.ScrollingWindow { }); } - // Elisa note - need to link this with specific add entity call function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i, /\.jpg\b/i, /\.png\b/i]; diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index 7b25e66c67..dde91dc694 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -156,6 +156,10 @@ function loaded() { var urlParts = url.split('/'); var filename = urlParts[urlParts.length - 1]; + if (url === "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx") { + type = "Image"; + } + if (entities[id] === undefined) { entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible, From f71d9e4d6a4a994cb26187476ac78e86c6f5b998 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Tue, 30 Jan 2018 17:49:30 -0800 Subject: [PATCH 087/272] snapshot referenced locally, won't work on OS --- interface/resources/qml/hifi/AssetServer.qml | 2 +- .../qml/hifi/dialogs/TabletAssetServer.qml | 2 +- interface/resources/snapshot/snapshot.fbx | Bin 0 -> 51420 bytes interface/src/Application.cpp | 2 +- scripts/system/edit.js | 4 ++-- scripts/system/html/js/entityList.js | 4 +++- scripts/system/html/js/entityProperties.js | 3 ++- 7 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 interface/resources/snapshot/snapshot.fbx diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index b173b3826d..42b8118115 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -183,7 +183,7 @@ Windows.ScrollingWindow { if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"; + var modelURL = "qrc:///snapshot/snapshot.fbx"; var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index ef4fb8d177..315def6f14 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -184,7 +184,7 @@ Rectangle { if (defaultURL.endsWith(".jpg") || defaultURL.endsWith(".png")) { var name = assetProxyModel.data(treeView.selection.currentIndex); - var modelURL = "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"; + var modelURL = "qrc:///snapshot/snapshot.fbx"; var textures = JSON.stringify({ "tex.picture": defaultURL}); var shapeType = "box"; var dynamic = false; diff --git a/interface/resources/snapshot/snapshot.fbx b/interface/resources/snapshot/snapshot.fbx new file mode 100644 index 0000000000000000000000000000000000000000..641a7f82ebd0a67a9364c21867bad4a02d246048 GIT binary patch literal 51420 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

&G zn)U3&NLVlYg3k%9i=l-QG?rwY&lPFRdfN-$!ojKHtN?jwpZweFP!jW1fNRrMz*Wl=AuKoqy55AyU3eH^f^$WO?uQ|Q3)87W! zM%VQ3#OnI)jA6SHckwNm0;qmkMw6tW@TM|j;ZwBA76W$`f zes=!aTM{V(amXl#A5029(ssbCKD7PiNZSEt_|Qf<(st0xb(r3Mr0t-Y_Aq_?NZUab z=wbTyk+uU&>S3s-Z5{UDtKcKM}3o>GeMF{{KcB$g(?AYpNpS!mo7M IwBH~9Z+ICcSO5S3 literal 0 HcmV?d00001 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b203487547..53c1e3fad5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6525,7 +6525,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { QJsonObject textures { {"tex.picture", QString("atp:" + mapping) } }; - properties.setModelURL("https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx"); + properties.setModelURL("qrc:///snapshot/snapshot.fbx"); properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); properties.setShapeType(SHAPE_TYPE_BOX); } else { diff --git a/scripts/system/edit.js b/scripts/system/edit.js index c298da38bc..ece8516567 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -548,9 +548,9 @@ var toolBar = (function () { z: 2.58 }, shapeType: "box", - modelURL: "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx", + modelURL: 'qrc:///snapshot/snapshot.fbx', // change to another default image - textures: JSON.stringify({ "tex.picture": "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/dog.jpg" }) + textures: JSON.stringify({ "tex.picture": 'qrc:///snapshot/img/no-image.jpg' }) }); }); diff --git a/scripts/system/html/js/entityList.js b/scripts/system/html/js/entityList.js index dde91dc694..85cd77bd28 100644 --- a/scripts/system/html/js/entityList.js +++ b/scripts/system/html/js/entityList.js @@ -156,7 +156,9 @@ function loaded() { var urlParts = url.split('/'); var filename = urlParts[urlParts.length - 1]; - if (url === "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx") { + var snapURL = 'qrc:///snapshot/snapshot.fbx'; + + if (url === snapURL) { type = "Image"; } diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 59b54b1020..acaff333e2 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -797,7 +797,8 @@ function loaded() { elID.value = properties.id; // HTML workaround since image is not yet a separate entity type - if (properties.type === "Model" && properties.modelURL === "https://hifi-content.s3.amazonaws.com/elisalj/image_entity/snapshot.fbx") { + var snapURL = 'qrc:///snapshot/snapshot.fbx'; + if (properties.type === "Model" && properties.modelURL === snapURL) { properties.type = "Image"; } From d7a847930d3f8d88cbbb505a6f6b6bafbbad8ac6 Mon Sep 17 00:00:00 2001 From: Elisa Lupin-Jimenez Date: Wed, 31 Jan 2018 11:44:22 -0800 Subject: [PATCH 088/272] added image icon --- interface/resources/fonts/hifi-glyphs.ttf | Bin 31232 -> 31500 bytes .../fonts/hifi-glyphs/fonts/hifi-glyphs.eot | Bin 0 -> 31678 bytes .../fonts/hifi-glyphs/fonts/hifi-glyphs.svg | 148 ++++++++++++++++++ .../fonts/hifi-glyphs/fonts/hifi-glyphs.ttf | Bin 0 -> 31500 bytes .../fonts/hifi-glyphs/fonts/hifi-glyphs.woff | Bin 0 -> 20032 bytes .../fonts/hifi-glyphs/icons-reference.html | 94 ++++++++++- .../resources/fonts/hifi-glyphs/styles.css | 35 ++++- .../resources/icons/create-icons/image.svg | 23 +++ .../resources/qml/hifi/tablet/EditTabView.qml | 2 +- scripts/system/edit.js | 1 - scripts/system/html/js/entityProperties.js | 2 +- 11 files changed, 298 insertions(+), 7 deletions(-) create mode 100644 interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.eot create mode 100644 interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.svg create mode 100644 interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.ttf create mode 100644 interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.woff create mode 100644 interface/resources/icons/create-icons/image.svg diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 4cc5a0fe4f098a287c1df067c8bff37695f96d34..8907cf7858dd304cdad024bfa1ff4ca5cd94caf9 100644 GIT binary patch delta 724 zcmX|8O=uHg5Ph>h-=@iK`jgG3nn;_(>^4eivq_UGO~Jo*03;0QVN) zX6G`+!tO43VEF|A+uTBVcJti01h6S!VKbM_%s5l^Fo2H$;<;S5k`V@J8z2?H!Cbzy z)bq8w1E5C$1r`>kGZRPhIY1l%$d}J76|h4W0UB;CbTyOD?i_ub28u0Dt*}@u&77$F zfYNh-k#!sa-mUbPOYI{+;NZ}T_jeoG9&-)t4kc;5HcC}WC9NtCSnyeP&}HzJ@u(EYPvN^4f+E^ov|n-DW(Vg0d|0kC*nP%B`gw6E$TNDaYHwBiAl^DrG#$iK__|C zgvNqQH)8RGsp$dcRy}4sMszda|BrZC7X`baPejBPrbc<$R?GqWn-6M7gWo&g@Y| z_0ABp$wt^A$>#-+s4~gUOI;p%;PR4JZB63kHo?uwYRz#?q0T5G=(k{E5D^Sl!^PgV zXrw>VZw^L=tM`g}b*VT{>$OkCZsO=x?RV*^Ad2((%v^P|?5DNrhqBl4|CbHzFM6Dk ACjbBd delta 475 zcmX|-Pe>F27{!0z?6_>Hl;lBV(GkK38QNLUDR4XK+M&==V(DOwy1BW#IkZFUivMnc zu9t>xA`)~ow8=vt6p=S0FG+_EdkD#nVnUZTW~4s&c<=Jw_uf}Nk@;hpLx6hb2{DjN z4&5p){#k?4cOcr=)0^ZiVJLkBwEn>>@&4_bHb@G%JDRubp^+~yLD>UkV%#d&)hZz< zZ3B_ zt$}N19n^G#H0Q0N%}*Hyx#|acY~|BOiC6dFNgar1PZpdz_VZ;ZyoZ|KK{OBq3$*y0~&1KYOszK#GhJ3Ro0XZUASApy0dARxVdMs@1@+ zt-^nf_8?G1_yAr@=z@5iYMY{fmkMuXy@o=qG??fZ80f@_VPLwtqn$Bz!_ea~!*o}j oc6Zu&BxUcwX_D7Z->L4-ly+$eL51KxrwMlxFZ_S{m45ugzdev~Hvj+t diff --git a/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.eot b/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.eot new file mode 100644 index 0000000000000000000000000000000000000000..d3591e6499c6afaf63e4a2c0f144f4722c2f8d9f GIT binary patch literal 31678 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 + + +Generated by Fontastic.me + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8907cf7858dd304cdad024bfa1ff4ca5cd94caf9 GIT binary patch literal 31500 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 literal 0 HcmV?d00001 diff --git a/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.woff b/interface/resources/fonts/hifi-glyphs/fonts/hifi-glyphs.woff new file mode 100644 index 0000000000000000000000000000000000000000..152e5b4cfc7c4c4a93501e1299cd76b08f99f111 GIT binary patch literal 20032 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%0AM|Nb=x81LFNbI8I6Rv$RP zc-K%jk^mOA588iV4M9T_)j2;vQ+z4~P8&EIs9nHvAQ$`?^r(nK&{Y@@`OWK$p_x<{ zfd75=Fq@$UU?X+MgWtTJE~WQ9M_;2m^V_B;rzW@N_9$eqfYT_0v4t!JE9$^%M(1SE z7wBY(B3ZMV5qQukt}^4*6c7o_m%<3sEOsUa2D^LsHrh)cezf{2`Z(RYQ#&YU(uO4g zI@6y?r!$#E8r-Re{gw8`w!p>{X)9xb)AjaS@YJ-dbTSsa_6LEC znTW-ciCE~m>-=$;b676;128?b`CHfzet7i-=U;uz1?OM$_J<$5{lgDKzjp3rt#sOg zsTdDk^OoOArsGgM9=!INKn%X)CiMUIwf>ly1Ol0v;9JnrsJ)6kzrsGx39=*k{7A@N z9vBJd2ZGLWKdO_Evpg`6503=x_HuiShEJ0CqcpZ2Uk$jiM7?!u4Qw62>bMwFbh z{XMil8<_y_LKk5k)%oSP8aLvZ-ifY#bOM7A`I*i9Aq+wcI!^?WU~?ypB-k+1PL*E@ z$PrpM&=Rhv(e{9WTjCY;( zr2J!5`yV?lK3vz(2 z4Nf(XMM1LkCX;a>OD7#j$Ht0e$vG2l6iL#0a!3`7A^}x$EX?0DSYyz4$nSZ67#IrO zbNs$pA+G+yJOO<*Z#8K5%7m z_*QH*QILjV_<0=u!13V^c*7rNFQ~AWEoYZh*q>b(8p5&cID^8x`SHgg%>4fdArfd9 zEWX^wAS@Cn|1k*BqxcwvH^0w5BQYQXUEvkF|3N=~$CIWNeCGZ@0z{x?rmfJk&-g)z z!F4hY!eDIvLiXKPmtJw@vZYsqnrMsFIYPeHGxsAVHj$d98_7>zeeK=g9!F+Dz-K}< z%^69R*rfsR8o_lWnPfT!A~F`FNi7BTEM0N^cDj#2pOU6YCSk@w4&zfJse#p67U03D zrAZRA5*ZZSLAOPP&~LrDo<72W`;o+_>7*5`oUfR#06%f8N?Ju%^{?Hqp>e~Sez>Gn zqZ_tu*xLUXJxC9ZKDKQe*|zPm(Z}J}WBuDUkbb9)otrJ}rhDn$!CkGJS~k@dYUnyz zH`vnB+A>%NmoV2gk&M=+<0z2U5XdHBa zm42qMI2}UvCj;PTb1Cq!gU%G9WD@u+B*h(`~JPb!;buts$)M8G> zg!5q`N(bcuI!MDbE)PW|{`O?Ol$6lxB8mXskEkWV)1#yG2@p70X`2N8%MH@!>Gj0) zo8ZjIrnXz#rR|claz@Dz%kRnsQLob17;BU;rNc65oDZ-UR#e)j{f=$i*8iCNxV(S# z(Jfmx&FvW3t*J>hp(X*Qgph)1)zzM8aLM2m0w3|WG6qJ~ zxSG)8hO3EO>pHs0I#!bPIQ=pKT6*GL6m<7fdR0q^Sf<+k&OoRB4{a{H_Mb0aE zHD|(48M~2DJ8;9{vB6>RD1oAyse%KUO=c5Te9MN>D(Mlrrhjc?6KQN*JFp6LqyG_L z;>K;ne)tVm0#^;Xmk9jJLF&4J01?0CP@KpC z3}pv#6^i028#EskB4SiXNx)&yt^~eqD?^b;Nibe1F2wOf>1R0!7v++T@j>~Ncr4GO$Tw18~VG^jD0CvY2A3WAbfg04ddQCM0l3Y3w+m<(N1 zPH&;2>u1Z9sL*Iy)xoXT4K1x%nx$GqRvB55kw}O}ASt@lE{y;pxd`?OVWGtbm$Nbs z2Pmj8(L!>J+X&hS9QcS9Q6m}&YmAE)sfZomgyD6&8|G3(ak&DiC6h;E?DqmlJy9n8 zar@K4@h2Dm5@YnFy9&KVGS36(h#Us}dVsLozLKp~7|Dy7Q@0~3_k*N}$o)zm z6%<~hmSjn3iI~G84at7$j*4L4p&taW-=ITwV8~wyN&$<{h-uM~FvLP+H?DwVmqT*E zm^C+z%@7PBF)oQI5hSJ|($o@ZB=KIB9}xTGUYb;SgU=-L+z79_!5m;3#GVVezc^Xk zCdJo1f<2sPM8HwVzIh*u_zo7f7q$&=)6%j3(z27)%e4 zIr|eVxRHZ{;oL}2F643rN(#B~ATAHS$rifpliwShVw{m2J15ZdTPb6o-R3%TAlDQH zj4xsr0w(B>pffVd2r{m92p)6e+Db}KnGzIfV;uP~E_&F}PF(b`&j63e)N#GA5OA#& z(W^#8+70ZjxNDmVRVBp)846ks7fiy_jEHfag*6q)@6I-nOa{OYM2k?-6jdV5X&1AF zE&zRCim^ZE_`M%6j=!Dk)UkGOuq=^c=6E+T?({aplC-gB&h!@G4(a zo{v`@tBF?je^C?eKutjxyqZxfk zJk1yeTia>MluFGy}D zGFX0^8+akRoP%|Kw*)Yx zm&^+zbe3+mwvCd%oqC9+8Nos~7^>44jSCnQ;^T1XE>CGG4Qv|X{6_$(qu?8t(8l~O z$N;m8XZt?_2F?aU)4@D7$^4alECmNY1=Vp$9?WHt7wfv4z>tX11OVKX?Me3;q}S+C zyXg=e6bJbMVTc<_g;P;J!NvI`yup`4ch9L0fN7O71=Wo;yM~N1mYvGXq-WDp`UK5V z@I6G56)eFJOu^#wDU#-ye6k>n(oJ+%cHa~lFhR*MH47Kvc*9$aj*~tMpBZTFn<_XA)C8({t9Rti0PPj~xL(rs1;)+sgL#Hi zfH+nD2#smU3~@^Ba~RGPv1UfKFnnTZ8JeS*q(k=KLv4$p8O?hDfRWwhJ+v=5G&D4r z?591%`Enp)M6@u4y9u~El;aMcw{zII?X&!EIzBdL`!fEcaN*vmoIlmxRTL1CD;&r<|L(`%_{;s>=Xb>t zx;@Z5`QkYN{4I%|*du)bcPdM=JB`Wj&+(%q#L4acb|;EloG1$U{qF<#8*jK1XSY+z z(g+78S3Dl&BY^ripgyX_t+>TyX^z=4P?p`#1 zJNuE_4pjReHGA|C78|;3{ucHt74{R(XW3XH84o&Pe>`DkLL&iOB?#JKKduyn($3v% z1~0&+8K9Jbvaz7E+aEhtHWRdSKVt`IztB64_xBo;eG!Ss1JM3J@X3P`7NMc`m{Ku+5Ur(2x_{(1D4Zs5|9y~VUqi1_9 zLCbCZtEzU&g-o#*LR= zdL#b7@!orHyzyS>_VNeTta%_rht#khA@(WuDNIBUt3$wd_mw}hfB!QfIxOV59C1!@ zPG)kcyfBQ(0jJxW*l$G{WkuhE)$5in{XBQ=bEK-e*FMb-_SV!f&(^=8Kk>x2t@-__ zeZ(1ho88bDUSq5!-^eoJ;jyP5-TT^Wf7Rc*k39D1xO18l9N)8xxqs)4sc$|4O?TKk zSs>L0AQenj0TV4z?-SbkMX>NWo`yQ_fO z-&nb3IVHE<|I91jefHV!hMuEO)Z|wXdzD}DM28!QBhHU6X7_B_vS&}zmYUkerka|q zO}oJ*UuB=pcJ(meRdHb&rZF96VVcX(Jj}qXWsx8JfZ4QZ+8FK6MRPQl)eY6a>>{w? z_1>{=vrT9hI>H^D9C8ppqsc*|}E>+3eR z>}EFe z{W>c4Gn(XP#U;MM2z}X97Gry|sS>r2z${Ejl}%Fk4GVqh3B*4yB_;GQkzX`;_TA0w zbVsg9YNQ(?O`V-xolTMTz~)W4&gsr6ux+-}ZMiMe(`0&j3z&u5=$6QICmH(+OXs4q zJrlhXZP^yuLffLfJv}|qHsG|DY}-Wdc+YHf6D6DIY<7HNVk|pHHv!atv;U2~vSPIS zs*0!XV_U}qN{#_TLk1gQSQEk_K7gs12_YfI_=rH%rU^<%8B0woX*H`ECLJYuU}GfH z66^yF-jgJgpbFzUZ)J4NvN$ak=XhLanV4r-=Om}vPEy7>$?jqeii`5ZUgT6WXk79s zAq9URYm$EWsR{-UMKl9S*igd2=|l#d2eI*tpd-}$s8*z?hXU4|J_{5AgLrMNi zEVvUIh;j6oQdCgEv)ZtpK_glKflqZ!BipuZ*bYt)AV^ig7KTx6TfcofqXLptK@$L- z0zmp_do!D{;<1o~dJ+aGpphdJ8W7xcI5957xuk0)2}Jf|8kQoO2^vWzK(rq7Nk#Vo z#e6ET%`lpyCb)zU7mFEnG~k+80>O|IA~1-iy{urY9WT_ll28*m=3IckhVgX}Vs(s%)vz?6F0^KOXb z2Z-PzY0|uDrqel^PI#6emUjU+bxX6{!GHlL2Z|S2D-EqDqCs3GkO10%cVUTXKFwi@ zuY%)}F#@ZY>HI>bNy61l2#x4wz3B-pp~Nw!sp7Ip@#5mU*y*wHsp-D4&aU3R&aUy^ zDUgzn*w3+E4xH!MF4(FtaP-!QbEW6CNgp>xJ>&DJedRx{E=kg{>bOMmf2vMZ@qbud z!6-hMzEv!G$P&ha!9gT~;KYGX8Gr_ua>p!g-O7QbJWNLbq&e4ySLCAeTRH#u{5h;$>Xg?0trQG;2R;tgg6CAa zd%m;GHJF86ykI3=~acKhegSq!x>6osYTfY#9)+$YZMw#6QG zET_dTy}`EZmVomUkdgKm?c1F%25jFAtaJNrZ2hPojf`qghK35-Jek8SB$D?=&PV@5 zKpYkE>ZV}n#LL6NtzR;#D8=PWS5vuhSH!7A(pe0eC_L^5D~7^cV^t7%5o`=GCBYk4 z#}c?vK}jhX>EPV7W&vYM9Qc=1 zv6$H{VD>B`M{;wzFd!tlKAq_P256;)7TtfB!4zD@a5pcYlB+)MH^iOywxzN;-zCr0j0%z{t59&Jr;h-d)C1a6Lo?qQKPOT29>rIBx?U z&Jqtc!40;#PNyoW4kiQ-pkQ;|U1ee|-?%qhyK{Wz%EN<}`*ND_G0Zvy95-}KrRKTSn3GoYLQ#@xF z{?WK`K_%OB?0P?Si4BxzillV6=zt~?am`)97{!lvvtcO!XjMI^QkW1ZAx1GMh=~0d zT9uT146VS1(3uGy3?}v~fEXeV`Eemig5kswQW15FfVYq%k$EWBnWCp%*<;|2#$z98IDXQVXu(gyI z#Kk}l2gkD{TA9 zQ980~q;8aUJUO+$pN2OKZtF*@YmGaHZ1zA=j(Z_tToEq5-PkO0lnZehY=9!GD8)H1 zyS-8u-=aI4MG)#8G_j3Rvy%=_FtQhLaYeS9h2Sl6V`g`;`^Cd7@+HEK(*yOiTgZJW zvYTQK=IU|L=m{s$6EnC=7DGb#FA>x$lJ_AJQ}lY5J!Ro$C*Wp1cfsGy72u0@f~)<( zN=hnzjk>c1Tjt#zxL(VsB60PdO2=3WK_N-#0~j8p2w+|J2nPbdi!mwQ(xw*-ueSfl z@@PVVWTd#kPjUC64*6v_#|*{g+F?q!F~vGcu?@KxzVh03wJ)Yec+0wg1{g;D@YaAA z^Y`$q{9P@g3YZPz_QTWq0;M|{cd;1h?(w}Rn<(cIQ}Wa_af59|l%f)mC2v=xyARRR z4oLnK$_0_w+0kjr}=goCdyfwt|hKFx-+v0Ofr z$>(DkcoGW-ow7aN%`DuEX2Ovu-n{00Hj<6zb6IF3nvJ;e4?EHc%~#IfGXGDk?(Km) zH-JVDCy=XG(MuW12^=qyuRP3nVKo#uP)z7mol+S*cW!(y`#CG@i-mR>_yOXO4?A#=280E@_PC; zMm(22(m-EXzJqCdf`xlKpym}jSbF96*S@%8`Hsdu#+|vSsBo{D;nvpagM zfg&vf$BLk>RxGk<1i)yZS230IpRtG7S$?dGwvp=t%^jW1L8sr}(lNa`^k#t0PE2jo z$jgD(p8MAKUVH8vOM}ioy~@@$Hr0mivOoJ$V0Y7&+93M+gr$Ku=%KmI(_3c?vsBhh zYGJCv^7oz3s1B>#z621Oq;U-_7ipwzYx};2!~M@u;+$(U?8MYl2i_46(nrHP+J|FS z+)SntK;BqG>)P-)F|BA7U6*f|1A1nYCTW#fyN73IyC>V)y1U!jC%b27CnslumGklW z5UT(e0p*-qoPS#NW&89S8IPteV*wF61$2mbbbhaWf8egsL3bAd$GIxk^Bz>vUs%=0 zc&Z5Wu?kj&p_+iS$Hzuq0zz|o$^bsg5018NYTpck1r)!kk=eu5;zLMH6k;wlktGax zvi;Gyr(Ly*DOs4(Mdc7GT{lC)6JZp*c`Ey5KTgyjl>>VRp6@Df#BTTkDzeG`KI#;_TTMGom;P1+s(9%v0HM?pwVd!7^Hq3yAuZ4x@WMNIe0NU z(=yvU-V@o<|9Ia)VqfdT*(dW~c#f&v&K9Cie&Bra2xIn7uAoX}ZuiCd5V1?_lUSSi z(ai%4o_?^E)ruCf$niY6;OmUwuJpRf2n8V8VD@Xc1-YUF@3sevX&c{AujbBg=2NVLAREIePTSk)xp(ov*N2E0f8_t!QX9mEU0S zDu!Vw@gl@!+)Sih>7-Ed9dHf*VE>^QsN9D7<5W;F_1TFOUHI(%USM>Wu5|xMRe?Q#z53lQhf{Sz_$Zzs*XmTwAPNNZ|%^ z*EmB1)-_Af-OWtvGtx#PP4N@)Dcm25n~~r?x+gF-%mHmc9h4L3PY~QkO3~TN%%A7x zdtb3^*%enTef8aUUwiG{kh8NKX!6F<M@TUPVg4RDe zFw#GQNg_Ot2e`!Jq`i}!>cWyRr9eyJl4^M9{`)Vzth?LgK&hMS=6iVJT8WZ2txl>_ zavGRWpPK&DAD?=P%+4~NWk8%uoB?)p?7e?IbO_g#O_MWlD;jZbc7RdmKWWc_MMKlL z6Es0Nj@)}M<8J?g8)>TRWbb0{!YhQkioJqfAyV^gmflTQ(Yt{^Qt>D+6wk3qs+<`C z{)py0dy7QA1@qR-6HkANQO9hg8}=`_Jq(6|W4l*H(Pw$D7Wn>~$5m{9v-z zS2z#;?!SCs_dAQ(8!DVHEB}q>_VvzP?2Q$;*<%HJ6MW0|3+&Am)?MxoukJSvfBcS3 z7DEHq{p0(i&K=OAbB`T4{`j-@XIOiM9rWWFHpyghp_*PvIp<51+UM)^Rm!->CMe+5 zx``X8pfNoa$l;vsw^wasWniGt%9Sf0Ub#}|3|wTf&$iE|w@p*}*E1;X04&~M53;vZ z{BW`NkK*bY_QI>Lz3}|EuKD0MZ@=~Hko@5_Z(l%3r*j{>6rSHXA7D4s2jU6SN~hCS z$nIKfrEz0tG9Eg2oBwv_L3aI}?qlotVNTkw|im1QaoNA{xOoc%Zqoq8_$ndS6u@Vmjljwp9SH9HVOv7 zTt6ODVbN=LEpSg93Ai}`JR1pvZWxS_cvq|frS99sVl>M;yvcRky)+`%RM()Yo30Oz zIat2#Nir(#Z1>V|1v>ZnVS=)J}cCs%BO(_%ttr#^5o^kEchM)SXULJCu%KjQ%uk`Q6c>v{ zqlqY=O7ICisR@`#wO6 zspc+fL`joHBBHM-g(%=lfxD_8Dsu4?omk9YM@*^`^)kybKVHR^0`NhAB7)>$Q-v$J zXsmc%l_+YOYo~agF3+i&XUZ&iT?n9;KTkXt%(ZiH$2UVO$4OrWO( z(BpXHaZzM|Jw&YGI;dEZhdY9s$1S)S^|&bySr5ZyfMS_yA&~o~42E8>2C=O_I z*Be~^hJOrod7B3ia=@tPy=R7vyf&g(;6|B*7O3G`lk^$-(YxfH3<>AMd{jQR8H*0Z+|5`bW;Y}jRuKMvGZwiO#*_Yf+VLIRkVUCrFUGxC z&S(8JrU*HiMCOUR18c|*yGrjh`?st&NrIQ4%+dTB`av(4u&jE z(e;cskrd9Lx;8P1FEFgYv+ADcne3jV-b8l|S)8pHrob~rlEfj-nJhIhnx>+J2Ue8? zf!uKiT5E#FPl2&G+2uyxF%qMIu%S?lO` z-40p4kQtW8MDJzx(%pbdl3dS3XuVtumWB|BaS=WOGR8KUUfM^) zB9R@9iKr1hX29J(Cc!6#B-b78?~Qc!)^lrfHQ9Bu8+P{Y>fOif$qj3HBbO$V`LXdF zW=>vY&wBe@6tZRfyN|zr8)I@=Sx@Vxlu3YP>-*7HmpAt^iIf-vb;G%v7Jhm)d-vCV z71%!c+T-7OWLpQl({Tx5RWFfN8o^*z_Xjs zdP3z3F7(haqw5;j#AJ8~O-`z+#IhI_4|Y*W-x%YnQI)*(60^VQ>EW3jGdqPRo3=J> zUa2*-*R>Bluw@NQ!NctO)|U0bdbxF$?v(MUPD*ypwl;(+=Y8OZj13R?8Hcd}&+BDtS5?rx~9SlbXLIcl@1V$pcL15IUSlYPs(4DmmXX36@ z^6nvK<%MjU?VkS zy~nwkRrJv(=-cEcz0XNOnFfU6B)S056?o%(=$>x}CP(^vLKg&j2Ku{$cRb+7O)^2d z*N>)HdITiwXXj61p;4L?SN5;$f4ILsQWvQUr$nB|X$7-T*fh9laPtsxwXXeE9aJqj5oNYD(638zv&+DCh&N~$67aFv9L&$QbkiS$g}q8H9GDGQ$##J z42Frf7>o?)GO=+78>3TQP&kFdBsy~6T~8(OBqa>JU=PYi54k;dutnHvjy)o+i+KPZA6AOU2!_m|3aDHs;h-35Q!k&Pbp&AD#``-|^4p z^D`m&efkUOeY!E6@1P{>jIfV9-a5w&79vV-th#4yPjz>KPsyB#hldR1!*YLu6H-C~ zyt^E=uV+SNc_e6m%RfqKKW4%??<{2vG@F#ycD%Oz)ty=0r0Mu<>s;$xn~~C!TvFr{ zBIZs#g}d_PBqfPi)=SwDw;Jg!mP&Qdh~WQm>11cLH`X1)q^7Ge*4Q3wle)WUyWBR} zJtNQ1sYz*uJTk@RGVyRY77vFaa@?YMlFL}RVCB4ZDrFCR*Y19A<4%9D!guoOlRhzV zQpM>dpFO4ITs$B9Qzd7Ye6{4(l9eS*C2Gk`$^Md;O5XMPeE;lQ;(OTF=!^R--(2ak z(uYg)rTa?1SNhwsPnMluURnP6@=MCIvKF}NEulNmf31@6Q{i_q7_J^XmG zg_XcN-ce9y@hGUIcNEm37hhyFji!0sJC%p5S-oaI!^5?k*$SGCEINM7#IobZOf16V z4@~#`gU|Z$6hQZwLg<##n2->GwUWRCn4AzxC$cm{)25PjSBP~Y=ak_AgDi?#@odJj zj&BuQbo`W&rN{TYE&BCaKlt^puYK#n3$MNQ!VBNJ?$@D3@4R~Jl~*mh^{T6uz4Fda zUVY`A&?0n5i{}fAK0!%3AR#KJ{`HZ}V~$;VEXr1sCzf^c)JF zskgm`4Em`XDj+mMmlh~}hVhbgPRP1Zyxro*vTh_n+Z&gjZ6nIlN;m^3>ZdF7R6)nSR&>gJd)rs z2?I~94buT!HU(hm8Jp=OMlLlN2$^eQRCj%fd&dV2?Fw{0uT zj*l1GHUt+*v)oL4qmWh7X+2{O^I9a`qj#y@S~XWQRLczw@ezxpbP*g@EvMy_oRY`m z7|0@NO}uJg9Un`i65eu;oWg7ZUC?EiMk9O7z0zJncP6%ncW_z7g4wPcvMJ(WylN`b zo^I3Hs(w7XE@^K ziBPgAosfs(@kC;XCeq~I=kLFV@vc#SSQdHag?nFM;%PdJalv7lPLSvCdH#9EySCyq z9FLQ4+{-M=#Ed@LO}kV7?@tQX?3*?4Ry8C8fVILgA-!U@)awV zFJCcv^0c0*?Ni$(G;}t0wSi^}GSV~B(=#|48*927rk2kK!UYY}x@S!Vg4tbD8#p$l zfR`}z0+SQ~me}~rc${NkU|?hbf-|;@&V%S{(|3u%XaG$G2KE2|c${NkWME+617ZmV z5MW|p1i~&LW&!gU017w&y#N3Jc${NkW@2ERz`)AD!RW)7#=yYf4yC^`NHVlAFfcK& zax%aGqW}W}1f;p9FgP$MKG0@-@c#jW9urgzn3&4g&7c5;i~#6F3nc&mc$~G6S5iV@ z428do2zC(_0SiUNf>=<&jv!(eyI}8P@4ff3DwpC;^!MtsKAB8TP9~YjNq{K6BMV6& z(u}AixmHSkkz<4_zB*jK+dn>JW_jm_Aq0GJn+a9ue^x&sJ>tHtJT!j z)i<6rwKjYE{DHRi(w?G@&V|JmPeZkAS>W^#9uo3{0wEaSjGB1pq-73Y-7{c${NkWME)o z00KQGhX1$!-)2%}U}QiAOaNR31QGxMc$__sJxhXN6oxPS2fCPuLzeJ5`o#-|Mj(VQ zVlL|9AWq`o=H_6Os9B(?Ll|xjfeuPE1AB@k&DA~!^63+V*_m9Pgz}-CdfHkURi6mKwh$` z#*oWFQpprI2YeK{lr^OHmz{Et51yECOO-w^n1A2Av0=!Hcd;a)mJ%`Se5rja>I`&G zMYel9N8CqRjL6a?!x;@>@k~wEJ#eR;E19Cq^cUL$G)XhJ002+`0E++sc$|%oJr06E z6od!)NenhN#&Qc2D+r5?dH_mGZ-B4~0Rl80!3%f~kKqA4h6k{7z-OX~g`2$W_hx6` z&H|X=3=93T;A1X4f`?ex#u6uChn}mjOTG(x@U1DGmNTX@8*cSH;{1iMjU6_^4m}rP zmwXfU$PeT&IIsd_C~!ngr3G?xFhN!v>zvKk$y-cNp+q

HiFi Glyphs

-

This font was created inHigh Fidelity

+

This font was created for use inHigh Fidelity

CSS mapping

  • @@ -520,8 +520,52 @@
  • -
    - +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    +

Character mapping

@@ -1034,6 +1078,50 @@
+
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • +
  • +
    + +
  • + + + + + + diff --git a/domain-server/resources/web/base-settings.html b/domain-server/resources/web/base-settings.html new file mode 100644 index 0000000000..13787b5fbe --- /dev/null +++ b/domain-server/resources/web/base-settings.html @@ -0,0 +1,51 @@ +
    +
    +
    + +
    +
    + +
    + +
    + + +
    + +
    +
    +
    +
    +
    diff --git a/domain-server/resources/web/content/index.shtml b/domain-server/resources/web/content/index.shtml index 0e48c1eff8..9b507f7826 100644 --- a/domain-server/resources/web/content/index.shtml +++ b/domain-server/resources/web/content/index.shtml @@ -1,45 +1,19 @@ -
    -
    -
    - -
    -
    + -
    -
    -
    -
    -

    Upload Entities File

    -
    -
    -
    -

    - Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.
    - Note: Your domain's content will be replaced by the content you upload, but the backup files of your domain's content will not immediately be changed. -

    -

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

    - -
    C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz
    - -
    /Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz
    - -
    /home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz
    -
    - -
    -
    - -
    -
    -
    -
    -
    + - - + + + + + diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 2e6e084164..7b2ed37b15 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -1,5 +1,7 @@ $(document).ready(function(){ + Settings.afterReloadActions = function() {}; + function showSpinnerAlert(title) { swal({ title: title, diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 158008fc2b..22de75a778 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -18,6 +18,14 @@ body { margin-top: 70px; } +/* unfortunate hack so that anchors go to the right place with fixed navbar */ +:target:before { + content: " "; + display: block; + height: 70px; + margin-top: -70px; +} + [hidden] { display: none !important; } @@ -345,3 +353,75 @@ table .headers + .headers td { text-align: center; margin-top: 20px; } + +@media (min-width: 768px) { + ul.nav li.dropdown-on-hover:hover ul.dropdown-menu { + display: block; + } +} + +ul.nav li.dropdown ul.dropdown-menu { + padding: 0px 0px; +} + +ul.nav li.dropdown li a { + padding-top: 7px; + padding-bottom: 7px; +} + +ul.nav li.dropdown li a:hover { + color: white; + background-color: #337ab7; +} + +ul.nav li.dropdown ul.dropdown-menu .divider { + margin: 0px 0; +} + +#visit-domain-link { + background-color: transparent; +} + +.navbar-btn { + margin-left: 10px; +} + +#save-settings-xs-button { + float: right; + margin-right: 10px; +} + +#button-bars { + display: inline-block; + float: left; +} + +#hamburger-badge { + position: relative; + top: -2px; + float: left; + margin-right: 10px; + margin-left: 0px; +} + +#restart-server { + margin-left: 0px; +} + +#restart-server:hover { + text-decoration: none; +} + +.badge { + margin-left: 5px; +} + +.panel-title { + display: inline-block; +} + +#visit-hmd-icon { + width: 25px; + position: relative; + top: -1px; +} diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index 1e32e9f02f..aff82d557e 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -17,30 +17,47 @@
    - diff --git a/domain-server/resources/web/images/hmd-w-eyes.svg b/domain-server/resources/web/images/hmd-w-eyes.svg new file mode 100644 index 0000000000..c100de2f4e --- /dev/null +++ b/domain-server/resources/web/images/hmd-w-eyes.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js new file mode 100644 index 0000000000..5e32463d61 --- /dev/null +++ b/domain-server/resources/web/js/base-settings.js @@ -0,0 +1,1140 @@ +var DomainInfo = null; + +var viewHelpers = { + getFormGroup: function(keypath, setting, values, isAdvanced) { + form_group = "
    "; + setting_value = _(values).valueForKeyPath(keypath); + + if (_.isUndefined(setting_value) || _.isNull(setting_value)) { + if (_.has(setting, 'default')) { + setting_value = setting.default; + } else { + setting_value = ""; + } + } + + label_class = 'control-label'; + + function common_attrs(extra_classes) { + extra_classes = (!_.isUndefined(extra_classes) ? extra_classes : ""); + return " class='" + (setting.type !== 'checkbox' ? 'form-control' : '') + + " " + Settings.TRIGGER_CHANGE_CLASS + " " + extra_classes + "' data-short-name='" + + setting.name + "' name='" + keypath + "' " + + "id='" + (!_.isUndefined(setting.html_id) ? setting.html_id : keypath) + "'"; + } + + if (setting.type === 'checkbox') { + if (setting.label) { + form_group += "" + } + + form_group += "
    " + form_group += "" + + if (setting.help) { + form_group += "" + setting.help + ""; + } + + form_group += "
    " + } else { + input_type = _.has(setting, 'type') ? setting.type : "text" + + if (setting.label) { + form_group += ""; + } + + if (input_type === 'table') { + form_group += makeTable(setting, keypath, setting_value) + } else { + if (input_type === 'select') { + form_group += "" + + form_group += "" + } else if (input_type === 'button') { + // Is this a button that should link to something directly? + // If so, we use an anchor tag instead of a button tag + + if (setting.href) { + form_group += "" + + setting.button_label + ""; + } else { + form_group += ""; + } + + } else { + + if (input_type == 'integer') { + input_type = "text" + } + + form_group += "" + } + + form_group += "" + setting.help + "" + } + } + + form_group += "
    " + return form_group + } +} + +function reloadSettings(callback) { + $.getJSON(Settings.endpoint, function(data){ + _.extend(data, viewHelpers) + + $('#panels').html(Settings.panelsTemplate(data)) + + Settings.data = data; + Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true); + + Settings.afterReloadActions(); + + // setup any bootstrap switches + $('.toggle-checkbox').bootstrapSwitch(); + + $('[data-toggle="tooltip"]').tooltip(); + + // call the callback now that settings are loaded + callback(true); + }).fail(function() { + // call the failure object since settings load faild + callback(false) + }); +} + +function postSettings(jsonSettings) { + // POST the form JSON to the domain-server settings.json endpoint so the settings are saved + $.ajax(Settings.endpoint, { + data: JSON.stringify(jsonSettings), + contentType: 'application/json', + type: 'POST' + }).done(function(data){ + if (data.status == "success") { + if ($(".save-button").html() === SAVE_BUTTON_LABEL_RESTART) { + showRestartModal(); + } else { + location.reload(true); + } + } else { + showErrorMessage("Error", SETTINGS_ERROR_MESSAGE) + reloadSettings(); + } + }).fail(function(){ + showErrorMessage("Error", SETTINGS_ERROR_MESSAGE) + reloadSettings(); + }); +} + +$(document).ready(function(){ + + $('.save-button.navbar-btn').show(); + + $.ajaxSetup({ + timeout: 20000, + }); + + reloadSettings(function(success){ + if (success) { + // if there was a hash in the URL, jump to it now + if (location.hash) { + location.href = location.hash; + } + } else { + swal({ + title: '', + type: 'error', + text: Strings.LOADING_SETTINGS_ERROR + }); + } + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.ADD_ROW_BUTTON_CLASS, function(){ + addTableRow($(this).closest('tr')); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.DEL_ROW_BUTTON_CLASS, function(){ + deleteTableRow($(this).closest('tr')); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.ADD_CATEGORY_BUTTON_CLASS, function(){ + addTableCategory($(this).closest('tr')); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.DEL_CATEGORY_BUTTON_CLASS, function(){ + deleteTableCategory($(this).closest('tr')); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.TOGGLE_CATEGORY_COLUMN_CLASS, function(){ + toggleTableCategory($(this).closest('tr')); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_UP_BUTTON_CLASS, function(){ + moveTableRow($(this).closest('tr'), true); + }); + + $('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_DOWN_BUTTON_CLASS, function(){ + moveTableRow($(this).closest('tr'), false); + }); + + $('#' + Settings.FORM_ID).on('keyup', function(e){ + var $target = $(e.target); + if (e.keyCode == 13) { + if ($target.is('table input')) { + // capture enter in table input + // if we have a sibling next to us that has an input, jump to it, otherwise check if we have a glyphicon for add to click + sibling = $target.parent('td').next(); + + if (sibling.hasClass(Settings.DATA_COL_CLASS)) { + // set focus to next input + sibling.find('input').focus(); + } else { + + // jump over the re-order row, if that's what we're on + if (sibling.hasClass(Settings.REORDER_BUTTONS_CLASS)) { + sibling = sibling.next(); + } + + // for tables with categories we add the entry and setup the new row on enter + if (sibling.find("." + Settings.ADD_CATEGORY_BUTTON_CLASS).length) { + sibling.find("." + Settings.ADD_CATEGORY_BUTTON_CLASS).click(); + + // set focus to the first input in the new row + $target.closest('table').find('tr.inputs input:first').focus(); + } + + var tableRows = sibling.parent(); + var tableBody = tableRows.parent(); + + // if theres no more siblings, we should jump to a new row + if (sibling.next().length == 0 && tableRows.nextAll().length == 1) { + tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click(); + } + } + + } else if ($target.is('input')) { + $target.change().blur(); + } + + e.preventDefault(); + } + }); + + $('#' + Settings.FORM_ID).on('keypress', function(e){ + if (e.keyCode == 13) { + + e.preventDefault(); + } + }); + + $('#' + Settings.FORM_ID).on('change keyup paste', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){ + // this input was changed, add the changed data attribute to it + $(this).attr('data-changed', true); + + badgeForDifferences($(this)); + }); + + $('#' + Settings.FORM_ID).on('switchChange.bootstrapSwitch', 'input.toggle-checkbox', function(){ + // this checkbox was changed, add the changed data attribute to it + $(this).attr('data-changed', true); + + badgeForDifferences($(this)); + }); + + // Bootstrap switch in table + $('#' + Settings.FORM_ID).on('change', 'input.table-checkbox', function () { + // Bootstrap switches in table: set the changed data attribute for all rows in table. + var row = $(this).closest('tr'); + if (row.hasClass("value-row")) { // Don't set attribute on input row switches prior to it being added to table. + row.find('td.' + Settings.DATA_COL_CLASS + ' input').attr('data-changed', true); + updateDataChangedForSiblingRows(row, true); + badgeForDifferences($(this)); + } + }); + + $('#' + Settings.FORM_ID).on('change', 'input.table-time', function() { + // Bootstrap switches in table: set the changed data attribute for all rows in table. + var row = $(this).closest('tr'); + if (row.hasClass("value-row")) { // Don't set attribute on input row switches prior to it being added to table. + row.find('td.' + Settings.DATA_COL_CLASS + ' input').attr('data-changed', true); + updateDataChangedForSiblingRows(row, true); + badgeForDifferences($(this)); + } + }); + + $('#' + Settings.FORM_ID).on('change', 'select', function(){ + $("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change(); + }); + + var panelsSource = $('#panels-template').html(); + Settings.panelsTemplate = _.template(panelsSource); +}); + +function dynamicButton(button_id, text) { + return $(""); +} + +function showSpinnerAlert(title) { + swal({ + title: title, + text: '
    ', + html: true, + showConfirmButton: false, + allowEscapeKey: false + }); +} + +function parseJSONResponse(xhr) { + try { + return JSON.parse(xhr.responseText); + } catch (e) { + } + return null; +} + +function validateInputs() { + // check if any new values are bad + var tables = $('table'); + + var inputsValid = true; + + var tables = $('table'); + + // clear any current invalid rows + $('tr.' + Settings.INVALID_ROW_CLASS).removeClass(Settings.INVALID_ROW_CLASS); + + function markParentRowInvalid(rowChild) { + $(rowChild).closest('tr').addClass(Settings.INVALID_ROW_CLASS); + } + + _.each(tables, function(table) { + // validate keys specificially for spaces and equality to an existing key + var newKeys = $(table).find('tr.' + Settings.NEW_ROW_CLASS + ' td.key'); + + var keyWithSpaces = false; + var empty = false; + var duplicateKey = false; + + _.each(newKeys, function(keyCell) { + var keyVal = $(keyCell).children('input').val(); + + if (keyVal.indexOf(' ') !== -1) { + keyWithSpaces = true; + markParentRowInvalid(keyCell); + return; + } + + // make sure the key isn't empty + if (keyVal.length === 0) { + empty = true + + markParentRowInvalid(input); + return; + } + + // make sure we don't have duplicate keys in the table + var otherKeys = $(table).find('td.key').not(keyCell); + _.each(otherKeys, function(otherKeyCell) { + var keyInput = $(otherKeyCell).children('input'); + + if (keyInput.length) { + if ($(keyInput).val() == keyVal) { + duplicateKey = true; + } + } else if ($(otherKeyCell).html() == keyVal) { + duplicateKey = true; + } + + if (duplicateKey) { + markParentRowInvalid(keyCell); + return; + } + }); + + }); + + if (keyWithSpaces) { + showErrorMessage("Error", "Key contains spaces"); + inputsValid = false; + return + } + + if (empty) { + showErrorMessage("Error", "Empty field(s)"); + inputsValid = false; + return + } + + if (duplicateKey) { + showErrorMessage("Error", "Two keys cannot be identical"); + inputsValid = false; + return; + } + }); + + return inputsValid; +} + +var SETTINGS_ERROR_MESSAGE = "There was a problem saving domain settings. Please try again!"; + +function saveSettings() { + + if (validateInputs()) { + // POST the form JSON to the domain-server settings.json endpoint so the settings are saved + var canPost = true; + + // disable any inputs not changed + $("input:not([data-changed])").each(function () { + $(this).prop('disabled', true); + }); + + // grab a JSON representation of the form via form2js + var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true); + + // re-enable all inputs + $("input").each(function () { + $(this).prop('disabled', false); + }); + + // remove focus from the button + $(this).blur(); + + if (Settings.handlePostSettings === undefined) { + console.log("----- saveSettings() called ------"); + console.log(formJSON); + + // POST the form JSON to the domain-server settings.json endpoint so the settings are saved + postSettings(formJSON); + } else { + Settings.handlePostSettings(formJSON) + } + } +} + +$('body').on('click', '.save-button', function(e){ + saveSettings(); + return false; +}); + +function makeTable(setting, keypath, setting_value) { + var isArray = !_.has(setting, 'key'); + var categoryKey = setting.categorize_by_key; + var isCategorized = !!categoryKey && isArray; + + if (!isArray && setting.can_order) { + setting.can_order = false; + } + + var html = ""; + + if (setting.help) { + html += "" + setting.help + "" + } + + var nonDeletableRowKey = setting["non-deletable-row-key"]; + var nonDeletableRowValues = setting["non-deletable-row-values"]; + + html += ""; + + if (setting.caption) { + html += "" + } + + // Column groups + if (setting.groups) { + html += "" + _.each(setting.groups, function (group) { + html += "" + }) + if (!setting.read_only) { + if (setting.can_order) { + html += ""; + } + html += "" + } + html += "" + } + + // Column names + html += "" + + if (setting.numbered === true) { + html += "" // Row number + } + + if (setting.key) { + html += "" // Key + } + + var numVisibleColumns = 0; + _.each(setting.columns, function(col) { + if (!col.hidden) numVisibleColumns++; + html += "" // Data + }) + + if (!setting.read_only) { + if (setting.can_order) { + numVisibleColumns++; + html += ""; + } + numVisibleColumns++; + html += ""; + } + + // populate rows in the table from existing values + var row_num = 1; + + if (keypath.length > 0 && _.size(setting_value) > 0) { + var rowIsObject = setting.columns.length > 1; + + _.each(setting_value, function(row, rowIndexOrName) { + var categoryPair = {}; + var categoryValue = ""; + if (isCategorized) { + categoryValue = rowIsObject ? row[categoryKey] : row; + categoryPair[categoryKey] = categoryValue; + if (_.findIndex(setting_value, categoryPair) === rowIndexOrName) { + html += makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, setting.can_add_new_categories, ""); + } + } + + html += ""; + + if (setting.numbered === true) { + html += "" + } + + if (setting.key) { + html += "" + } + + var isNonDeletableRow = !setting.can_add_new_rows; + + _.each(setting.columns, function(col) { + + var colValue, colName; + if (isArray) { + colValue = rowIsObject ? row[col.name] : row; + colName = keypath + "[" + rowIndexOrName + "]" + (rowIsObject ? "." + col.name : ""); + } else { + colValue = row[col.name]; + colName = keypath + "." + rowIndexOrName + "." + col.name; + } + + isNonDeletableRow = isNonDeletableRow + || (nonDeletableRowKey === col.name && nonDeletableRowValues.indexOf(colValue) !== -1); + + if (isArray && col.type === "checkbox" && col.editable) { + html += + ""; + } else if (isArray && col.type === "time" && col.editable) { + html += + ""; + } else { + // Use a hidden input so that the values are posted. + html += + ""; + } + + }); + + if (!setting.read_only) { + if (setting.can_order) { + html += "" + } + if (isNonDeletableRow) { + html += ""; + } else { + html += ""; + } + } + + html += "" + + if (isCategorized && setting.can_add_new_rows && _.findLastIndex(setting_value, categoryPair) === rowIndexOrName) { + html += makeTableInputs(setting, categoryPair, categoryValue); + } + + row_num++ + }); + } + + // populate inputs in the table for new values + if (!setting.read_only) { + if (setting.can_add_new_categories) { + html += makeTableCategoryInput(setting, numVisibleColumns); + } + + if (setting.can_add_new_rows || setting.can_add_new_categories) { + html += makeTableHiddenInputs(setting, {}, ""); + } + } + html += "
    " + setting.caption + "
    " + group.label + "
    #" + setting.key.label + "" + col.label + "
    " + row_num + "" + rowIndexOrName + "" + + "" + + "" + + "" + + "" + + colValue + + "" + + "" + + "
    " + + return html; +} + +function makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, canRemove, message) { + var html = + "" + + "" + + "" + + "" + categoryValue + "" + + "" + + ((canRemove) ? ( + "" + + "" + + "" + ) : ( + "" + )) + + ""; + return html; +} + +function makeTableHiddenInputs(setting, initialValues, categoryValue) { + var html = ""; + + if (setting.numbered === true) { + html += ""; + } + + if (setting.key) { + html += "\ + \ + " + } + + _.each(setting.columns, function(col) { + var defaultValue = _.has(initialValues, col.name) ? initialValues[col.name] : col.default; + if (col.type === "checkbox") { + html += + "" + + "" + + ""; + } else if (col.type === "select") { + html += "" + html += ""; + html += ""; + } else { + html += + "" + + "" + + ""; + } + }) + + if (setting.can_order) { + html += "" + } + html += "" + html += "" + + return html +} + +function makeTableCategoryInput(setting, numVisibleColumns) { + var canAddRows = setting.can_add_new_rows; + var categoryKey = setting.categorize_by_key; + var placeholder = setting.new_category_placeholder || ""; + var message = setting.new_category_message || ""; + var html = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + return html; +} + +function getDescriptionForKey(key) { + for (var i in Settings.data.descriptions) { + if (Settings.data.descriptions[i].name === key) { + return Settings.data.descriptions[i]; + } + } +} + +var SAVE_BUTTON_LABEL_SAVE = "Save"; +var SAVE_BUTTON_LABEL_RESTART = "Save and restart"; +var reasonsForRestart = []; +var numChangesBySection = {}; + +function badgeForDifferences(changedElement) { + // figure out which group this input is in + var panelParentID = changedElement.closest('.panel').attr('id'); + + // if the panel contains non-grouped settings, the initial value is Settings.initialValues + var isGrouped = $('#' + panelParentID).hasClass('grouped'); + + if (isGrouped) { + var initialPanelJSON = Settings.initialValues[panelParentID] + ? Settings.initialValues[panelParentID] + : {}; + + // get a JSON representation of that section + var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID]; + } else { + var initialPanelJSON = Settings.initialValues; + + // get a JSON representation of that section + var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true); + } + + var badgeValue = 0 + var description = getDescriptionForKey(panelParentID); + + // badge for any settings we have that are not the same or are not present in initialValues + for (var setting in panelJSON) { + if ((!_.has(initialPanelJSON, setting) && panelJSON[setting] !== "") || + (!_.isEqual(panelJSON[setting], initialPanelJSON[setting]) + && (panelJSON[setting] !== "" || _.has(initialPanelJSON, setting)))) { + badgeValue += 1; + + // add a reason to restart + if (description && description.restart != false) { + reasonsForRestart.push(setting); + } + } else { + // remove a reason to restart + if (description && description.restart != false) { + reasonsForRestart = $.grep(reasonsForRestart, function(v) { return v != setting; }); + } + } + } + + // update the list-group-item badge to have the new value + if (badgeValue == 0) { + badgeValue = "" + } + + numChangesBySection[panelParentID] = badgeValue; + + var hasChanges = badgeValue > 0; + + if (!hasChanges) { + for (var key in numChangesBySection) { + if (numChangesBySection[key] > 0) { + hasChanges = true; + break; + } + } + } + + $(".save-button").prop("disabled", !hasChanges); + $(".save-button").html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE); + + // add the badge to the navbar item and the panel header + $("a[href='" + settingsGroupAnchor(Settings.path, panelParentID) + "'] .badge").html(badgeValue); + $("#" + panelParentID + " .panel-heading .badge").html(badgeValue); + + // make the navbar dropdown show a badge that is the total of the badges of all groups + var totalChanges = 0; + $('.panel-heading .badge').each(function(index){ + if (this.innerHTML.length > 0) { + totalChanges += parseInt(this.innerHTML); + } + }); + + if (totalChanges == 0) { + totalChanges = "" + } + + var totalBadgeClass = Settings.content_settings ? '.content-settings-badge' : '.domain-settings-badge'; + + $(totalBadgeClass).html(totalChanges); + $('#hamburger-badge').html(totalChanges); +} + +function addTableRow(row) { + var table = row.parents('table'); + var isArray = table.data('setting-type') === 'array'; + var keepField = row.data("keep-field"); + + var columns = row.parent().children('.' + Settings.DATA_ROW_CLASS); + + var input_clone = row.clone(); + + // Change input row to data row + var table = row.parents("table"); + var setting_name = table.attr("name"); + row.addClass(Settings.DATA_ROW_CLASS + " " + Settings.NEW_ROW_CLASS); + + if (!isArray) { + // show the key input + var keyInput = row.children(".key").children("input"); + + // whenever the keyInput changes, re-badge for differences + keyInput.on('change keyup paste', function(){ + // update siblings in the row to have the correct name + var currentKey = $(this).val(); + + $(this).closest('tr').find('.value-col input').each(function(index){ + var input = $(this); + + if (currentKey.length > 0) { + input.attr("name", setting_name + "." + currentKey + "." + input.parent().attr('name')); + } else { + input.removeAttr("name"); + } + }) + + badgeForDifferences($(this)); + }); + } + + // if this is an array, add the row index (which is the index of the last row + 1) + // as a data attribute to the row + var row_index = 0; + if (isArray) { + var previous_row = row.siblings('.' + Settings.DATA_ROW_CLASS + ':last'); + + if (previous_row.length > 0) { + row_index = parseInt(previous_row.attr(Settings.DATA_ROW_INDEX), 10) + 1; + } else { + row_index = 0; + } + + row.attr(Settings.DATA_ROW_INDEX, row_index); + } + + var focusChanged = false; + + _.each(row.children(), function(element) { + if ($(element).hasClass("numbered")) { + // Index row + var numbers = columns.children(".numbered") + if (numbers.length > 0) { + $(element).html(parseInt(numbers.last().text()) + 1) + } else { + $(element).html(1) + } + } else if ($(element).hasClass(Settings.REORDER_BUTTONS_CLASS)) { + $(element).html("") + } else if ($(element).hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) { + // Change buttons + var anchor = $(element).children("a") + anchor.removeClass(Settings.ADD_ROW_SPAN_CLASSES) + anchor.addClass(Settings.DEL_ROW_SPAN_CLASSES) + } else if ($(element).hasClass("key")) { + var input = $(element).children("input") + input.show(); + } else if ($(element).hasClass(Settings.DATA_COL_CLASS)) { + // show inputs + var input = $(element).find("input"); + input.show(); + + var isCheckbox = input.hasClass("table-checkbox"); + var isDropdown = input.hasClass("table-dropdown"); + + if (isArray) { + var key = $(element).attr('name'); + + // are there multiple columns or just one? + // with multiple we have an array of Objects, with one we have an array of whatever the value type is + var num_columns = row.children('.' + Settings.DATA_COL_CLASS).length + var newName = setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : ""); + + input.attr("name", newName); + + if (isDropdown) { + // default values for hidden inputs inside child selects gets cleared so we need to remind it + var selectElement = $(element).children("select"); + selectElement.attr("data-hidden-input", newName); + $(element).children("input").val(selectElement.val()); + } + } + + if (isArray && !focusChanged) { + input.focus(); + focusChanged = true; + } + + // if we are adding a dropdown, we should go ahead and make its select + // element is visible + if (isDropdown) { + $(element).children("select").attr("style", ""); + } + + if (isCheckbox) { + $(input).find("input").attr("data-changed", "true"); + } else { + input.attr("data-changed", "true"); + } + } else { + console.log("Unknown table element"); + } + }); + + if (!isArray) { + keyInput.focus(); + } + + input_clone.children('td').each(function () { + if ($(this).attr("name") !== keepField) { + $(this).find("input").val($(this).children('input').attr('data-default')); + } + }); + + if (isArray) { + updateDataChangedForSiblingRows(row, true) + + // the addition of any table row should remove the empty-array-row + row.siblings('.empty-array-row').remove() + } + + badgeForDifferences($(table)) + + row.after(input_clone) +} + +function deleteTableRow($row) { + var $table = $row.closest('table'); + var categoryName = $row.data("category"); + var isArray = $table.data('setting-type') === 'array'; + + $row.empty(); + + if (!isArray) { + if ($row.attr('name')) { + $row.html(""); + } else { + // for rows that didn't have a key, simply remove the row + $row.remove(); + } + } else { + if ($table.find('.' + Settings.DATA_ROW_CLASS + "[data-category='" + categoryName + "']").length <= 1) { + // This is the last row of the category, so delete the header + $table.find('.' + Settings.DATA_CATEGORY_CLASS + "[data-category='" + categoryName + "']").remove(); + } + + if ($table.find('.' + Settings.DATA_ROW_CLASS).length > 1) { + updateDataChangedForSiblingRows($row); + + // this isn't the last row - we can just remove it + $row.remove(); + } else { + // this is the last row, we can't remove it completely since we need to post an empty array + $row + .removeClass(Settings.DATA_ROW_CLASS) + .removeClass(Settings.NEW_ROW_CLASS) + .removeAttr("data-category") + .addClass('empty-array-row') + .html(""); + } + } + + // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated + badgeForDifferences($table); +} + +function addTableCategory($categoryInputRow) { + var $input = $categoryInputRow.find("input").first(); + var categoryValue = $input.prop("value"); + if (!categoryValue || $categoryInputRow.closest("table").find("tr[data-category='" + categoryValue + "']").length !== 0) { + $categoryInputRow.addClass("has-warning"); + + setTimeout(function () { + $categoryInputRow.removeClass("has-warning"); + }, 400); + + return; + } + + var $rowInput = $categoryInputRow.next(".inputs").clone(); + if (!$rowInput) { + console.error("Error cloning inputs"); + } + + var canAddRows = $categoryInputRow.data("can-add-rows"); + var message = $categoryInputRow.data("message"); + var categoryKey = $categoryInputRow.data("key"); + var width = 0; + $categoryInputRow + .children("td") + .each(function () { + width += $(this).prop("colSpan") || 1; + }); + + $input + .prop("value", "") + .focus(); + + $rowInput.find("td[name='" + categoryKey + "'] > input").first() + .prop("value", categoryValue); + $rowInput + .attr("data-category", categoryValue) + .addClass(Settings.NEW_ROW_CLASS); + + var $newCategoryRow = $(makeTableCategoryHeader(categoryKey, categoryValue, width, true, " - " + message)); + $newCategoryRow.addClass(Settings.NEW_ROW_CLASS); + + $categoryInputRow + .before($newCategoryRow) + .before($rowInput); + + if (canAddRows) { + $rowInput.removeAttr("hidden"); + } else { + addTableRow($rowInput); + } +} + +function deleteTableCategory($categoryHeaderRow) { + var categoryName = $categoryHeaderRow.data("category"); + + $categoryHeaderRow + .closest("table") + .find("tr[data-category='" + categoryName + "']") + .each(function () { + if ($(this).hasClass(Settings.DATA_ROW_CLASS)) { + deleteTableRow($(this)); + } else { + $(this).remove(); + } + }); +} + +function toggleTableCategory($categoryHeaderRow) { + var $icon = $categoryHeaderRow.find("." + Settings.TOGGLE_CATEGORY_SPAN_CLASS).first(); + var categoryName = $categoryHeaderRow.data("category"); + var wasExpanded = $icon.hasClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS); + if (wasExpanded) { + $icon + .addClass(Settings.TOGGLE_CATEGORY_CONTRACTED_CLASS) + .removeClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS); + } else { + $icon + .addClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS) + .removeClass(Settings.TOGGLE_CATEGORY_CONTRACTED_CLASS); + } + $categoryHeaderRow + .closest("table") + .find("tr[data-category='" + categoryName + "']") + .toggleClass("contracted", wasExpanded); +} + +function moveTableRow(row, move_up) { + var table = $(row).closest('table') + var isArray = table.data('setting-type') === 'array' + if (!isArray) { + return; + } + + if (move_up) { + var prev_row = row.prev() + if (prev_row.hasClass(Settings.DATA_ROW_CLASS)) { + prev_row.before(row) + } + } else { + var next_row = row.next() + if (next_row.hasClass(Settings.DATA_ROW_CLASS)) { + next_row.after(row) + } + } + + // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated + badgeForDifferences($(table)) +} + +function updateDataChangedForSiblingRows(row, forceTrue) { + // anytime a new row is added to an array we need to set data-changed for all sibling row inputs to true + // unless it matches the inital set of values + + if (!forceTrue) { + // figure out which group this row is in + var panelParentID = row.closest('.panel').attr('id') + // get the short name for the setting from the table + var tableShortName = row.closest('table').data('short-name') + + // get a JSON representation of that section + var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName] + if (Settings.initialValues[panelParentID]) { + var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] + } else { + var initialPanelSettingJSON = {}; + } + + // if they are equal, we don't need data-changed + isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON) + } else { + isTrue = true + } + + row.siblings('.' + Settings.DATA_ROW_CLASS).each(function(){ + var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input') + if (isTrue) { + hiddenInput.attr('data-changed', isTrue) + } else { + hiddenInput.removeAttr('data-changed') + } + }) +} + +function cleanupFormValues(node) { + if (node.type && node.type === 'checkbox') { + return { name: node.name, value: node.checked ? true : false }; + } else { + return false; + } +} + +function showErrorMessage(title, message) { + swal(title, message) +} diff --git a/domain-server/resources/web/settings/js/bootstrap-switch.min.js b/domain-server/resources/web/js/bootstrap-switch.min.js similarity index 100% rename from domain-server/resources/web/settings/js/bootstrap-switch.min.js rename to domain-server/resources/web/js/bootstrap-switch.min.js diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index ad1509b038..aa658bce3f 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -23,16 +23,22 @@ function showRestartModal() { }, 1000); } +function settingsGroupAnchor(base, html_id) { + return base + "#" + html_id + "_group" +} + $(document).ready(function(){ var url = window.location; + // Will only work if string in href matches with location $('ul.nav a[href="'+ url +'"]').parent().addClass('active'); // Will also work for relative and absolute hrefs $('ul.nav a').filter(function() { return this.href == url; - }).parent().addClass('active'); - $('body').on('click', '#restart-server', function(e) { + }).parent().addClass('active'); + + $('body').on('click', '#restart-server', function(e) { swal( { title: "Are you sure?", text: "This will restart your domain server, causing your domain to be briefly offline.", @@ -45,4 +51,35 @@ $(document).ready(function(){ }); return false; }); + + var $contentDropdown = $('#content-settings-nav-dropdown'); + var $settingsDropdown = $('#domain-settings-nav-dropdown'); + + // for pages that have the settings dropdowns + if ($contentDropdown.length && $settingsDropdown.length) { + // make a JSON request to get the dropdown menus for content and settings + // we don't error handle here because the top level menu is still clickable and usables if this fails + $.getJSON('/settings-menu-groups.json', function(data){ + function makeGroupDropdownElement(group, base) { + var html_id = group.html_id ? group.html_id : group.name; + return "
  • " + group.label + "
  • "; + } + + $.each(data.content_settings, function(index, group){ + if (index > 0) { + $contentDropdown.append(""); + } + + $contentDropdown.append(makeGroupDropdownElement(group, "/content/")); + }); + + $.each(data.domain_settings, function(index, group){ + if (index > 0) { + $settingsDropdown.append(""); + } + + $settingsDropdown.append(makeGroupDropdownElement(group, "/settings/")); + }); + }); + } }); diff --git a/domain-server/resources/web/settings/js/form2js.min.js b/domain-server/resources/web/js/form2js.min.js similarity index 100% rename from domain-server/resources/web/settings/js/form2js.min.js rename to domain-server/resources/web/js/form2js.min.js diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index 00f699fa4e..e1870a2fa8 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -1,6 +1,4 @@ -var Settings = { - showAdvanced: false, - ADVANCED_CLASS: 'advanced-setting', +Object.assign(Settings, { DEPRECATED_CLASS: 'deprecated-setting', TRIGGER_CHANGE_CLASS: 'trigger-change', DATA_ROW_CLASS: 'value-row', @@ -41,7 +39,7 @@ var Settings = { FORM_ID: 'settings-form', INVALID_ROW_CLASS: 'invalid-input', DATA_ROW_INDEX: 'data-row-index' -}; +}); var URLs = { // STABLE METAVERSE_URL: https://metaverse.highfidelity.com diff --git a/domain-server/resources/web/js/underscore-min.js b/domain-server/resources/web/js/underscore-min.js index f01025b7bc..3c3eec027b 100644 --- a/domain-server/resources/web/js/underscore-min.js +++ b/domain-server/resources/web/js/underscore-min.js @@ -3,4 +3,3 @@ // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this); -//# sourceMappingURL=underscore-min.map \ No newline at end of file diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index d36330375a..d71692523a 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -1,104 +1,21 @@ -
    -
    -
    - -
    -
    + -
    -
    -
    - - - - - - - -
    -
    - -
    -
    - - - -
    - - -
    -
    -
    -
    - - -
    + - - - + - - - - + + + + + diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 3faeff4482..9a31b766a6 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1,1262 +1,20 @@ -var DomainInfo = null; - -var viewHelpers = { - getFormGroup: function(keypath, setting, values, isAdvanced) { - form_group = "
    "; - setting_value = _(values).valueForKeyPath(keypath); - - if (_.isUndefined(setting_value) || _.isNull(setting_value)) { - if (_.has(setting, 'default')) { - setting_value = setting.default; - } else { - setting_value = ""; - } - } - - label_class = 'control-label'; - - function common_attrs(extra_classes) { - extra_classes = (!_.isUndefined(extra_classes) ? extra_classes : ""); - return " class='" + (setting.type !== 'checkbox' ? 'form-control' : '') - + " " + Settings.TRIGGER_CHANGE_CLASS + " " + extra_classes + "' data-short-name='" - + setting.name + "' name='" + keypath + "' " - + "id='" + (!_.isUndefined(setting.html_id) ? setting.html_id : keypath) + "'"; - } - - if (setting.type === 'checkbox') { - if (setting.label) { - form_group += "" - } - - form_group += "
    " - form_group += "" - - if (setting.help) { - form_group += "" + setting.help + ""; - } - - form_group += "
    " - } else { - input_type = _.has(setting, 'type') ? setting.type : "text" - - if (setting.label) { - form_group += ""; - } - - if (input_type === 'table') { - form_group += makeTable(setting, keypath, setting_value) - } else { - if (input_type === 'select') { - form_group += "" - - form_group += "" - } else if (input_type === 'button') { - // Is this a button that should link to something directly? - // If so, we use an anchor tag instead of a button tag - - if (setting.href) { - form_group += "" - + setting.button_label + ""; - } else { - form_group += ""; - } - - } else { - - if (input_type == 'integer') { - input_type = "text" - } - - form_group += "" - } - - form_group += "" + setting.help + "" - } - } - - form_group += "
    " - return form_group - } -} - -var qs = (function(a) { - if (a == "") return {}; - var b = {}; - for (var i = 0; i < a.length; ++i) - { - var p=a[i].split('=', 2); - if (p.length == 1) { - b[p[0]] = ""; - } else { - b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); - } - } - return b; -})(window.location.search.substr(1).split('&')); - $(document).ready(function(){ - /* - * Clamped-width. - * Usage: - *
    This long content will force clamped width
    - * - * Author: LV - */ - - $.ajaxSetup({ - timeout: 20000, - }); - - $('[data-clampedwidth]').each(function () { - var elem = $(this); - var parentPanel = elem.data('clampedwidth'); - var resizeFn = function () { - var sideBarNavWidth = $(parentPanel).width() - parseInt(elem.css('paddingLeft')) - parseInt(elem.css('paddingRight')) - parseInt(elem.css('marginLeft')) - parseInt(elem.css('marginRight')) - parseInt(elem.css('borderLeftWidth')) - parseInt(elem.css('borderRightWidth')); - elem.css('width', sideBarNavWidth); - }; - - resizeFn(); - $(window).resize(resizeFn); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.ADD_ROW_BUTTON_CLASS, function(){ - addTableRow($(this).closest('tr')); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.DEL_ROW_BUTTON_CLASS, function(){ - deleteTableRow($(this).closest('tr')); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.ADD_CATEGORY_BUTTON_CLASS, function(){ - addTableCategory($(this).closest('tr')); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.DEL_CATEGORY_BUTTON_CLASS, function(){ - deleteTableCategory($(this).closest('tr')); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.TOGGLE_CATEGORY_COLUMN_CLASS, function(){ - toggleTableCategory($(this).closest('tr')); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_UP_BUTTON_CLASS, function(){ - moveTableRow($(this).closest('tr'), true); - }); - - $('#' + Settings.FORM_ID).on('click', '.' + Settings.MOVE_DOWN_BUTTON_CLASS, function(){ - moveTableRow($(this).closest('tr'), false); - }); - - $('#' + Settings.FORM_ID).on('keyup', function(e){ - var $target = $(e.target); - if (e.keyCode == 13) { - if ($target.is('table input')) { - // capture enter in table input - // if we have a sibling next to us that has an input, jump to it, otherwise check if we have a glyphicon for add to click - sibling = $target.parent('td').next(); - - if (sibling.hasClass(Settings.DATA_COL_CLASS)) { - // set focus to next input - sibling.find('input').focus(); - } else { - - // jump over the re-order row, if that's what we're on - if (sibling.hasClass(Settings.REORDER_BUTTONS_CLASS)) { - sibling = sibling.next(); - } - - // for tables with categories we add the entry and setup the new row on enter - if (sibling.find("." + Settings.ADD_CATEGORY_BUTTON_CLASS).length) { - sibling.find("." + Settings.ADD_CATEGORY_BUTTON_CLASS).click(); - - // set focus to the first input in the new row - $target.closest('table').find('tr.inputs input:first').focus(); - } - - var tableRows = sibling.parent(); - var tableBody = tableRows.parent(); - - // if theres no more siblings, we should jump to a new row - if (sibling.next().length == 0 && tableRows.nextAll().length == 1) { - tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click(); - } - } - - } else if ($target.is('input')) { - $target.change().blur(); - } - - e.preventDefault(); - } - }); - - $('#' + Settings.FORM_ID).on('keypress', function(e){ - if (e.keyCode == 13) { - - e.preventDefault(); - } - }); - - $('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){ - // this input was changed, add the changed data attribute to it - $(this).attr('data-changed', true); - - badgeSidebarForDifferences($(this)); - }); - - $('#' + Settings.FORM_ID).on('switchChange.bootstrapSwitch', 'input.toggle-checkbox', function(){ - // this checkbox was changed, add the changed data attribute to it - $(this).attr('data-changed', true); - - badgeSidebarForDifferences($(this)); - }); - - // Bootstrap switch in table - $('#' + Settings.FORM_ID).on('change', 'input.table-checkbox', function () { - // Bootstrap switches in table: set the changed data attribute for all rows in table. - var row = $(this).closest('tr'); - if (row.hasClass("value-row")) { // Don't set attribute on input row switches prior to it being added to table. - row.find('td.' + Settings.DATA_COL_CLASS + ' input').attr('data-changed', true); - updateDataChangedForSiblingRows(row, true); - badgeSidebarForDifferences($(this)); - } - }); - - $('#' + Settings.FORM_ID).on('change', 'input.table-time', function() { - // Bootstrap switches in table: set the changed data attribute for all rows in table. - var row = $(this).closest('tr'); - if (row.hasClass("value-row")) { // Don't set attribute on input row switches prior to it being added to table. - row.find('td.' + Settings.DATA_COL_CLASS + ' input').attr('data-changed', true); - updateDataChangedForSiblingRows(row, true); - badgeSidebarForDifferences($(this)); - } - }); - - $('.advanced-toggle').click(function(){ - Settings.showAdvanced = !Settings.showAdvanced - var advancedSelector = $('.' + Settings.ADVANCED_CLASS) - - if (Settings.showAdvanced) { - advancedSelector.show(); - $(this).html("Hide advanced") - } else { - advancedSelector.hide(); - $(this).html("Show advanced") - } - - $(this).blur(); - }) - - $('#' + Settings.FORM_ID).on('click', '#' + Settings.CREATE_DOMAIN_ID_BTN_ID, function(){ - $(this).blur(); - showDomainCreationAlert(false); - }) - - $('#' + Settings.FORM_ID).on('click', '#' + Settings.CHOOSE_DOMAIN_ID_BTN_ID, function(){ - $(this).blur(); - chooseFromHighFidelityDomains($(this)) - }); - - $('#' + Settings.FORM_ID).on('click', '#' + Settings.GET_TEMPORARY_NAME_BTN_ID, function(){ - $(this).blur(); - createTemporaryDomain(); - }); - - - $('#' + Settings.FORM_ID).on('change', 'select', function(){ - $("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change() - }); - - $('#' + Settings.FORM_ID).on('click', '#' + Settings.DISCONNECT_ACCOUNT_BTN_ID, function(e){ - $(this).blur(); - disonnectHighFidelityAccount(); - e.preventDefault(); - }); - - $('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){ - $(this).blur(); - prepareAccessTokenPrompt(function(accessToken) { - // we have an access token - set the access token input with this and save settings - $(Settings.ACCESS_TOKEN_SELECTOR).val(accessToken).change(); - saveSettings(); - }); - }); - - var panelsSource = $('#panels-template').html() - Settings.panelsTemplate = _.template(panelsSource) - - var sidebarTemplate = $('#list-group-template').html() - Settings.sidebarTemplate = _.template(sidebarTemplate) - - var navbarHeight = $('.navbar').outerHeight(true); - - $('#setup-sidebar').affix({ - offset: { - top: 1, - bottom: navbarHeight - } - }); - - reloadSettings(function(success){ - if (success) { - handleAction(); - } else { - swal({ - title: '', - type: 'error', - text: Strings.LOADING_SETTINGS_ERROR - }); - } - $('body').scrollspy({ - target: '#setup-sidebar', - offset: navbarHeight - }); - }); -}); - -function getShareName(callback) { - getDomainFromAPI(function(data){ - // check if we have owner_places (for a real domain) or a name (for a temporary domain) - if (data && data.status == "success") { - var shareName; - if (data.domain.default_place_name) { - shareName = data.domain.default_place_name; - } else if (data.domain.name) { - shareName = data.domain.name; - } else if (data.domain.network_address) { - shareName = data.domain.network_address; - if (data.domain.network_port !== 40102) { - shareName += ':' + data.domain.network_port; - } - } - - callback(true, shareName); - } else { - callback(false); - } - }) -} - -function handleAction() { - // check if we were passed an action to handle - var action = qs["action"]; - - if (action == "share") { - // figure out if we already have a stored domain ID - if (Settings.data.values.metaverse.id.length > 0) { - // we need to ask the API what a shareable name for this domain is - getShareName(function(success, shareName){ - if (success) { - var shareLink = "hifi://" + shareName; - - console.log(shareLink); - - // show a dialog with a copiable share URL - swal({ - title: "Share", - type: "input", - inputPlaceholder: shareLink, - inputValue: shareLink, - text: "Copy this URL to invite friends to your domain.", - closeOnConfirm: true - }); - - $('.sweet-alert input').select(); - - } else { - // show an error alert - swal({ - title: '', - type: 'error', - text: "There was a problem retreiving domain information from High Fidelity API.", - confirmButtonText: 'Try again', - showCancelButton: true, - closeOnConfirm: false - }, function(isConfirm){ - if (isConfirm) { - // they want to try getting domain share info again - showSpinnerAlert("Requesting domain information...") - handleAction(); - } else { - swal.close(); - } - }); - } - }); - } else { - // no domain ID present, just show the share dialog - createTemporaryDomain(); - } - } -} - -function dynamicButton(button_id, text) { - return $(""); -} - -function postSettings(jsonSettings) { - // POST the form JSON to the domain-server settings.json endpoint so the settings are saved - $.ajax('/settings.json', { - data: JSON.stringify(jsonSettings), - contentType: 'application/json', - type: 'POST' - }).done(function(data){ - if (data.status == "success") { - if ($(".save-button").html() === SAVE_BUTTON_LABEL_RESTART) { - showRestartModal(); - } else { - location.reload(true); - } - } else { - showErrorMessage("Error", SETTINGS_ERROR_MESSAGE) - reloadSettings(); - } - }).fail(function(){ - showErrorMessage("Error", SETTINGS_ERROR_MESSAGE) - reloadSettings(); - }); -} - -function accessTokenIsSet() { - return Settings.data.values.metaverse.access_token.length > 0; -} - -function setupHFAccountButton() { - - var hasAccessToken = accessTokenIsSet(); - var el; - - if (hasAccessToken) { - el = "

    "; - el += ""; - el += ""; - el += "

    "; - el = $(el); - } else { - // setup an object for the settings we want our button to have - var buttonSetting = { - type: 'button', - name: 'connected_account', - label: 'Connected Account', - } - buttonSetting.help = ""; - buttonSetting.classes = "btn-primary"; - buttonSetting.button_label = "Connect High Fidelity Account"; - buttonSetting.html_id = Settings.CONNECT_ACCOUNT_BTN_ID; - - buttonSetting.href = URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true"; - - // since we do not have an access token we change hide domain ID and auto networking settings - // without an access token niether of them can do anything - $("[data-keypath='metaverse.id']").hide(); - - // use the existing getFormGroup helper to ask for a button - el = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values); - } - - // add the button group to the top of the metaverse panel - $('#metaverse .panel-body').prepend(el); -} - -function disonnectHighFidelityAccount() { - // the user clicked on the disconnect account btn - give them a sweet alert to make sure this is what they want to do - swal({ - title: "Are you sure?", - text: "This will remove your domain-server OAuth access token." - + "

    This could cause your domain to appear offline and no longer be reachable via any place names.", - type: "warning", - html: true, - showCancelButton: true - }, function(){ - // we need to post to settings to clear the access-token - $(Settings.ACCESS_TOKEN_SELECTOR).val('').change(); - // reset the domain id to get a new temporary name - $(Settings.DOMAIN_ID_SELECTOR).val('').change(); - saveSettings(); - }); -} - -function showSpinnerAlert(title) { - swal({ - title: title, - text: '
    ', - html: true, - showConfirmButton: false, - allowEscapeKey: false - }); -} - -function showDomainCreationAlert(justConnected) { - swal({ - title: 'Create new domain ID', - type: 'input', - text: 'Enter a label this machine.

    This will help you identify which domain ID belongs to which machine.

    ', - showCancelButton: true, - confirmButtonText: "Create", - closeOnConfirm: false, - html: true - }, function(inputValue){ - if (inputValue === false) { - swal.close(); - - // user cancelled domain ID creation - if we're supposed to save after cancel then save here - if (justConnected) { - saveSettings(); - } - } else { - // we're going to change the alert to a new one with a spinner while we create this domain - showSpinnerAlert('Creating domain ID'); - createNewDomainID(inputValue, justConnected); - } - }); -} - -function createNewDomainID(label, justConnected) { - // get the JSON object ready that we'll use to create a new domain - var domainJSON = { - "label": label - } - - $.post("/api/domains", domainJSON, function(data){ - // we successfully created a domain ID, set it on that field - var domainID = data.domain.id; - console.log("Setting domain id to ", data, domainID); - $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); - - if (justConnected) { - var successText = Strings.CREATE_DOMAIN_SUCCESS_JUST_CONNECTED - } else { - var successText = Strings.CREATE_DOMAIN_SUCCESS; - } - - successText += "

    Click the button below to save your new settings and restart your domain-server."; - - // show a sweet alert to say we are all finished up and that we need to save - swal({ - title: 'Success!', - type: 'success', - text: successText, - html: true, - confirmButtonText: 'Save' - }, function(){ - saveSettings(); - }); - }, 'json').fail(function(){ - - var errorText = "There was a problem creating your new domain ID. Do you want to try again or"; - - if (justConnected) { - errorText += " just save your new access token?

    You can always create a new domain ID later."; - } else { - errorText += " cancel?" - } - - // we failed to create the new domain ID, show a sweet-alert that lets them try again or cancel - swal({ - title: '', - type: 'error', - text: errorText, - html: true, - confirmButtonText: 'Try again', - showCancelButton: true, - closeOnConfirm: false - }, function(isConfirm){ - if (isConfirm) { - // they want to try creating a domain ID again - showDomainCreationAlert(justConnected); - } else { - // they want to cancel - if (justConnected) { - // since they just connected we need to save the access token here - saveSettings(); - } - } - }); - }); -} - -function createDomainSpinner() { - var spinner = ''; - return spinner; -} - -function createDomainLoadingError(message) { - var errorEl = $(""); - errorEl.append(message + " "); - - var retryLink = $("Please click here to try again."); - retryLink.click(function(ev) { - ev.preventDefault(); - reloadDomainInfo(); - }); - errorEl.append(retryLink); - - return errorEl; -} - -function parseJSONResponse(xhr) { - try { - return JSON.parse(xhr.responseText); - } catch (e) { - } - return null; -} - -function showOrHideLabel() { - var type = getCurrentDomainIDType(); - var shouldShow = accessTokenIsSet() && (type === DOMAIN_ID_TYPE_FULL || type === DOMAIN_ID_TYPE_UNKNOWN); - $(".panel#label").toggle(shouldShow); - $("li a[href='#label']").parent().toggle(shouldShow); - return shouldShow; -} - -function setupDomainLabelSetting() { - showOrHideLabel(); - - var html = "
    " - html += " Edit"; - html += ""; - html += "
    "; - - html = $(html); - - html.find('a').click(function(ev) { - ev.preventDefault(); - - var label = DomainInfo.label === null ? "" : DomainInfo.label; - var modal_body = "
    "; - modal_body += ""; - modal_body += ""; - modal_body += "
    "; - modal_body += "
    "; - - var dialog = bootbox.dialog({ - title: 'Edit Label', - message: modal_body, - closeButton: false, - onEscape: true, - buttons: [ - { - label: 'Cancel', - className: 'edit-label-cancel-btn', - callback: function() { - dialog.modal('hide'); - } - }, - { - label: 'Save', - className: 'edit-label-save-btn btn btn-primary', - callback: function() { - var data = { - label: $('#domain-label-input').val() - }; - - $('.edit-label-cancel-btn').attr('disabled', 'disabled'); - $('.edit-label-save-btn').attr('disabled', 'disabled'); - $('.edit-label-save-btn').html("Saving..."); - - $('.error-message').hide(); - - $.ajax({ - url: '/api/domains', - type: 'PUT', - data: data, - success: function(xhr) { - dialog.modal('hide'); - reloadDomainInfo(); - }, - error: function(xhr) { - var data = parseJSONResponse(xhr); - console.log(data, data.status, data.data); - if (data.status === "fail") { - for (var key in data.data) { - var errorMsg = data.data[key]; - var errorEl = $('.error-message[data-property="' + key + '"'); - errorEl.html(errorMsg); - errorEl.show(); - } - } - $('.edit-label-cancel-btn').removeAttr('disabled'); - $('.edit-label-save-btn').removeAttr('disabled'); - $('.edit-label-save-btn').html("Save"); - } - }); - return false; - } - } - ], - callback: function(result) { - console.log("result: ", result); - } - }); - }); - - var spinner = createDomainSpinner(); - var errorEl = createDomainLoadingError("Error loading label."); - - html.append(spinner); - html.append(errorEl); - - $('div#label .panel-body').append(html); -} - -function showOrHideAutomaticNetworking() { - var type = getCurrentDomainIDType(); - if (!accessTokenIsSet() || (type !== DOMAIN_ID_TYPE_FULL && type !== DOMAIN_ID_TYPE_UNKNOWN)) { - $("[data-keypath='metaverse.automatic_networking']").hide(); - return false; - } - $("[data-keypath='metaverse.automatic_networking']").show(); - return true; -} - -function setupDomainNetworkingSettings() { - if (!showOrHideAutomaticNetworking()) { - return; - } - - var autoNetworkingSetting = Settings.data.values.metaverse.automatic_networking; - if (autoNetworkingSetting === 'full') { - return; - } - - var includeAddress = autoNetworkingSetting === 'disabled'; - - if (includeAddress) { - var label = "Network Address:Port"; - } else { - var label = "Network Port"; - } - - var lowerName = name.toLowerCase(); - var form = '
    '; - form += ''; - form += ' Edit'; - form += ''; - form += '
    This defines how nodes will connect to your domain. You can read more about automatic networking here.
    '; - form += '
    '; - - form = $(form); - - form.find('#edit-network-address-port').click(function(ev) { - ev.preventDefault(); - - var address = DomainInfo.network_address === null ? '' : DomainInfo.network_address; - var port = DomainInfo.network_port === null ? '' : DomainInfo.network_port; - var modal_body = "
    "; - if (includeAddress) { - modal_body += ""; - modal_body += ""; - modal_body += "
    "; - } - modal_body += ""; - modal_body += ""; - modal_body += "
    "; - modal_body += "
    "; - - var dialog = bootbox.dialog({ - title: 'Edit Network', - message: modal_body, - closeButton: false, - onEscape: true, - buttons: [ - { - label: 'Cancel', - className: 'edit-network-cancel-btn', - callback: function() { - dialog.modal('hide'); - } - }, - { - label: 'Save', - className: 'edit-network-save-btn btn btn-primary', - callback: function() { - var data = { - network_port: $('#network-port-input').val() - }; - if (includeAddress) { - data.network_address = $('#network-address-input').val(); - } - - $('.edit-network-cancel-btn').attr('disabled', 'disabled'); - $('.edit-network-save-btn').attr('disabled', 'disabled'); - $('.edit-network-save-btn').html("Saving..."); - - console.log('data', data); - - $('.error-message').hide(); - - $.ajax({ - url: '/api/domains', - type: 'PUT', - data: data, - success: function(xhr) { - console.log(xhr, parseJSONResponse(xhr)); - dialog.modal('hide'); - reloadDomainInfo(); - }, - error:function(xhr) { - var data = parseJSONResponse(xhr); - console.log(data, data.status, data.data); - if (data.status === "fail") { - for (var key in data.data) { - var errorMsg = data.data[key]; - console.log(key, errorMsg); - var errorEl = $('.error-message[data-property="' + key + '"'); - console.log(errorEl); - errorEl.html(errorMsg); - errorEl.show(); - } - } - $('.edit-network-cancel-btn').removeAttr('disabled'); - $('.edit-network-save-btn').removeAttr('disabled'); - $('.edit-network-save-btn').html("Save"); - } - }); - return false; - } - } - ], - callback: function(result) { - console.log("result: ", result); - } - }); - }); - - var spinner = createDomainSpinner(); - - var errorMessage = '' - if (includeAddress) { - errorMessage = "We were unable to load the network address and port."; - } else { - errorMessage = "We were unable to load the network port." - } - var errorEl = createDomainLoadingError(errorMessage); - - var autoNetworkingEl = $('div[data-keypath="metaverse.automatic_networking"]'); - autoNetworkingEl.after(spinner); - autoNetworkingEl.after(errorEl); - autoNetworkingEl.after(form); -} - - -function setupPlacesTable() { - // create a dummy table using our view helper - var placesTableSetting = { - type: 'table', - name: 'places', - label: 'Places', - html_id: Settings.PLACES_TABLE_ID, - help: "The following places currently point to this domain.
    To point places to this domain, " - + " go to the My Places " - + "page in your High Fidelity Metaverse account.", - read_only: true, - can_add_new_rows: false, - columns: [ + var qs = (function(a) { + if (a == "") return {}; + var b = {}; + for (var i = 0; i < a.length; ++i) { - "name": "name", - "label": "Name" - }, - { - "name": "path", - "label": "Viewpoint or Path" - }, - { - "name": "remove", - "label": "", - "class": "buttons" - } - ] - } - - // get a table for the places - var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values); - - // append the places table in the right place - $('#places_paths .panel-body').prepend(placesTableGroup); - //$('#' + Settings.PLACES_TABLE_ID).append(""); - - var spinner = createDomainSpinner(); - $('#' + Settings.PLACES_TABLE_ID).after($(spinner)); - - var errorEl = createDomainLoadingError("There was an error retreiving your places."); - $("#" + Settings.PLACES_TABLE_ID).after(errorEl); - - // do we have a domain ID? - if (Settings.data.values.metaverse.id.length == 0) { - // we don't have a domain ID - add a button to offer the user a chance to get a temporary one - var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); - $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); - } - if (accessTokenIsSet()) { - appendAddButtonToPlacesTable(); - } -} - -function placeTableRow(name, path, isTemporary, placeID) { - var name_link = "" + (isTemporary ? name + " (temporary)" : name) + ""; - - function placeEditClicked() { - editHighFidelityPlace(placeID, name, path); - } - - function placeDeleteClicked() { - var el = $(this); - var confirmString = Strings.REMOVE_PLACE_TITLE.replace("{{place}}", name); - var dialog = bootbox.dialog({ - message: confirmString, - closeButton: false, - onEscape: true, - buttons: [ - { - label: Strings.REMOVE_PLACE_CANCEL_BUTTON, - className: "delete-place-cancel-btn", - callback: function() { - dialog.modal('hide'); - } - }, - { - label: Strings.REMOVE_PLACE_DELETE_BUTTON, - className: "delete-place-confirm-btn btn btn-danger", - callback: function() { - $('.delete-place-cancel-btn').attr('disabled', 'disabled'); - $('.delete-place-confirm-btn').attr('disabled', 'disabled'); - $('.delete-place-confirm-btn').html(Strings.REMOVE_PLACE_DELETE_BUTTON_PENDING); - sendUpdatePlaceRequest( - placeID, - '', - null, - true, - function() { - reloadDomainInfo(); - dialog.modal('hide'); - }, function() { - $('.delete-place-cancel-btn').removeAttr('disabled'); - $('.delete-place-confirm-btn').removeAttr('disabled'); - $('.delete-place-confirm-btn').html(Strings.REMOVE_PLACE_DELETE_BUTTON); - bootbox.alert(Strings.REMOVE_PLACE_ERROR); - }); - return false; - } - }, - ] - }); - } - - if (isTemporary) { - var editLink = ""; - var deleteColumn = ""; - } else { - var editLink = " Edit"; - var deleteColumn = ""; - } - - var row = $("" + name_link + "" + path + editLink + "" + deleteColumn + ""); - row.find(".place-edit").click(placeEditClicked); - row.find(".place-delete").click(placeDeleteClicked); - - return row; -} - -function placeTableRowForPlaceObject(place) { - var placePathOrIndex = (place.path ? place.path : "/"); - return placeTableRow(place.name, placePathOrIndex, false, place.id); -} - -function reloadDomainInfo() { - $('#' + Settings.PLACES_TABLE_ID + " tbody tr").not('.headers').remove(); - - $('.domain-loading-show').show(); - $('.domain-loading-hide').hide(); - $('.domain-loading-error').hide(); - $('.loading-domain-info-spinner').show(); - $('#' + Settings.PLACES_TABLE_ID).append("Hello"); - - getDomainFromAPI(function(data){ - $('.loading-domain-info-spinner').hide(); - $('.domain-loading-show').hide(); - - // check if we have owner_places (for a real domain) or a name (for a temporary domain) - if (data.status == "success") { - $('.domain-loading-hide').show(); - if (data.domain.owner_places) { - // add a table row for each of these names - _.each(data.domain.owner_places, function(place){ - $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place)); - }); - } else if (data.domain.name) { - // add a table row for this temporary domain name - $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true)); - } - - // Update label - if (showOrHideLabel()) { - var label = data.domain.label; - label = label === null ? '' : label; - $('#network-label').val(label); - } - - // Update automatic networking - if (showOrHideAutomaticNetworking()) { - var autoNetworkingSetting = Settings.data.values.metaverse.automatic_networking; - var address = data.domain.network_address === null ? "" : data.domain.network_address; - var port = data.domain.network_port === null ? "" : data.domain.network_port; - if (autoNetworkingSetting === 'disabled') { - $('#network-address-port input').val(address + ":" + port); - } else if (autoNetworkingSetting === 'ip') { - $('#network-address-port input').val(port); - } - } - - if (accessTokenIsSet()) { - appendAddButtonToPlacesTable(); - } - - } else { - $('.domain-loading-error').show(); - } - }) -} - -function appendDomainIDButtons() { - var domainIDInput = $(Settings.DOMAIN_ID_SELECTOR); - - var createButton = dynamicButton(Settings.CREATE_DOMAIN_ID_BTN_ID, Strings.CREATE_DOMAIN_BUTTON); - createButton.css('margin-top', '10px'); - var chooseButton = dynamicButton(Settings.CHOOSE_DOMAIN_ID_BTN_ID, Strings.CHOOSE_DOMAIN_BUTTON); - chooseButton.css('margin', '10px 0px 0px 10px'); - - domainIDInput.after(chooseButton); - domainIDInput.after(createButton); -} - -function editHighFidelityPlace(placeID, name, path) { - var dialog; - - var modal_body = "
    "; - modal_body += ""; - modal_body += "
    "; - - var modal_buttons = [ - { - label: Strings.EDIT_PLACE_CANCEL_BUTTON, - className: "edit-place-cancel-button", - callback: function() { - dialog.modal('hide'); - } - }, - { - label: Strings.EDIT_PLACE_CONFIRM_BUTTON, - className: 'edit-place-save-button btn btn-primary', - callback: function() { - var placePath = $('#place-path-input').val(); - - if (path == placePath) { - return true; - } - - $('.edit-place-cancel-button').attr('disabled', 'disabled'); - $('.edit-place-save-button').attr('disabled', 'disabled'); - $('.edit-place-save-button').html(Strings.EDIT_PLACE_BUTTON_PENDING); - - sendUpdatePlaceRequest( - placeID, - placePath, - null, - false, - function() { - dialog.modal('hide') - reloadDomainInfo(); - }, - function() { - $('.edit-place-cancel-button').removeAttr('disabled'); - $('.edit-place-save-button').removeAttr('disabled'); - $('.edit-place-save-button').html(Strings.EDIT_PLACE_CONFIRM_BUTTON); - } - ); - - return false; - } - } - ]; - - dialog = bootbox.dialog({ - title: Strings.EDIT_PLACE_TITLE, - closeButton: false, - onEscape: true, - message: modal_body, - buttons: modal_buttons - }) -} - -function appendAddButtonToPlacesTable() { - var addRow = $(" "); - addRow.find(".place-add").click(function(ev) { - ev.preventDefault(); - chooseFromHighFidelityPlaces(Settings.initialValues.metaverse.access_token, null, function(placeName, newDomainID) { - if (newDomainID) { - Settings.data.values.metaverse.id = newDomainID; - var domainIDEl = $("[data-keypath='metaverse.id']"); - domainIDEl.val(newDomainID); - Settings.initialValues.metaverse.id = newDomainID; - badgeSidebarForDifferences(domainIDEl); - } - reloadDomainInfo(); - }); - }); - $('#' + Settings.PLACES_TABLE_ID + " tbody").append(addRow); -} - -function chooseFromHighFidelityDomains(clickedButton) { - // setup the modal to help user pick their domain - if (Settings.initialValues.metaverse.access_token) { - - // add a spinner to the choose button - clickedButton.html("Loading domains..."); - clickedButton.attr('disabled', 'disabled'); - - // get a list of user domains from data-web - $.ajax({ - url: "/api/domains", - dataType: 'json', - jsonp: false, - success: function(data){ - - var modal_buttons = { - cancel: { - label: 'Cancel', - className: 'btn-default' - } - } - - if (data.data.domains.length) { - // setup a select box for the returned domains - modal_body = "

    Choose the High Fidelity domain you want this domain-server to represent.
    This will set your domain ID on the settings page.

    "; - domain_select = $(""); - _.each(data.data.domains, function(domain){ - var domainString = ""; - - if (domain.label) { - domainString += '"' + domain.label+ '" - '; - } - - domainString += domain.id; - - domain_select.append(""); - }) - modal_body += "" + domain_select[0].outerHTML - modal_buttons["success"] = { - label: 'Choose domain', - callback: function() { - domainID = $('#domain-name-select').val() - // set the domain ID on the form - $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); - } - } + var p=a[i].split('=', 2); + if (p.length == 1) { + b[p[0]] = ""; } else { - modal_buttons["success"] = { - label: 'Create new domain', - callback: function() { - window.open(URLs.METAVERSE_URL + "/user/domains", '_blank'); - } - } - modal_body = "

    You do not have any domains in your High Fidelity account." + - "

    Go to your domains page to create a new one. Once your domain is created re-open this dialog to select it.

    " + b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); } - - bootbox.dialog({ - title: "Choose matching domain", - onEscape: true, - message: modal_body, - buttons: modal_buttons - }) - }, - error: function() { - bootbox.alert("Failed to retrieve your domains from the High Fidelity Metaverse"); - }, - complete: function() { - // remove the spinner from the choose button - clickedButton.html("Choose from my domains") - clickedButton.removeAttr('disabled') } - }); - - } else { - bootbox.alert({ - message: "You must have an access token to query your High Fidelity domains.

    " + - "Please follow the instructions on the settings page to add an access token.", - title: "Access token required" - }) - } - } - -function createTemporaryDomain() { - swal({ - title: 'Create temporary place name', - text: "This will create a temporary place name and domain ID" - + " so other users can easily connect to your domain.

    " - + "In order to make your domain reachable, this will also enable full automatic networking.", - showCancelButton: true, - confirmButtonText: 'Create', - closeOnConfirm: false, - html: true - }, function(isConfirm){ - if (isConfirm) { - showSpinnerAlert('Creating temporary place name'); - - // make a get request to get a temporary domain - $.post(URLs.METAVERSE_URL + '/api/v1/domains/temporary', function(data){ - if (data.status == "success") { - var domain = data.data.domain; - - // we should have a new domain ID - set it on the domain ID value - $(Settings.DOMAIN_ID_SELECTOR).val(domain.id).change(); - - // we also need to make sure auto networking is set to full - $('[data-hidden-input="metaverse.automatic_networking"]').val("full").change(); - - swal({ - type: 'success', - title: 'Success!', - text: "We have created a temporary name and domain ID for you.

    " - + "Your temporary place name is " + domain.name + ".

    " - + "Press the button below to save your new settings and restart your domain-server.", - confirmButtonText: 'Save', - html: true - }, function(){ - saveSettings(); - }); - } - }); - } - }); -} - -function reloadSettings(callback) { - $.getJSON('/settings.json', function(data){ - _.extend(data, viewHelpers) - - $('.nav-stacked').html(Settings.sidebarTemplate(data)) - $('#panels').html(Settings.panelsTemplate(data)) - - Settings.data = data; - Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true); + return b; + })(window.location.search.substr(1).split('&')); + Settings.afterReloadActions = function() { // append the domain selection modal appendDomainIDButtons(); @@ -1291,117 +49,10 @@ function reloadSettings(callback) { } } - // setup any bootstrap switches - $('.toggle-checkbox').bootstrapSwitch(); - - $('[data-toggle="tooltip"]').tooltip(); - - // call the callback now that settings are loaded - callback(true); - }).fail(function() { - // call the failure object since settings load faild - callback(false) - }); -} - -function validateInputs() { - // check if any new values are bad - var tables = $('table'); - - var inputsValid = true; - - var tables = $('table'); - - // clear any current invalid rows - $('tr.' + Settings.INVALID_ROW_CLASS).removeClass(Settings.INVALID_ROW_CLASS); - - function markParentRowInvalid(rowChild) { - $(rowChild).closest('tr').addClass(Settings.INVALID_ROW_CLASS); + handleAction(); } - _.each(tables, function(table) { - // validate keys specificially for spaces and equality to an existing key - var newKeys = $(table).find('tr.' + Settings.NEW_ROW_CLASS + ' td.key'); - - var keyWithSpaces = false; - var empty = false; - var duplicateKey = false; - - _.each(newKeys, function(keyCell) { - var keyVal = $(keyCell).children('input').val(); - - if (keyVal.indexOf(' ') !== -1) { - keyWithSpaces = true; - markParentRowInvalid(keyCell); - return; - } - - // make sure the key isn't empty - if (keyVal.length === 0) { - empty = true - - markParentRowInvalid(input); - return; - } - - // make sure we don't have duplicate keys in the table - var otherKeys = $(table).find('td.key').not(keyCell); - _.each(otherKeys, function(otherKeyCell) { - var keyInput = $(otherKeyCell).children('input'); - - if (keyInput.length) { - if ($(keyInput).val() == keyVal) { - duplicateKey = true; - } - } else if ($(otherKeyCell).html() == keyVal) { - duplicateKey = true; - } - - if (duplicateKey) { - markParentRowInvalid(keyCell); - return; - } - }); - - }); - - if (keyWithSpaces) { - showErrorMessage("Error", "Key contains spaces"); - inputsValid = false; - return - } - - if (empty) { - showErrorMessage("Error", "Empty field(s)"); - inputsValid = false; - return - } - - if (duplicateKey) { - showErrorMessage("Error", "Two keys cannot be identical"); - inputsValid = false; - return; - } - }); - - return inputsValid; -} - -var SETTINGS_ERROR_MESSAGE = "There was a problem saving domain settings. Please try again!"; - -function saveSettings() { - - if (validateInputs()) { - // POST the form JSON to the domain-server settings.json endpoint so the settings are saved - var canPost = true; - - // disable any inputs not changed - $("input:not([data-changed])").each(function () { - $(this).prop('disabled', true); - }); - - // grab a JSON representation of the form via form2js - var formJSON = form2js('settings-form', ".", false, cleanupFormValues, true); + Settings.handlePostSettings = function(formJSON) { // check if we've set the basic http password if (formJSON["security"]) { @@ -1424,727 +75,945 @@ function saveSettings() { delete formJSON["security"]["verify_http_password"]; } else { bootbox.alert({ "message": "Passwords must match!", "title": "Password Error" }); - canPost = false; + return false; } } } - console.log("----- SAVING ------"); + console.log("----- handlePostSettings() called ------"); console.log(formJSON); - // re-enable all inputs - $("input").each(function () { - $(this).prop('disabled', false); - }); + if (formJSON["security"]) { + var username = formJSON["security"]["http_username"]; - // remove focus from the button - $(this).blur(); + var password = formJSON["security"]["http_password"]; - if (canPost) { - if (formJSON["security"]) { - var username = formJSON["security"]["http_username"]; + if ((password == sha256_digest("")) && (username == undefined || (username && username.length != 0))) { + swal({ + title: "Are you sure?", + text: "You have entered a blank password with a non-blank username. Are you sure you want to require a blank password?", + type: "warning", + showCancelButton: true, + confirmButtonColor: "#5cb85c", + confirmButtonText: "Yes!", + closeOnConfirm: true + }, + function () { + formJSON["security"]["http_password"] = ""; - var password = formJSON["security"]["http_password"]; + postSettings(formJSON); + }); - if ((password == sha256_digest("")) && (username == undefined || (username && username.length != 0))) { - swal({ - title: "Are you sure?", - text: "You have entered a blank password with a non-blank username. Are you sure you want to require a blank password?", - type: "warning", - showCancelButton: true, - confirmButtonColor: "#5cb85c", - confirmButtonText: "Yes!", - closeOnConfirm: true - }, - function () { - formJSON["security"]["http_password"] = ""; - postSettings(formJSON); - }); - return; - } + return; } - // POST the form JSON to the domain-server settings.json endpoint so the settings are saved - postSettings(formJSON); } - } -} -$('body').on('click', '.save-button', function(e){ - saveSettings(); - return false; -}); + postSettings(formJSON); + }; -function makeTable(setting, keypath, setting_value) { - var isArray = !_.has(setting, 'key'); - var categoryKey = setting.categorize_by_key; - var isCategorized = !!categoryKey && isArray; - - if (!isArray && setting.can_order) { - setting.can_order = false; - } - - var html = ""; - - if (setting.help) { - html += "" + setting.help + "" - } - - var nonDeletableRowKey = setting["non-deletable-row-key"]; - var nonDeletableRowValues = setting["non-deletable-row-values"]; - - html += ""; - - if (setting.caption) { - html += "" - } - - // Column groups - if (setting.groups) { - html += "" - _.each(setting.groups, function (group) { - html += "" - }) - if (!setting.read_only) { - if (setting.can_order) { - html += ""; - } - html += "" - } - html += "" - } - - // Column names - html += "" - - if (setting.numbered === true) { - html += "" // Row number - } - - if (setting.key) { - html += "" // Key - } - - var numVisibleColumns = 0; - _.each(setting.columns, function(col) { - if (!col.hidden) numVisibleColumns++; - html += "" // Data + $('#' + Settings.FORM_ID).on('click', '#' + Settings.CREATE_DOMAIN_ID_BTN_ID, function(){ + $(this).blur(); + showDomainCreationAlert(false); }) - if (!setting.read_only) { - if (setting.can_order) { - numVisibleColumns++; - html += ""; - } - numVisibleColumns++; - html += ""; + $('#' + Settings.FORM_ID).on('click', '#' + Settings.CHOOSE_DOMAIN_ID_BTN_ID, function(){ + $(this).blur(); + chooseFromHighFidelityDomains($(this)) + }); + + $('#' + Settings.FORM_ID).on('click', '#' + Settings.GET_TEMPORARY_NAME_BTN_ID, function(){ + $(this).blur(); + createTemporaryDomain(); + }); + + $('#' + Settings.FORM_ID).on('click', '#' + Settings.DISCONNECT_ACCOUNT_BTN_ID, function(e){ + $(this).blur(); + disonnectHighFidelityAccount(); + e.preventDefault(); + }); + + $('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){ + $(this).blur(); + prepareAccessTokenPrompt(function(accessToken) { + // we have an access token - set the access token input with this and save settings + $(Settings.ACCESS_TOKEN_SELECTOR).val(accessToken).change(); + saveSettings(); + }); + }); + + function accessTokenIsSet() { + return Settings.data.values.metaverse.access_token.length > 0; } - // populate rows in the table from existing values - var row_num = 1; - - if (keypath.length > 0 && _.size(setting_value) > 0) { - var rowIsObject = setting.columns.length > 1; - - _.each(setting_value, function(row, rowIndexOrName) { - var categoryPair = {}; - var categoryValue = ""; - if (isCategorized) { - categoryValue = rowIsObject ? row[categoryKey] : row; - categoryPair[categoryKey] = categoryValue; - if (_.findIndex(setting_value, categoryPair) === rowIndexOrName) { - html += makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, setting.can_add_new_categories, ""); + function getShareName(callback) { + getDomainFromAPI(function(data){ + // check if we have owner_places (for a real domain) or a name (for a temporary domain) + if (data && data.status == "success") { + var shareName; + if (data.domain.default_place_name) { + shareName = data.domain.default_place_name; + } else if (data.domain.name) { + shareName = data.domain.name; + } else if (data.domain.network_address) { + shareName = data.domain.network_address; + if (data.domain.network_port !== 40102) { + shareName += ':' + data.domain.network_port; + } } + + callback(true, shareName); + } else { + callback(false); + } + }) + } + + function handleAction() { + // check if we were passed an action to handle + var action = qs["action"]; + + if (action == "share") { + // figure out if we already have a stored domain ID + if (Settings.data.values.metaverse.id.length > 0) { + // we need to ask the API what a shareable name for this domain is + getShareName(function(success, shareName){ + if (success) { + var shareLink = "hifi://" + shareName; + + console.log(shareLink); + + // show a dialog with a copiable share URL + swal({ + title: "Share", + type: "input", + inputPlaceholder: shareLink, + inputValue: shareLink, + text: "Copy this URL to invite friends to your domain.", + closeOnConfirm: true + }); + + $('.sweet-alert input').select(); + + } else { + // show an error alert + swal({ + title: '', + type: 'error', + text: "There was a problem retreiving domain information from High Fidelity API.", + confirmButtonText: 'Try again', + showCancelButton: true, + closeOnConfirm: false + }, function(isConfirm){ + if (isConfirm) { + // they want to try getting domain share info again + showSpinnerAlert("Requesting domain information...") + handleAction(); + } else { + swal.close(); + } + }); + } + }); + } else { + // no domain ID present, just show the share dialog + createTemporaryDomain(); + } + } + } + + function setupHFAccountButton() { + + var hasAccessToken = accessTokenIsSet(); + var el; + + if (hasAccessToken) { + el = "

    "; + el += ""; + el += ""; + el += "

    "; + el = $(el); + } else { + // setup an object for the settings we want our button to have + var buttonSetting = { + type: 'button', + name: 'connected_account', + label: 'Connected Account', + } + buttonSetting.help = ""; + buttonSetting.classes = "btn-primary"; + buttonSetting.button_label = "Connect High Fidelity Account"; + buttonSetting.html_id = Settings.CONNECT_ACCOUNT_BTN_ID; + + buttonSetting.href = URLs.METAVERSE_URL + "/user/tokens/new?for_domain_server=true"; + + // since we do not have an access token we change hide domain ID and auto networking settings + // without an access token niether of them can do anything + $("[data-keypath='metaverse.id']").hide(); + + // use the existing getFormGroup helper to ask for a button + el = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values); + } + + // add the button group to the top of the metaverse panel + $('#metaverse .panel-body').prepend(el); + } + + function disonnectHighFidelityAccount() { + // the user clicked on the disconnect account btn - give them a sweet alert to make sure this is what they want to do + swal({ + title: "Are you sure?", + text: "This will remove your domain-server OAuth access token." + + "

    This could cause your domain to appear offline and no longer be reachable via any place names.", + type: "warning", + html: true, + showCancelButton: true + }, function(){ + // we need to post to settings to clear the access-token + $(Settings.ACCESS_TOKEN_SELECTOR).val('').change(); + // reset the domain id to get a new temporary name + $(Settings.DOMAIN_ID_SELECTOR).val('').change(); + saveSettings(); + }); + } + + function showDomainCreationAlert(justConnected) { + swal({ + title: 'Create new domain ID', + type: 'input', + text: 'Enter a label this machine.

    This will help you identify which domain ID belongs to which machine.

    ', + showCancelButton: true, + confirmButtonText: "Create", + closeOnConfirm: false, + html: true + }, function(inputValue){ + if (inputValue === false) { + swal.close(); + + // user cancelled domain ID creation - if we're supposed to save after cancel then save here + if (justConnected) { + saveSettings(); + } + } else { + // we're going to change the alert to a new one with a spinner while we create this domain + showSpinnerAlert('Creating domain ID'); + createNewDomainID(inputValue, justConnected); + } + }); + } + + function createNewDomainID(label, justConnected) { + // get the JSON object ready that we'll use to create a new domain + var domainJSON = { + "label": label + } + + $.post("/api/domains", domainJSON, function(data){ + // we successfully created a domain ID, set it on that field + var domainID = data.domain.id; + console.log("Setting domain id to ", data, domainID); + $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); + + if (justConnected) { + var successText = Strings.CREATE_DOMAIN_SUCCESS_JUST_CONNECTED + } else { + var successText = Strings.CREATE_DOMAIN_SUCCESS; } - html += ""; + successText += "

    Click the button below to save your new settings and restart your domain-server."; - if (setting.numbered === true) { - html += "" + // show a sweet alert to say we are all finished up and that we need to save + swal({ + title: 'Success!', + type: 'success', + text: successText, + html: true, + confirmButtonText: 'Save' + }, function(){ + saveSettings(); + }); + }, 'json').fail(function(){ + + var errorText = "There was a problem creating your new domain ID. Do you want to try again or"; + + if (justConnected) { + errorText += " just save your new access token?

    You can always create a new domain ID later."; + } else { + errorText += " cancel?" } - if (setting.key) { - html += "" - } - - var isNonDeletableRow = !setting.can_add_new_rows; - - _.each(setting.columns, function(col) { - - var colValue, colName; - if (isArray) { - colValue = rowIsObject ? row[col.name] : row; - colName = keypath + "[" + rowIndexOrName + "]" + (rowIsObject ? "." + col.name : ""); + // we failed to create the new domain ID, show a sweet-alert that lets them try again or cancel + swal({ + title: '', + type: 'error', + text: errorText, + html: true, + confirmButtonText: 'Try again', + showCancelButton: true, + closeOnConfirm: false + }, function(isConfirm){ + if (isConfirm) { + // they want to try creating a domain ID again + showDomainCreationAlert(justConnected); } else { - colValue = row[col.name]; - colName = keypath + "." + rowIndexOrName + "." + col.name; + // they want to cancel + if (justConnected) { + // since they just connected we need to save the access token here + saveSettings(); + } + } + }); + }); + } + + function createDomainSpinner() { + var spinner = ''; + return spinner; + } + + function createDomainLoadingError(message) { + var errorEl = $(""); + errorEl.append(message + " "); + + var retryLink = $("Please click here to try again."); + retryLink.click(function(ev) { + ev.preventDefault(); + reloadDomainInfo(); + }); + errorEl.append(retryLink); + + return errorEl; + } + + function showOrHideLabel() { + var type = getCurrentDomainIDType(); + var shouldShow = accessTokenIsSet() && (type === DOMAIN_ID_TYPE_FULL || type === DOMAIN_ID_TYPE_UNKNOWN); + $(".panel#label").toggle(shouldShow); + $("li a[href='#label']").parent().toggle(shouldShow); + return shouldShow; + } + + function setupDomainLabelSetting() { + showOrHideLabel(); + + var html = "
    " + html += " Edit"; + html += ""; + html += "
    "; + + html = $(html); + + html.find('a').click(function(ev) { + ev.preventDefault(); + + var label = DomainInfo.label === null ? "" : DomainInfo.label; + var modal_body = "
    "; + modal_body += ""; + modal_body += ""; + modal_body += "
    "; + modal_body += "
    "; + + var dialog = bootbox.dialog({ + title: 'Edit Label', + message: modal_body, + closeButton: false, + onEscape: true, + buttons: [ + { + label: 'Cancel', + className: 'edit-label-cancel-btn', + callback: function() { + dialog.modal('hide'); + } + }, + { + label: 'Save', + className: 'edit-label-save-btn btn btn-primary', + callback: function() { + var data = { + label: $('#domain-label-input').val() + }; + + $('.edit-label-cancel-btn').attr('disabled', 'disabled'); + $('.edit-label-save-btn').attr('disabled', 'disabled'); + $('.edit-label-save-btn').html("Saving..."); + + $('.error-message').hide(); + + $.ajax({ + url: '/api/domains', + type: 'PUT', + data: data, + success: function(xhr) { + dialog.modal('hide'); + reloadDomainInfo(); + }, + error: function(xhr) { + var data = parseJSONResponse(xhr); + console.log(data, data.status, data.data); + if (data.status === "fail") { + for (var key in data.data) { + var errorMsg = data.data[key]; + var errorEl = $('.error-message[data-property="' + key + '"'); + errorEl.html(errorMsg); + errorEl.show(); + } + } + $('.edit-label-cancel-btn').removeAttr('disabled'); + $('.edit-label-save-btn').removeAttr('disabled'); + $('.edit-label-save-btn').html("Save"); + } + }); + return false; + } + } + ], + callback: function(result) { + console.log("result: ", result); + } + }); + }); + + var spinner = createDomainSpinner(); + var errorEl = createDomainLoadingError("Error loading label."); + + html.append(spinner); + html.append(errorEl); + + $('div#label .panel-body').append(html); + } + + function showOrHideAutomaticNetworking() { + var type = getCurrentDomainIDType(); + if (!accessTokenIsSet() || (type !== DOMAIN_ID_TYPE_FULL && type !== DOMAIN_ID_TYPE_UNKNOWN)) { + $("[data-keypath='metaverse.automatic_networking']").hide(); + return false; + } + $("[data-keypath='metaverse.automatic_networking']").show(); + return true; + } + + function setupDomainNetworkingSettings() { + if (!showOrHideAutomaticNetworking()) { + return; + } + + var autoNetworkingSetting = Settings.data.values.metaverse.automatic_networking; + if (autoNetworkingSetting === 'full') { + return; + } + + var includeAddress = autoNetworkingSetting === 'disabled'; + + if (includeAddress) { + var label = "Network Address:Port"; + } else { + var label = "Network Port"; + } + + var lowerName = name.toLowerCase(); + var form = '
    '; + form += ''; + form += ' Edit'; + form += ''; + form += '
    This defines how nodes will connect to your domain. You can read more about automatic networking here.
    '; + form += '
    '; + + form = $(form); + + form.find('#edit-network-address-port').click(function(ev) { + ev.preventDefault(); + + var address = DomainInfo.network_address === null ? '' : DomainInfo.network_address; + var port = DomainInfo.network_port === null ? '' : DomainInfo.network_port; + var modal_body = "
    "; + if (includeAddress) { + modal_body += ""; + modal_body += ""; + modal_body += "
    "; + } + modal_body += ""; + modal_body += ""; + modal_body += "
    "; + modal_body += "
    "; + + var dialog = bootbox.dialog({ + title: 'Edit Network', + message: modal_body, + closeButton: false, + onEscape: true, + buttons: [ + { + label: 'Cancel', + className: 'edit-network-cancel-btn', + callback: function() { + dialog.modal('hide'); + } + }, + { + label: 'Save', + className: 'edit-network-save-btn btn btn-primary', + callback: function() { + var data = { + network_port: $('#network-port-input').val() + }; + if (includeAddress) { + data.network_address = $('#network-address-input').val(); + } + + $('.edit-network-cancel-btn').attr('disabled', 'disabled'); + $('.edit-network-save-btn').attr('disabled', 'disabled'); + $('.edit-network-save-btn').html("Saving..."); + + console.log('data', data); + + $('.error-message').hide(); + + $.ajax({ + url: '/api/domains', + type: 'PUT', + data: data, + success: function(xhr) { + console.log(xhr, parseJSONResponse(xhr)); + dialog.modal('hide'); + reloadDomainInfo(); + }, + error:function(xhr) { + var data = parseJSONResponse(xhr); + console.log(data, data.status, data.data); + if (data.status === "fail") { + for (var key in data.data) { + var errorMsg = data.data[key]; + console.log(key, errorMsg); + var errorEl = $('.error-message[data-property="' + key + '"'); + console.log(errorEl); + errorEl.html(errorMsg); + errorEl.show(); + } + } + $('.edit-network-cancel-btn').removeAttr('disabled'); + $('.edit-network-save-btn').removeAttr('disabled'); + $('.edit-network-save-btn').html("Save"); + } + }); + return false; + } + } + ], + callback: function(result) { + console.log("result: ", result); + } + }); + }); + + var spinner = createDomainSpinner(); + + var errorMessage = '' + if (includeAddress) { + errorMessage = "We were unable to load the network address and port."; + } else { + errorMessage = "We were unable to load the network port." + } + var errorEl = createDomainLoadingError(errorMessage); + + var autoNetworkingEl = $('div[data-keypath="metaverse.automatic_networking"]'); + autoNetworkingEl.after(spinner); + autoNetworkingEl.after(errorEl); + autoNetworkingEl.after(form); + } + + + function setupPlacesTable() { + // create a dummy table using our view helper + var placesTableSetting = { + type: 'table', + name: 'places', + label: 'Places', + html_id: Settings.PLACES_TABLE_ID, + help: "The following places currently point to this domain.
    To point places to this domain, " + + " go to the My Places " + + "page in your High Fidelity Metaverse account.", + read_only: true, + can_add_new_rows: false, + columns: [ + { + "name": "name", + "label": "Name" + }, + { + "name": "path", + "label": "Viewpoint or Path" + }, + { + "name": "remove", + "label": "", + "class": "buttons" + } + ] + } + + // get a table for the places + var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values); + + // append the places table in the right place + $('#places_paths .panel-body').prepend(placesTableGroup); + //$('#' + Settings.PLACES_TABLE_ID).append(""); + + var spinner = createDomainSpinner(); + $('#' + Settings.PLACES_TABLE_ID).after($(spinner)); + + var errorEl = createDomainLoadingError("There was an error retreiving your places."); + $("#" + Settings.PLACES_TABLE_ID).after(errorEl); + + // do we have a domain ID? + if (Settings.data.values.metaverse.id.length == 0) { + // we don't have a domain ID - add a button to offer the user a chance to get a temporary one + var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); + $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); + } + if (accessTokenIsSet()) { + appendAddButtonToPlacesTable(); + } + } + + function placeTableRow(name, path, isTemporary, placeID) { + var name_link = "" + (isTemporary ? name + " (temporary)" : name) + ""; + + function placeEditClicked() { + editHighFidelityPlace(placeID, name, path); + } + + function placeDeleteClicked() { + var el = $(this); + var confirmString = Strings.REMOVE_PLACE_TITLE.replace("{{place}}", name); + var dialog = bootbox.dialog({ + message: confirmString, + closeButton: false, + onEscape: true, + buttons: [ + { + label: Strings.REMOVE_PLACE_CANCEL_BUTTON, + className: "delete-place-cancel-btn", + callback: function() { + dialog.modal('hide'); + } + }, + { + label: Strings.REMOVE_PLACE_DELETE_BUTTON, + className: "delete-place-confirm-btn btn btn-danger", + callback: function() { + $('.delete-place-cancel-btn').attr('disabled', 'disabled'); + $('.delete-place-confirm-btn').attr('disabled', 'disabled'); + $('.delete-place-confirm-btn').html(Strings.REMOVE_PLACE_DELETE_BUTTON_PENDING); + sendUpdatePlaceRequest( + placeID, + '', + null, + true, + function() { + reloadDomainInfo(); + dialog.modal('hide'); + }, function() { + $('.delete-place-cancel-btn').removeAttr('disabled'); + $('.delete-place-confirm-btn').removeAttr('disabled'); + $('.delete-place-confirm-btn').html(Strings.REMOVE_PLACE_DELETE_BUTTON); + bootbox.alert(Strings.REMOVE_PLACE_ERROR); + }); + return false; + } + }, + ] + }); + } + + if (isTemporary) { + var editLink = ""; + var deleteColumn = ""; + } else { + var editLink = " Edit"; + var deleteColumn = ""; + } + + var row = $("" + deleteColumn + ""); + row.find(".place-edit").click(placeEditClicked); + row.find(".place-delete").click(placeDeleteClicked); + + return row; + } + + function placeTableRowForPlaceObject(place) { + var placePathOrIndex = (place.path ? place.path : "/"); + return placeTableRow(place.name, placePathOrIndex, false, place.id); + } + + function reloadDomainInfo() { + $('#' + Settings.PLACES_TABLE_ID + " tbody tr").not('.headers').remove(); + + $('.domain-loading-show').show(); + $('.domain-loading-hide').hide(); + $('.domain-loading-error').hide(); + $('.loading-domain-info-spinner').show(); + $('#' + Settings.PLACES_TABLE_ID).append("Hello"); + + getDomainFromAPI(function(data){ + $('.loading-domain-info-spinner').hide(); + $('.domain-loading-show').hide(); + + // check if we have owner_places (for a real domain) or a name (for a temporary domain) + if (data.status == "success") { + $('.domain-loading-hide').show(); + if (data.domain.owner_places) { + // add a table row for each of these names + _.each(data.domain.owner_places, function(place){ + $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place)); + }); + } else if (data.domain.name) { + // add a table row for this temporary domain name + $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true)); } - isNonDeletableRow = isNonDeletableRow - || (nonDeletableRowKey === col.name && nonDeletableRowValues.indexOf(colValue) !== -1); - - if (isArray && col.type === "checkbox" && col.editable) { - html += - ""; - } else if (isArray && col.type === "time" && col.editable) { - html += - ""; - } else { - // Use a hidden input so that the values are posted. - html += - ""; + // Update label + if (showOrHideLabel()) { + var label = data.domain.label; + label = label === null ? '' : label; + $('#network-label').val(label); } + // Update automatic networking + if (showOrHideAutomaticNetworking()) { + var autoNetworkingSetting = Settings.data.values.metaverse.automatic_networking; + var address = data.domain.network_address === null ? "" : data.domain.network_address; + var port = data.domain.network_port === null ? "" : data.domain.network_port; + if (autoNetworkingSetting === 'disabled') { + $('#network-address-port input').val(address + ":" + port); + } else if (autoNetworkingSetting === 'ip') { + $('#network-address-port input').val(port); + } + } + + if (accessTokenIsSet()) { + appendAddButtonToPlacesTable(); + } + + } else { + $('.domain-loading-error').show(); + } + }) + } + + function appendDomainIDButtons() { + var domainIDInput = $(Settings.DOMAIN_ID_SELECTOR); + + var createButton = dynamicButton(Settings.CREATE_DOMAIN_ID_BTN_ID, Strings.CREATE_DOMAIN_BUTTON); + createButton.css('margin-top', '10px'); + var chooseButton = dynamicButton(Settings.CHOOSE_DOMAIN_ID_BTN_ID, Strings.CHOOSE_DOMAIN_BUTTON); + chooseButton.css('margin', '10px 0px 0px 10px'); + + domainIDInput.after(chooseButton); + domainIDInput.after(createButton); + } + + function editHighFidelityPlace(placeID, name, path) { + var dialog; + + var modal_body = "
    "; + modal_body += ""; + modal_body += "
    "; + + var modal_buttons = [ + { + label: Strings.EDIT_PLACE_CANCEL_BUTTON, + className: "edit-place-cancel-button", + callback: function() { + dialog.modal('hide'); + } + }, + { + label: Strings.EDIT_PLACE_CONFIRM_BUTTON, + className: 'edit-place-save-button btn btn-primary', + callback: function() { + var placePath = $('#place-path-input').val(); + + if (path == placePath) { + return true; + } + + $('.edit-place-cancel-button').attr('disabled', 'disabled'); + $('.edit-place-save-button').attr('disabled', 'disabled'); + $('.edit-place-save-button').html(Strings.EDIT_PLACE_BUTTON_PENDING); + + sendUpdatePlaceRequest( + placeID, + placePath, + null, + false, + function() { + dialog.modal('hide') + reloadDomainInfo(); + }, + function() { + $('.edit-place-cancel-button').removeAttr('disabled'); + $('.edit-place-save-button').removeAttr('disabled'); + $('.edit-place-save-button').html(Strings.EDIT_PLACE_CONFIRM_BUTTON); + } + ); + + return false; + } + } + ]; + + dialog = bootbox.dialog({ + title: Strings.EDIT_PLACE_TITLE, + closeButton: false, + onEscape: true, + message: modal_body, + buttons: modal_buttons + }) + } + + function appendAddButtonToPlacesTable() { + var addRow = $(""); + addRow.find(".place-add").click(function(ev) { + ev.preventDefault(); + chooseFromHighFidelityPlaces(Settings.initialValues.metaverse.access_token, null, function(placeName, newDomainID) { + if (newDomainID) { + Settings.data.values.metaverse.id = newDomainID; + var domainIDEl = $("[data-keypath='metaverse.id']"); + domainIDEl.val(newDomainID); + Settings.initialValues.metaverse.id = newDomainID; + badgeForDifferences(domainIDEl); + } + reloadDomainInfo(); + }); + }); + $('#' + Settings.PLACES_TABLE_ID + " tbody").append(addRow); + } + + function chooseFromHighFidelityDomains(clickedButton) { + // setup the modal to help user pick their domain + if (Settings.initialValues.metaverse.access_token) { + + // add a spinner to the choose button + clickedButton.html("Loading domains..."); + clickedButton.attr('disabled', 'disabled'); + + // get a list of user domains from data-web + $.ajax({ + url: "/api/domains", + dataType: 'json', + jsonp: false, + success: function(data){ + + var modal_buttons = { + cancel: { + label: 'Cancel', + className: 'btn-default' + } + } + + if (data.data.domains.length) { + // setup a select box for the returned domains + modal_body = "

    Choose the High Fidelity domain you want this domain-server to represent.
    This will set your domain ID on the settings page.

    "; + domain_select = $(""); + _.each(data.data.domains, function(domain){ + var domainString = ""; + + if (domain.label) { + domainString += '"' + domain.label+ '" - '; + } + + domainString += domain.id; + + domain_select.append(""); + }) + modal_body += "" + domain_select[0].outerHTML + modal_buttons["success"] = { + label: 'Choose domain', + callback: function() { + domainID = $('#domain-name-select').val() + // set the domain ID on the form + $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); + } + } + } else { + modal_buttons["success"] = { + label: 'Create new domain', + callback: function() { + window.open(URLs.METAVERSE_URL + "/user/domains", '_blank'); + } + } + modal_body = "

    You do not have any domains in your High Fidelity account." + + "

    Go to your domains page to create a new one. Once your domain is created re-open this dialog to select it.

    " + } + + bootbox.dialog({ + title: "Choose matching domain", + onEscape: true, + message: modal_body, + buttons: modal_buttons + }) + }, + error: function() { + bootbox.alert("Failed to retrieve your domains from the High Fidelity Metaverse"); + }, + complete: function() { + // remove the spinner from the choose button + clickedButton.html("Choose from my domains") + clickedButton.removeAttr('disabled') + } }); - if (!setting.read_only) { - if (setting.can_order) { - html += "" - } - if (isNonDeletableRow) { - html += ""; - } else { - html += ""; - } - } - - html += "" - - if (isCategorized && setting.can_add_new_rows && _.findLastIndex(setting_value, categoryPair) === rowIndexOrName) { - html += makeTableInputs(setting, categoryPair, categoryValue); - } - - row_num++ - }); - } - - // populate inputs in the table for new values - if (!setting.read_only) { - if (setting.can_add_new_categories) { - html += makeTableCategoryInput(setting, numVisibleColumns); - } - - if (setting.can_add_new_rows || setting.can_add_new_categories) { - html += makeTableHiddenInputs(setting, {}, ""); - } - } - html += "
    " + setting.caption + "
    " + group.label + "
    #" + setting.key.label + "" + col.label + "
    " + row_num + "" + rowIndexOrName + "
    " + name_link + "" + path + editLink + "
    " + - "" + - "" + - "" + - "" + - colValue + - "" + - "
    " - + "
    " - - return html; -} - -function makeTableCategoryHeader(categoryKey, categoryValue, numVisibleColumns, canRemove, message) { - var html = - "" + - "" + - "" + - "" + categoryValue + "" + - "" + - ((canRemove) ? ( - "" + - "" + - "" - ) : ( - "" - )) + - ""; - return html; -} - -function makeTableHiddenInputs(setting, initialValues, categoryValue) { - var html = ""; - - if (setting.numbered === true) { - html += ""; - } - - if (setting.key) { - html += "\ - \ - " - } - - _.each(setting.columns, function(col) { - var defaultValue = _.has(initialValues, col.name) ? initialValues[col.name] : col.default; - if (col.type === "checkbox") { - html += - "" + - "" + - ""; - } else if (col.type === "select") { - html += "" - html += ""; - html += ""; - } else { - html += - "" + - "" + - ""; - } - }) - - if (setting.can_order) { - html += "" - } - html += "" - html += "" - - return html -} - -function makeTableCategoryInput(setting, numVisibleColumns) { - var canAddRows = setting.can_add_new_rows; - var categoryKey = setting.categorize_by_key; - var placeholder = setting.new_category_placeholder || ""; - var message = setting.new_category_message || ""; - var html = - "" + - "" + - "" + - "" + - "" + - "" + - "" + - ""; - return html; -} - -function getDescriptionForKey(key) { - for (var i in Settings.data.descriptions) { - if (Settings.data.descriptions[i].name === key) { - return Settings.data.descriptions[i]; - } - } -} - -var SAVE_BUTTON_LABEL_SAVE = "Save"; -var SAVE_BUTTON_LABEL_RESTART = "Save and restart"; -var reasonsForRestart = []; -var numChangesBySection = {}; - -function badgeSidebarForDifferences(changedElement) { - // figure out which group this input is in - var panelParentID = changedElement.closest('.panel').attr('id'); - - // if the panel contains non-grouped settings, the initial value is Settings.initialValues - var isGrouped = $('#' + panelParentID).hasClass('grouped'); - - if (isGrouped) { - var initialPanelJSON = Settings.initialValues[panelParentID] - ? Settings.initialValues[panelParentID] - : {}; - - // get a JSON representation of that section - var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID]; - } else { - var initialPanelJSON = Settings.initialValues; - - // get a JSON representation of that section - var panelJSON = form2js(panelParentID, ".", false, cleanupFormValues, true); - } - - var badgeValue = 0 - var description = getDescriptionForKey(panelParentID); - - // badge for any settings we have that are not the same or are not present in initialValues - for (var setting in panelJSON) { - if ((!_.has(initialPanelJSON, setting) && panelJSON[setting] !== "") || - (!_.isEqual(panelJSON[setting], initialPanelJSON[setting]) - && (panelJSON[setting] !== "" || _.has(initialPanelJSON, setting)))) { - badgeValue += 1; - - // add a reason to restart - if (description && description.restart != false) { - reasonsForRestart.push(setting); - } - } else { - // remove a reason to restart - if (description && description.restart != false) { - reasonsForRestart = $.grep(reasonsForRestart, function(v) { return v != setting; }); - } - } - } - - // update the list-group-item badge to have the new value - if (badgeValue == 0) { - badgeValue = "" - } - - numChangesBySection[panelParentID] = badgeValue; - - var hasChanges = badgeValue > 0; - - if (!hasChanges) { - for (var key in numChangesBySection) { - if (numChangesBySection[key] > 0) { - hasChanges = true; - break; - } - } - } - - $(".save-button").prop("disabled", !hasChanges); - $(".save-button").html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE); - $("a[href='#" + panelParentID + "'] .badge").html(badgeValue); -} - -function addTableRow(row) { - var table = row.parents('table'); - var isArray = table.data('setting-type') === 'array'; - var keepField = row.data("keep-field"); - - var columns = row.parent().children('.' + Settings.DATA_ROW_CLASS); - - var input_clone = row.clone(); - - if (!isArray) { - // show the key input - var keyInput = row.children(".key").children("input"); - } - - // Change input row to data row - var table = row.parents("table"); - var setting_name = table.attr("name"); - row.addClass(Settings.DATA_ROW_CLASS + " " + Settings.NEW_ROW_CLASS); - - // if this is an array, add the row index (which is the index of the last row + 1) - // as a data attribute to the row - var row_index = 0; - if (isArray) { - var previous_row = row.siblings('.' + Settings.DATA_ROW_CLASS + ':last'); - - if (previous_row.length > 0) { - row_index = parseInt(previous_row.attr(Settings.DATA_ROW_INDEX), 10) + 1; - } else { - row_index = 0; - } - - row.attr(Settings.DATA_ROW_INDEX, row_index); - } - - var focusChanged = false; - - _.each(row.children(), function(element) { - if ($(element).hasClass("numbered")) { - // Index row - var numbers = columns.children(".numbered") - if (numbers.length > 0) { - $(element).html(parseInt(numbers.last().text()) + 1) } else { - $(element).html(1) + bootbox.alert({ + message: "You must have an access token to query your High Fidelity domains.

    " + + "Please follow the instructions on the settings page to add an access token.", + title: "Access token required" + }) } - } else if ($(element).hasClass(Settings.REORDER_BUTTONS_CLASS)) { - $(element).html("") - } else if ($(element).hasClass(Settings.ADD_DEL_BUTTONS_CLASS)) { - // Change buttons - var anchor = $(element).children("a") - anchor.removeClass(Settings.ADD_ROW_SPAN_CLASSES) - anchor.addClass(Settings.DEL_ROW_SPAN_CLASSES) - } else if ($(element).hasClass("key")) { - var input = $(element).children("input") - input.show(); - } else if ($(element).hasClass(Settings.DATA_COL_CLASS)) { - // show inputs - var input = $(element).find("input"); - input.show(); + } - var isCheckbox = input.hasClass("table-checkbox"); - var isDropdown = input.hasClass("table-dropdown"); + function createTemporaryDomain() { + swal({ + title: 'Create temporary place name', + text: "This will create a temporary place name and domain ID" + + " so other users can easily connect to your domain.

    " + + "In order to make your domain reachable, this will also enable full automatic networking.", + showCancelButton: true, + confirmButtonText: 'Create', + closeOnConfirm: false, + html: true + }, function(isConfirm){ + if (isConfirm) { + showSpinnerAlert('Creating temporary place name'); - if (isArray) { - var key = $(element).attr('name'); + // make a get request to get a temporary domain + $.post(URLs.METAVERSE_URL + '/api/v1/domains/temporary', function(data){ + if (data.status == "success") { + var domain = data.data.domain; - // are there multiple columns or just one? - // with multiple we have an array of Objects, with one we have an array of whatever the value type is - var num_columns = row.children('.' + Settings.DATA_COL_CLASS).length - var newName = setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : ""); + // we should have a new domain ID - set it on the domain ID value + $(Settings.DOMAIN_ID_SELECTOR).val(domain.id).change(); - input.attr("name", newName); + // we also need to make sure auto networking is set to full + $('[data-hidden-input="metaverse.automatic_networking"]').val("full").change(); - if (isDropdown) { - // default values for hidden inputs inside child selects gets cleared so we need to remind it - var selectElement = $(element).children("select"); - selectElement.attr("data-hidden-input", newName); - $(element).children("input").val(selectElement.val()); - } - } else { - // because the name of the setting in question requires the key - // setup a hook to change the HTML name of the element whenever the key changes - var colName = $(element).attr("name"); - keyInput.on('change', function(){ - input.attr("name", setting_name + "." + $(this).val() + "." + colName); + swal({ + type: 'success', + title: 'Success!', + text: "We have created a temporary name and domain ID for you.

    " + + "Your temporary place name is " + domain.name + ".

    " + + "Press the button below to save your new settings and restart your domain-server.", + confirmButtonText: 'Save', + html: true + }, function(){ + saveSettings(); + }); + } }); } - - if (!focusChanged) { - input.focus(); - focusChanged = true; - } - - // if we are adding a dropdown, we should go ahead and make its select - // element is visible - if (isDropdown) { - $(element).children("select").attr("style", ""); - } - - if (isCheckbox) { - $(input).find("input").attr("data-changed", "true"); - } else { - input.attr("data-changed", "true"); - } - } else { - console.log("Unknown table element"); - } - }); - - input_clone.children('td').each(function () { - if ($(this).attr("name") !== keepField) { - $(this).find("input").val($(this).children('input').attr('data-default')); - } - }); - - if (isArray) { - updateDataChangedForSiblingRows(row, true) - - // the addition of any table row should remove the empty-array-row - row.siblings('.empty-array-row').remove() - } - - badgeSidebarForDifferences($(table)) - - row.after(input_clone) -} - -function deleteTableRow($row) { - var $table = $row.closest('table'); - var categoryName = $row.data("category"); - var isArray = $table.data('setting-type') === 'array'; - - $row.empty(); - - if (!isArray) { - if ($row.attr('name')) { - $row.html(""); - } else { - // for rows that didn't have a key, simply remove the row - $row.remove(); - } - } else { - if ($table.find('.' + Settings.DATA_ROW_CLASS + "[data-category='" + categoryName + "']").length <= 1) { - // This is the last row of the category, so delete the header - $table.find('.' + Settings.DATA_CATEGORY_CLASS + "[data-category='" + categoryName + "']").remove(); - } - - if ($table.find('.' + Settings.DATA_ROW_CLASS).length > 1) { - updateDataChangedForSiblingRows($row); - - // this isn't the last row - we can just remove it - $row.remove(); - } else { - // this is the last row, we can't remove it completely since we need to post an empty array - $row - .removeClass(Settings.DATA_ROW_CLASS) - .removeClass(Settings.NEW_ROW_CLASS) - .removeAttr("data-category") - .addClass('empty-array-row') - .html(""); - } - } - - // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated - badgeSidebarForDifferences($table); -} - -function addTableCategory($categoryInputRow) { - var $input = $categoryInputRow.find("input").first(); - var categoryValue = $input.prop("value"); - if (!categoryValue || $categoryInputRow.closest("table").find("tr[data-category='" + categoryValue + "']").length !== 0) { - $categoryInputRow.addClass("has-warning"); - - setTimeout(function () { - $categoryInputRow.removeClass("has-warning"); - }, 400); - - return; - } - - var $rowInput = $categoryInputRow.next(".inputs").clone(); - if (!$rowInput) { - console.error("Error cloning inputs"); - } - - var canAddRows = $categoryInputRow.data("can-add-rows"); - var message = $categoryInputRow.data("message"); - var categoryKey = $categoryInputRow.data("key"); - var width = 0; - $categoryInputRow - .children("td") - .each(function () { - width += $(this).prop("colSpan") || 1; }); - - $input - .prop("value", "") - .focus(); - - $rowInput.find("td[name='" + categoryKey + "'] > input").first() - .prop("value", categoryValue); - $rowInput - .attr("data-category", categoryValue) - .addClass(Settings.NEW_ROW_CLASS); - - var $newCategoryRow = $(makeTableCategoryHeader(categoryKey, categoryValue, width, true, " - " + message)); - $newCategoryRow.addClass(Settings.NEW_ROW_CLASS); - - $categoryInputRow - .before($newCategoryRow) - .before($rowInput); - - if (canAddRows) { - $rowInput.removeAttr("hidden"); - } else { - addTableRow($rowInput); - } -} - -function deleteTableCategory($categoryHeaderRow) { - var categoryName = $categoryHeaderRow.data("category"); - - $categoryHeaderRow - .closest("table") - .find("tr[data-category='" + categoryName + "']") - .each(function () { - if ($(this).hasClass(Settings.DATA_ROW_CLASS)) { - deleteTableRow($(this)); - } else { - $(this).remove(); - } - }); -} - -function toggleTableCategory($categoryHeaderRow) { - var $icon = $categoryHeaderRow.find("." + Settings.TOGGLE_CATEGORY_SPAN_CLASS).first(); - var categoryName = $categoryHeaderRow.data("category"); - var wasExpanded = $icon.hasClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS); - if (wasExpanded) { - $icon - .addClass(Settings.TOGGLE_CATEGORY_CONTRACTED_CLASS) - .removeClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS); - } else { - $icon - .addClass(Settings.TOGGLE_CATEGORY_EXPANDED_CLASS) - .removeClass(Settings.TOGGLE_CATEGORY_CONTRACTED_CLASS); - } - $categoryHeaderRow - .closest("table") - .find("tr[data-category='" + categoryName + "']") - .toggleClass("contracted", wasExpanded); -} - -function moveTableRow(row, move_up) { - var table = $(row).closest('table') - var isArray = table.data('setting-type') === 'array' - if (!isArray) { - return; } - if (move_up) { - var prev_row = row.prev() - if (prev_row.hasClass(Settings.DATA_ROW_CLASS)) { - prev_row.before(row) - } - } else { - var next_row = row.next() - if (next_row.hasClass(Settings.DATA_ROW_CLASS)) { - next_row.after(row) - } - } - - // we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated - badgeSidebarForDifferences($(table)) -} - -function updateDataChangedForSiblingRows(row, forceTrue) { - // anytime a new row is added to an array we need to set data-changed for all sibling row inputs to true - // unless it matches the inital set of values - - if (!forceTrue) { - // figure out which group this row is in - var panelParentID = row.closest('.panel').attr('id') - // get the short name for the setting from the table - var tableShortName = row.closest('table').data('short-name') - - // get a JSON representation of that section - var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName] - if (Settings.initialValues[panelParentID]) { - var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName] - } else { - var initialPanelSettingJSON = {}; - } - - // if they are equal, we don't need data-changed - isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON) - } else { - isTrue = true - } - - row.siblings('.' + Settings.DATA_ROW_CLASS).each(function(){ - var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input') - if (isTrue) { - hiddenInput.attr('data-changed', isTrue) - } else { - hiddenInput.removeAttr('data-changed') - } - }) -} - -function cleanupFormValues(node) { - if (node.type && node.type === 'checkbox') { - return { name: node.name, value: node.checked ? true : false }; - } else { - return false; - } -} - -function showErrorMessage(title, message) { - swal(title, message) -} +}); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 65053b7366..68a36195d9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -501,7 +501,7 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { // store the new domain ID and auto network setting immediately QString newSettingsJSON = QString("{\"metaverse\": { \"id\": \"%1\", \"automatic_networking\": \"full\"}}").arg(id); auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8()); - _settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object()); + _settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object(), DomainSettings); // store the new ID and auto networking setting on disk _settingsManager.persistToFile(); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 05227d35b7..52754babb3 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -39,8 +39,10 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString SETTING_DEFAULT_KEY = "default"; const QString DESCRIPTION_NAME_KEY = "name"; +const QString DESCRIPTION_GROUP_LABEL_KEY = "label"; const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; const QString DESCRIPTION_COLUMNS_KEY = "columns"; +const QString CONTENT_SETTING_FLAG_KEY = "content_setting"; const QString SETTINGS_VIEWPOINT_KEY = "viewpoint"; @@ -63,6 +65,8 @@ DomainServerSettingsManager::DomainServerSettingsManager() { if (descriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) { _descriptionArray = descriptionDocument.object()[DESCRIPTION_SETTINGS_KEY].toArray(); + splitSettingsDescription(); + return; } } @@ -78,6 +82,91 @@ DomainServerSettingsManager::DomainServerSettingsManager() { Q_ARG(int, MISSING_SETTINGS_DESC_ERROR_CODE)); } +void DomainServerSettingsManager::splitSettingsDescription() { + // construct separate description arrays for domain settings and content settings + // since they are displayed on different pages + + // along the way we also construct one object that holds the groups separated by domain settings + // and content settings, so that the DS can setup dropdown menus below "Content" and "Settings" + // headers to jump directly to a settings group on the page of either + QJsonArray domainSettingsMenuGroups; + QJsonArray contentSettingsMenuGroups; + + foreach(const QJsonValue& group, _descriptionArray) { + QJsonObject groupObject = group.toObject(); + + static const QString HIDDEN_GROUP_KEY = "hidden"; + bool groupHidden = groupObject.contains(HIDDEN_GROUP_KEY) && groupObject[HIDDEN_GROUP_KEY].toBool(); + + QJsonArray domainSettingArray; + QJsonArray contentSettingArray; + + foreach(const QJsonValue& settingDescription, groupObject[DESCRIPTION_SETTINGS_KEY].toArray()) { + QJsonObject settingDescriptionObject = settingDescription.toObject(); + + bool isContentSetting = settingDescriptionObject.contains(CONTENT_SETTING_FLAG_KEY) + && settingDescriptionObject[CONTENT_SETTING_FLAG_KEY].toBool(); + + if (isContentSetting) { + // push the setting description to the pending content setting array + contentSettingArray.push_back(settingDescriptionObject); + } else { + // push the setting description to the pending domain setting array + domainSettingArray.push_back(settingDescriptionObject); + } + } + + if (!domainSettingArray.isEmpty() || !contentSettingArray.isEmpty()) { + + // we know for sure we'll have something to add to our settings menu groups + // so setup that object for the group now, as long as the group isn't hidden alltogether + QJsonObject settingsDropdownGroup; + + if (!groupHidden) { + settingsDropdownGroup[DESCRIPTION_NAME_KEY] = groupObject[DESCRIPTION_NAME_KEY]; + settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY]; + + static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id"; + if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) { + settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY]; + } + } + + if (!domainSettingArray.isEmpty()) { + // we have some domain settings from this group, add the group with the filtered settings + QJsonObject filteredGroupObject = groupObject; + filteredGroupObject[DESCRIPTION_SETTINGS_KEY] = domainSettingArray; + _domainSettingsDescription.push_back(filteredGroupObject); + + // if the group isn't hidden, add its information to the domain settings menu groups + if (!groupHidden) { + domainSettingsMenuGroups.push_back(settingsDropdownGroup); + } + } + + if (!contentSettingArray.isEmpty()) { + // we have some content settings from this group, add the group with the filtered settings + QJsonObject filteredGroupObject = groupObject; + filteredGroupObject[DESCRIPTION_SETTINGS_KEY] = contentSettingArray; + _contentSettingsDescription.push_back(filteredGroupObject); + + // if the group isn't hidden, add its information to the content settings menu groups + if (!groupHidden) { + contentSettingsMenuGroups.push_back(settingsDropdownGroup); + } + } + } + } + + // populate the settings menu groups with what we've collected + + static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings"; + static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings"; + + _settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups; + _settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups; +} + void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer message) { Assignment::Type type; message->readPrimitive(&type); @@ -986,48 +1075,72 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin } bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) { - if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) { - // this is a POST operation to change one or more settings - QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent()); - QJsonObject postedObject = postedDocument.object(); + if (connection->requestOperation() == QNetworkAccessManager::PostOperation) { + if (url.path() == SETTINGS_PATH_JSON || url.path() == CONTENT_SETTINGS_PATH_JSON) { + // this is a POST operation to change one or more settings + QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent()); + QJsonObject postedObject = postedDocument.object(); - // we recurse one level deep below each group for the appropriate setting - bool restartRequired = recurseJSONObjectAndOverwriteSettings(postedObject); + SettingsType endpointType = url.path() == SETTINGS_PATH_JSON ? DomainSettings : ContentSettings; - // store whatever the current _settingsMap is to file - persistToFile(); + // we recurse one level deep below each group for the appropriate setting + bool restartRequired = recurseJSONObjectAndOverwriteSettings(postedObject, endpointType); - // return success to the caller - QString jsonSuccess = "{\"status\": \"success\"}"; - connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); + // store whatever the current _settingsMap is to file + persistToFile(); - // defer a restart to the domain-server, this gives our HTTPConnection enough time to respond - if (restartRequired) { - const int DOMAIN_SERVER_RESTART_TIMER_MSECS = 1000; - QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart())); - } else { - unpackPermissions(); - apiRefreshGroupInformation(); - emit updateNodePermissions(); - emit settingsUpdated(); + // return success to the caller + QString jsonSuccess = "{\"status\": \"success\"}"; + connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json"); + + // defer a restart to the domain-server, this gives our HTTPConnection enough time to respond + if (restartRequired) { + const int DOMAIN_SERVER_RESTART_TIMER_MSECS = 1000; + QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart())); + } else { + unpackPermissions(); + apiRefreshGroupInformation(); + emit updateNodePermissions(); + emit settingsUpdated(); + } + + return true; } + } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { + static const QString SETTINGS_MENU_GROUPS_PATH = "/settings-menu-groups.json"; - return true; - } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) { - // setup a JSON Object with descriptions and non-omitted settings - const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions"; - const QString SETTINGS_RESPONSE_VALUE_KEY = "values"; + if (url.path() == SETTINGS_PATH_JSON || url.path() == CONTENT_SETTINGS_PATH_JSON) { - QJsonObject rootObject; - rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = _descriptionArray; - rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true); - connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json"); + // setup a JSON Object with descriptions and non-omitted settings + const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions"; + const QString SETTINGS_RESPONSE_VALUE_KEY = "values"; + + QJsonObject rootObject; + + bool forDomainSettings = (url.path() == SETTINGS_PATH_JSON); + bool forContentSettings = (url.path() == CONTENT_SETTINGS_PATH_JSON);; + + rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = forDomainSettings + ? _domainSettingsDescription : _contentSettingsDescription; + + // grab a domain settings object for all types, filtered for the right class of settings + rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true, forDomainSettings, forContentSettings); + + connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json"); + + return true; + } else if (url.path() == SETTINGS_MENU_GROUPS_PATH) { + connection->respond(HTTPConnection::StatusCode200, QJsonDocument(_settingsMenuGroups).toJson(), "application/json"); + + return true; + } } return false; } -QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& typeValue, bool isAuthenticated) { +QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& typeValue, bool isAuthenticated, + bool includeDomainSettings, bool includeContentSettings) { QJsonObject responseObject; if (!typeValue.isEmpty() || isAuthenticated) { @@ -1036,8 +1149,15 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty const QString AFFECTED_TYPES_JSON_KEY = "assignment-types"; + QJsonArray& filteredDescriptionArray = _descriptionArray; + if (includeDomainSettings && !includeContentSettings) { + filteredDescriptionArray = _domainSettingsDescription; + } else if (includeContentSettings && !includeDomainSettings) { + filteredDescriptionArray = _contentSettingsDescription; + } + // enumerate the groups in the description object to find which settings to pass - foreach(const QJsonValue& groupValue, _descriptionArray) { + foreach(const QJsonValue& groupValue, filteredDescriptionArray) { QJsonObject groupObject = groupValue.toObject(); QString groupKey = groupObject[DESCRIPTION_NAME_KEY].toString(); QJsonArray groupSettingsArray = groupObject[DESCRIPTION_SETTINGS_KEY].toArray(); @@ -1045,10 +1165,13 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty QJsonObject groupResponseObject; foreach(const QJsonValue& settingValue, groupSettingsArray) { + const QString VALUE_HIDDEN_FLAG_KEY = "value-hidden"; QJsonObject settingObject = settingValue.toObject(); + // consider this setting as long as it isn't hidden + // and we've been asked to include this type (domain setting or content setting) if (!settingObject[VALUE_HIDDEN_FLAG_KEY].toBool()) { QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray(); if (affectedTypesArray.isEmpty()) { @@ -1212,7 +1335,8 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson return QJsonObject(); } -bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) { +bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, + SettingsType settingsType) { static const QString SECURITY_ROOT_KEY = "security"; static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist"; static const QString BROADCASTING_KEY = "broadcasting"; @@ -1222,6 +1346,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ auto& settingsVariant = _configMap.getConfig(); bool needRestart = false; + auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription; + // Iterate on the setting groups foreach(const QString& rootKey, postedObject.keys()) { const QJsonValue& rootValue = postedObject[rootKey]; @@ -1236,7 +1362,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ QJsonObject groupDescriptionObject; // we need to check the description array to see if this is a root setting or a group setting - foreach(const QJsonValue& groupValue, _descriptionArray) { + foreach(const QJsonValue& groupValue, filteredDescriptionArray) { if (groupValue.toObject()[DESCRIPTION_NAME_KEY] == rootKey) { // we matched a group - keep this since we'll use it below to update the settings groupDescriptionObject = groupValue.toObject(); @@ -1269,6 +1395,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ if (!matchingDescriptionObject.isEmpty()) { updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject); + if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != SETTINGS_PATHS_KEY && rootKey != WIZARD_KEY) { needRestart = true; @@ -1286,6 +1413,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ if (!matchingDescriptionObject.isEmpty()) { const QJsonValue& settingValue = rootValue.toObject()[settingKey]; updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject); + if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) || settingKey == AC_SUBNET_WHITELIST_KEY) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index d2f6d1e526..5e13c9f28a 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -13,6 +13,7 @@ #define hifi_DomainServerSettingsManager_h #include +#include #include #include @@ -28,6 +29,7 @@ const QString SETTINGS_PATHS_KEY = "paths"; const QString SETTINGS_PATH = "/settings"; const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json"; +const QString CONTENT_SETTINGS_PATH_JSON = "/content-settings.json"; const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions"; const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions"; const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions"; @@ -38,6 +40,10 @@ const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens"; using GroupByUUIDKey = QPair; // groupID, rankID +enum SettingsType { + DomainSettings, + ContentSettings +}; class DomainServerSettingsManager : public QObject { Q_OBJECT @@ -123,8 +129,10 @@ private slots: private: QStringList _argumentList; - QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); - bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject); + QJsonArray filteredDescriptionArray(bool isContentSettings); + QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false, + bool includeDomainSettings = true, bool includeContentSettings = true); + bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType); void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap, const QJsonObject& settingDescription); @@ -132,8 +140,15 @@ private: void sortPermissions(); void persistToFile(); + void splitSettingsDescription(); + double _descriptionVersion; + QJsonArray _descriptionArray; + QJsonArray _domainSettingsDescription; + QJsonArray _contentSettingsDescription; + QJsonObject _settingsMenuGroups; + HifiConfigVariantMap _configMap; friend class DomainServer; diff --git a/libraries/embedded-webserver/src/HTTPManager.cpp b/libraries/embedded-webserver/src/HTTPManager.cpp index bd256578d8..fd127a2e92 100644 --- a/libraries/embedded-webserver/src/HTTPManager.cpp +++ b/libraries/embedded-webserver/src/HTTPManager.cpp @@ -79,7 +79,7 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, QHash redirectHeader; redirectHeader.insert(QByteArray("Location"), redirectLocation.toUtf8()); - connection->respond(HTTPConnection::StatusCode301, "", HTTPConnection::DefaultContentType, redirectHeader); + connection->respond(HTTPConnection::StatusCode302, "", HTTPConnection::DefaultContentType, redirectHeader); } // if the last thing is a trailing slash then we want to look for index file From b0967dfc3a188fb799f0c82fd42d41f3e7272a39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 30 Jan 2018 16:38:32 -0800 Subject: [PATCH 219/272] move some more settings to content, leave places in domain settings --- domain-server/resources/describe-settings.json | 7 +++++-- domain-server/resources/web/js/base-settings.js | 8 ++++++-- domain-server/resources/web/js/domain-server.js | 7 +++++++ domain-server/resources/web/settings/js/settings.js | 11 +++++++++-- domain-server/src/DomainServerSettingsManager.cpp | 7 ++++++- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 705d110542..b9a4246895 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -55,8 +55,8 @@ ] }, { - "label": "Places / Paths", - "html_id": "places_paths", + "label": "Paths", + "html_id": "paths", "restart": false, "settings": [ { @@ -64,6 +64,7 @@ "label": "Paths", "help": "Clients can enter a path to reach an exact viewpoint in your domain.
    Add rows to the table below to map a path to a viewpoint.
    The index path ( / ) is where clients will enter if they do not enter an explicit path.", "type": "table", + "content_setting": true, "can_add_new_rows": true, "key": { "name": "path", @@ -1081,6 +1082,7 @@ "name": "attenuation_per_doubling_in_distance", "label": "Default Domain Attenuation", "help": "Factor between 0 and 1.0 (0: No attenuation, 1.0: extreme attenuation)", + "content_setting": true, "placeholder": "0.5", "default": "0.5", "advanced": false @@ -1313,6 +1315,7 @@ "name": "entityEditFilter", "label": "Filter Entity Edits", "help": "Check all entity edits against this filter function.", + "content_setting": true, "placeholder": "url whose content is like: function filter(properties) { return properties; }", "default": "", "advanced": true diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js index 5e32463d61..aad342da63 100644 --- a/domain-server/resources/web/js/base-settings.js +++ b/domain-server/resources/web/js/base-settings.js @@ -94,9 +94,13 @@ var viewHelpers = { function reloadSettings(callback) { $.getJSON(Settings.endpoint, function(data){ - _.extend(data, viewHelpers) + _.extend(data, viewHelpers); - $('#panels').html(Settings.panelsTemplate(data)) + for (var spliceIndex in Settings.extraGroups) { + data.descriptions.splice(spliceIndex, 0, Settings.extraGroups[spliceIndex]); + } + + $('#panels').html(Settings.panelsTemplate(data)); Settings.data = data; Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true); diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index aa658bce3f..a7c8c3a4d1 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -79,6 +79,13 @@ $(document).ready(function(){ } $settingsDropdown.append(makeGroupDropdownElement(group, "/settings/")); + + // for domain settings, we add a dummy "Places" group that we fill + // via the API - add it to the dropdown menu in the right spot + if (index == 1) { + $settingsDropdown.append(""); + $settingsDropdown.append(makeGroupDropdownElement({ html_id: 'places', label: 'Places' }, "/settings/")); + } }); }); } diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 9a31b766a6..d10d1304c3 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -14,6 +14,14 @@ $(document).ready(function(){ return b; })(window.location.search.substr(1).split('&')); + // define extra groups to add to description, with their splice index + Settings.extraGroups = { + 1: { + html_id: 'places', + label: 'Places' + } + } + Settings.afterReloadActions = function() { // append the domain selection modal appendDomainIDButtons(); @@ -657,8 +665,7 @@ $(document).ready(function(){ var placesTableGroup = viewHelpers.getFormGroup('', placesTableSetting, Settings.data.values); // append the places table in the right place - $('#places_paths .panel-body').prepend(placesTableGroup); - //$('#' + Settings.PLACES_TABLE_ID).append(""); + $('#places .panel-body').prepend(placesTableGroup); var spinner = createDomainSpinner(); $('#' + Settings.PLACES_TABLE_ID).after($(spinner)); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 52754babb3..f91c5af06f 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -123,7 +123,10 @@ void DomainServerSettingsManager::splitSettingsDescription() { QJsonObject settingsDropdownGroup; if (!groupHidden) { - settingsDropdownGroup[DESCRIPTION_NAME_KEY] = groupObject[DESCRIPTION_NAME_KEY]; + if (groupObject.contains(DESCRIPTION_NAME_KEY)) { + settingsDropdownGroup[DESCRIPTION_NAME_KEY] = groupObject[DESCRIPTION_NAME_KEY]; + } + settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY]; static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id"; @@ -1383,7 +1386,9 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ foreach(const QJsonValue& groupValue, _descriptionArray) { // find groups with root values (they don't have a group name) QJsonObject groupObject = groupValue.toObject(); + if (!groupObject.contains(DESCRIPTION_NAME_KEY)) { + // this is a group with root values - check if our setting is in here matchingDescriptionObject = settingDescriptionFromGroup(groupObject, rootKey); From 8c924ea1065f6f7e3eea80b2f92b13c6e3573710 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 30 Jan 2018 17:13:03 -0800 Subject: [PATCH 220/272] update badge colour --- domain-server/resources/web/css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 22de75a778..5155ab2330 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -414,6 +414,7 @@ ul.nav li.dropdown ul.dropdown-menu .divider { .badge { margin-left: 5px; + background-color: #00B4EF !important; } .panel-title { From 2c2a6d5c603342099c8edddc5fed026d1ac1b3f5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 30 Jan 2018 17:24:56 -0800 Subject: [PATCH 221/272] add the empty label group to domain extra groups --- domain-server/resources/describe-settings.json | 6 ------ domain-server/resources/web/settings/js/settings.js | 6 +++++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b9a4246895..bd351eb173 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,12 +1,6 @@ { "version": 2.1, "settings": [ - { - "name": "label", - "label": "Label", - "settings": [ - ] - }, { "name": "metaverse", "label": "Metaverse / Networking", diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index d10d1304c3..39d776af8b 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -16,7 +16,11 @@ $(document).ready(function(){ // define extra groups to add to description, with their splice index Settings.extraGroups = { - 1: { + 0: { + html_id: 'label', + label: 'Label' + }, + 2: { html_id: 'places', label: 'Places' } From 6e93eb5dfa5b28da904c840ba7070323d9f513f7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 30 Jan 2018 17:27:52 -0800 Subject: [PATCH 222/272] update SVG icon for HMD with new colour --- domain-server/resources/web/images/hmd-w-eyes.svg | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/web/images/hmd-w-eyes.svg b/domain-server/resources/web/images/hmd-w-eyes.svg index c100de2f4e..0e9081c10c 100644 --- a/domain-server/resources/web/images/hmd-w-eyes.svg +++ b/domain-server/resources/web/images/hmd-w-eyes.svg @@ -2,7 +2,10 @@ - + .st0{fill:#666666;} + +
    - <% _.each(settings, function(setting) { %> + <% _.each(split_settings[0], function(setting) { %> <% keypath = isGrouped ? group.name + "." + setting.name : setting.name %> <%= getFormGroup(keypath, setting, values, false) %> <% }); %> + + <% if (split_settings[1].length > 0) { %> + +
    + <% _.each(split_settings[1], function(setting) { %> + <% keypath = isGrouped ? group.name + "." + setting.name : setting.name %> + <%= getFormGroup(keypath, setting, values, true) %> + <% }); %> +
    + <% } %>
    <% } %> diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 5155ab2330..8090c9f450 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -426,3 +426,7 @@ ul.nav li.dropdown ul.dropdown-menu .divider { position: relative; top: -1px; } + +.advanced-settings-section { + margin-top: 20px; +} From bb2df1eb37f30fda8a8f71be18a1b941836ebfca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 31 Jan 2018 15:27:29 -0800 Subject: [PATCH 225/272] rename entity server section to remove settings --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index bd351eb173..cf3321f831 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1268,7 +1268,7 @@ }, { "name": "entity_server_settings", - "label": "Entity Server Settings", + "label": "Entity Server", "assignment-types": [ 6 ], From 0ace92798d66c95987396f1b7c2d4d8989e3a42f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 31 Jan 2018 17:18:49 -0800 Subject: [PATCH 226/272] repair 2.1 settings migration code for avatar height --- domain-server/src/DomainServerSettingsManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index f91c5af06f..874e543a08 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -406,14 +406,14 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList QVariant* avatarMinScale = _configMap.valueForKeyPath(AVATAR_MIN_SCALE_KEYPATH); if (avatarMinScale) { - float scale = avatarMinScale->toFloat(); - _configMap.valueForKeyPath(AVATAR_MIN_HEIGHT_KEYPATH, scale * DEFAULT_AVATAR_HEIGHT); + auto newMinScaleVariant = _configMap.valueForKeyPath(AVATAR_MIN_HEIGHT_KEYPATH, true); + *newMinScaleVariant = avatarMinScale->toFloat() * DEFAULT_AVATAR_HEIGHT; } QVariant* avatarMaxScale = _configMap.valueForKeyPath(AVATAR_MAX_SCALE_KEYPATH); if (avatarMaxScale) { - float scale = avatarMaxScale->toFloat(); - _configMap.valueForKeyPath(AVATAR_MAX_HEIGHT_KEYPATH, scale * DEFAULT_AVATAR_HEIGHT); + auto newMaxScaleVariant = _configMap.valueForKeyPath(AVATAR_MAX_HEIGHT_KEYPATH, true); + *newMaxScaleVariant = avatarMaxScale->toFloat() * DEFAULT_AVATAR_HEIGHT; } } From 2f6b079d80dc618bb8208d644c2d9dadb79069f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 31 Jan 2018 17:19:07 -0800 Subject: [PATCH 227/272] quick re-organization of settings groups --- .../resources/describe-settings.json | 234 +++++++++--------- .../resources/web/js/domain-server.js | 2 +- domain-server/resources/web/js/shared.js | 4 + 3 files changed, 122 insertions(+), 118 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index cf3321f831..103c045516 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -951,99 +951,6 @@ } ] }, - { - "name": "asset_server", - "label": "Asset Server (ATP)", - "assignment-types": [ 3 ], - "settings": [ - { - "name": "enabled", - "type": "checkbox", - "label": "Enabled", - "help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)", - "default": true, - "advanced": true - }, - { - "name": "assets_path", - "type": "string", - "label": "Assets Path", - "help": "The path to the directory assets are stored in.
    If this path is relative, it will be relative to the application data directory.
    If you change this path you will need to manually copy any existing assets from the previous directory.", - "default": "", - "advanced": true - }, - { - "name": "assets_filesize_limit", - "type": "int", - "label": "File Size Limit", - "help": "The file size limit of an asset that can be imported into the asset server in MBytes. 0 (default) means no limit on file size.", - "default": 0, - "advanced": true - } - ] - }, - { - "name": "entity_script_server", - "label": "Entity Script Server (ESS)", - "assignment-types": [ 5 ], - "settings": [ - { - "name": "entity_pps_per_script", - "label": "Entity PPS per script", - "help": "The number of packets per second (PPS) that can be sent to the entity server for each server entity script. This contributes to a total overall amount.
    Example: 1000 PPS with 5 entites gives a total PPS of 5000 that is shared among the entity scripts. A single could use 4000 PPS, leaving 1000 for the rest, for example.", - "default": 900, - "type": "int", - "advanced": true - }, - { - "name": "max_total_entity_pps", - "label": "Maximum Total Entity PPS", - "help": "The maximum total packets per seconds (PPS) that can be sent to the entity server.
    Example: 5 scripts @ 1000 PPS per script = 5000 total PPS. A maximum total PPS of 4000 would cap this 5000 total PPS to 4000.", - "default": 9000, - "type": "int", - "advanced": true - } - ] - }, - { - "name": "avatars", - "label": "Avatars", - "assignment-types": [ 1, 2 ], - "settings": [ - { - "name": "min_avatar_height", - "type": "double", - "label": "Minimum Avatar Height (meters)", - "help": "Limits the height of avatars in your domain. Must be at least 0.009.", - "placeholder": 0.4, - "default": 0.4 - }, - { - "name": "max_avatar_height", - "type": "double", - "label": "Maximum Avatar Height (meters)", - "help": "Limits the scale of avatars in your domain. Cannot be greater than 1755.", - "placeholder": 5.2, - "default": 5.2 - }, - { - "name": "avatar_whitelist", - "label": "Avatars Allowed from:", - "help": "Comma separated list of URLs (with optional paths) that avatar .fst files are allowed from. If someone attempts to use an avatar with a different domain, it will be rejected and the replacement avatar will be used. If left blank, any domain is allowed.", - "placeholder": "", - "default": "", - "advanced": true - }, - { - "name": "replacement_avatar", - "label": "Replacement Avatar for disallowed avatars", - "help": "A URL for an avatar .fst to be used when someone tries to use an avatar that is not allowed. If left blank, the generic default avatar is used.", - "placeholder": "", - "default": "", - "advanced": true - } - ] - }, { "name": "audio_threading", "label": "Audio Threading", @@ -1266,9 +1173,82 @@ } ] }, + { + "name": "avatars", + "label": "Avatars", + "assignment-types": [ 1, 2 ], + "settings": [ + { + "name": "min_avatar_height", + "type": "double", + "label": "Minimum Avatar Height (meters)", + "help": "Limits the height of avatars in your domain. Must be at least 0.009.", + "placeholder": 0.4, + "default": 0.4 + }, + { + "name": "max_avatar_height", + "type": "double", + "label": "Maximum Avatar Height (meters)", + "help": "Limits the scale of avatars in your domain. Cannot be greater than 1755.", + "placeholder": 5.2, + "default": 5.2 + }, + { + "name": "avatar_whitelist", + "label": "Avatars Allowed from:", + "help": "Comma separated list of URLs (with optional paths) that avatar .fst files are allowed from. If someone attempts to use an avatar with a different domain, it will be rejected and the replacement avatar will be used. If left blank, any domain is allowed.", + "placeholder": "", + "default": "", + "advanced": true + }, + { + "name": "replacement_avatar", + "label": "Replacement Avatar for disallowed avatars", + "help": "A URL for an avatar .fst to be used when someone tries to use an avatar that is not allowed. If left blank, the generic default avatar is used.", + "placeholder": "", + "default": "", + "advanced": true + } + ] + }, + { + "name": "avatar_mixer", + "label": "Avatar Mixer", + "assignment-types": [ + 1 + ], + "settings": [ + { + "name": "max_node_send_bandwidth", + "type": "double", + "label": "Per-Node Bandwidth", + "help": "Desired maximum send bandwidth (in Megabits per second) to each node", + "placeholder": 5.0, + "default": 5.0, + "advanced": true + }, + { + "name": "auto_threads", + "label": "Automatically determine thread count", + "type": "checkbox", + "help": "Allow system to determine number of threads (recommended)", + "default": false, + "advanced": true + }, + { + "name": "num_threads", + "label": "Number of Threads", + "help": "Threads to spin up for avatar mixing (if not automatically set)", + "placeholder": "1", + "default": "1", + "advanced": true + } + ] + }, { "name": "entity_server_settings", - "label": "Entity Server", + "label": "Entities", "assignment-types": [ 6 ], @@ -1504,35 +1484,55 @@ ] }, { - "name": "avatar_mixer", - "label": "Avatar Mixer", - "assignment-types": [ - 1 - ], + "name": "asset_server", + "label": "Asset Server (ATP)", + "assignment-types": [ 3 ], "settings": [ { - "name": "max_node_send_bandwidth", - "type": "double", - "label": "Per-Node Bandwidth", - "help": "Desired maximum send bandwidth (in Megabits per second) to each node", - "placeholder": 5.0, - "default": 5.0, - "advanced": true - }, - { - "name": "auto_threads", - "label": "Automatically determine thread count", + "name": "enabled", "type": "checkbox", - "help": "Allow system to determine number of threads (recommended)", - "default": false, + "label": "Enabled", + "help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)", + "default": true, "advanced": true }, { - "name": "num_threads", - "label": "Number of Threads", - "help": "Threads to spin up for avatar mixing (if not automatically set)", - "placeholder": "1", - "default": "1", + "name": "assets_path", + "type": "string", + "label": "Assets Path", + "help": "The path to the directory assets are stored in.
    If this path is relative, it will be relative to the application data directory.
    If you change this path you will need to manually copy any existing assets from the previous directory.", + "default": "", + "advanced": true + }, + { + "name": "assets_filesize_limit", + "type": "int", + "label": "File Size Limit", + "help": "The file size limit of an asset that can be imported into the asset server in MBytes. 0 (default) means no limit on file size.", + "default": 0, + "advanced": true + } + ] + }, + { + "name": "entity_script_server", + "label": "Entity Script Server (ESS)", + "assignment-types": [ 5 ], + "settings": [ + { + "name": "entity_pps_per_script", + "label": "Entity PPS per script", + "help": "The number of packets per second (PPS) that can be sent to the entity server for each server entity script. This contributes to a total overall amount.
    Example: 1000 PPS with 5 entites gives a total PPS of 5000 that is shared among the entity scripts. A single could use 4000 PPS, leaving 1000 for the rest, for example.", + "default": 900, + "type": "int", + "advanced": true + }, + { + "name": "max_total_entity_pps", + "label": "Maximum Total Entity PPS", + "help": "The maximum total packets per seconds (PPS) that can be sent to the entity server.
    Example: 5 scripts @ 1000 PPS per script = 5000 total PPS. A maximum total PPS of 4000 would cap this 5000 total PPS to 4000.", + "default": 9000, + "type": "int", "advanced": true } ] diff --git a/domain-server/resources/web/js/domain-server.js b/domain-server/resources/web/js/domain-server.js index a7c8c3a4d1..ae5a452ec9 100644 --- a/domain-server/resources/web/js/domain-server.js +++ b/domain-server/resources/web/js/domain-server.js @@ -82,7 +82,7 @@ $(document).ready(function(){ // for domain settings, we add a dummy "Places" group that we fill // via the API - add it to the dropdown menu in the right spot - if (index == 1) { + if (index == 0) { $settingsDropdown.append(""); $settingsDropdown.append(makeGroupDropdownElement({ html_id: 'places', label: 'Places' }, "/settings/")); } diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index e1870a2fa8..e7fc77b707 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -1,3 +1,7 @@ +if (typeof Settings === "undefined") { + Settings = {}; +} + Object.assign(Settings, { DEPRECATED_CLASS: 'deprecated-setting', TRIGGER_CHANGE_CLASS: 'trigger-change', From 11fe279f6f976a878a3140875ea25132e725ede7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 1 Feb 2018 15:47:12 -0800 Subject: [PATCH 228/272] add domain settings backup and restore to web interface --- .../resources/web/content/js/content.js | 10 - domain-server/resources/web/css/style.css | 4 + domain-server/resources/web/header.html | 2 +- .../resources/web/js/base-settings.js | 10 + .../resources/web/js/domain-server.js | 7 +- domain-server/resources/web/js/shared.js | 8 +- .../resources/web/settings/js/settings.js | 86 ++++++- .../src/DomainServerSettingsManager.cpp | 227 ++++++++++++++++-- .../src/DomainServerSettingsManager.h | 7 +- 9 files changed, 316 insertions(+), 45 deletions(-) diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 7b2ed37b15..e448952c65 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -2,16 +2,6 @@ $(document).ready(function(){ Settings.afterReloadActions = function() {}; - function showSpinnerAlert(title) { - swal({ - title: title, - text: '
    ', - html: true, - showConfirmButton: false, - allowEscapeKey: false - }); - } - var frm = $('#upload-form'); frm.submit(function (ev) { $.ajax({ diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 8090c9f450..ed19d46fb5 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -430,3 +430,7 @@ ul.nav li.dropdown ul.dropdown-menu .divider { .advanced-settings-section { margin-top: 20px; } + +#restore-settings-button { + margin-top: 10px; +} diff --git a/domain-server/resources/web/header.html b/domain-server/resources/web/header.html index aff82d557e..a9a477c7fb 100644 --- a/domain-server/resources/web/header.html +++ b/domain-server/resources/web/header.html @@ -67,7 +67,7 @@
    diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js index f6069a3c40..3f410d4e2c 100644 --- a/domain-server/resources/web/js/base-settings.js +++ b/domain-server/resources/web/js/base-settings.js @@ -155,7 +155,10 @@ function postSettings(jsonSettings) { $(document).ready(function(){ - $('.save-button.navbar-btn').show(); + $(document).on('click', '.save-button', function(e){ + saveSettings(); + e.preventDefault(); + }); $.ajaxSetup({ timeout: 20000, @@ -254,7 +257,7 @@ $(document).ready(function(){ } }); - $('#' + Settings.FORM_ID).on('change keyup paste', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){ + $('#' + Settings.FORM_ID).on('change keyup paste', '.' + Settings.TRIGGER_CHANGE_CLASS , function(e){ // this input was changed, add the changed data attribute to it $(this).attr('data-changed', true); @@ -438,11 +441,6 @@ function saveSettings() { } } -$('body').on('click', '.save-button', function(e){ - saveSettings(); - return false; -}); - function makeTable(setting, keypath, setting_value) { var isArray = !_.has(setting, 'key'); var categoryKey = setting.categorize_by_key; @@ -788,8 +786,8 @@ function badgeForDifferences(changedElement) { } } - $(".save-button").prop("disabled", !hasChanges); - $(".save-button").html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE); + $('.save-button').prop("disabled", !hasChanges); + $('.save-button-text').html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE); // add the badge to the navbar item and the panel header $("a[href='" + settingsGroupAnchor(Settings.path, panelParentID) + "'] .badge").html(badgeValue); @@ -832,7 +830,7 @@ function addTableRow(row) { var keyInput = row.children(".key").children("input"); // whenever the keyInput changes, re-badge for differences - keyInput.on('change keyup paste', function(){ + keyInput.on('change keyup paste', function(e){ // update siblings in the row to have the correct name var currentKey = $(this).val(); @@ -844,7 +842,7 @@ function addTableRow(row) { } else { input.removeAttr("name"); } - }) + }); badgeForDifferences($(this)); }); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 401b322502..131670d221 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -1181,7 +1181,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection // create a timestamped filename for the backup const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" }; - auto backupFilename = "ds-settings-" + QDateTime::currentDateTime().toString(DATETIME_FORMAT) + ".json"; + auto backupFilename = "domain-settings_" + QDateTime::currentDateTime().toString(DATETIME_FORMAT) + ".json"; downloadHeaders.insert("Content-Disposition", QString("attachment; filename=\"%1\"").arg(backupFilename).toLocal8Bit()); From 9f2015ba469737c9d2e59f4e646d306050a4d739 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 5 Feb 2018 16:58:18 -0800 Subject: [PATCH 230/272] check correct element to determine if restart is required --- domain-server/resources/web/js/base-settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js index 3f410d4e2c..17f06f3ad1 100644 --- a/domain-server/resources/web/js/base-settings.js +++ b/domain-server/resources/web/js/base-settings.js @@ -138,7 +138,7 @@ function postSettings(jsonSettings) { type: 'POST' }).done(function(data){ if (data.status == "success") { - if ($(".save-button").html() === SAVE_BUTTON_LABEL_RESTART) { + if ($(".save-button-text").html() === SAVE_BUTTON_LABEL_RESTART) { showRestartModal(); } else { location.reload(true); From 3516a8939a23f821f3d1dfb407e1e964fad807b4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 6 Feb 2018 16:44:51 -0800 Subject: [PATCH 231/272] flag settings in description as being excluded from backups --- .../resources/describe-settings.json | 9 ++++--- .../src/DomainServerSettingsManager.cpp | 24 ++++++++++++------- .../src/DomainServerSettingsManager.h | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 103c045516..93d703c8b3 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -9,7 +9,8 @@ "name": "access_token", "label": "Access Token", "help": "This is your OAuth access token to connect this domain-server with your High Fidelity account.
    It can be generated by clicking the 'Connect Account' button above.
    You can also go to the My Security page of your account and generate a token with the 'domains' scope and paste it here.", - "advanced": true + "advanced": true, + "backup": false }, { "name": "id", @@ -159,7 +160,8 @@ { "name": "http_username", "label": "HTTP Username", - "help": "Username used for basic HTTP authentication." + "help": "Username used for basic HTTP authentication.", + "backup": false }, { "name": "http_password", @@ -167,7 +169,8 @@ "type": "password", "help": "Password used for basic HTTP authentication. Leave this alone if you do not want to change it.", "password_placeholder": "******", - "value-hidden": true + "value-hidden": true, + "backup": false }, { "name": "verify_http_password", diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 131670d221..b8d4a07238 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -40,6 +40,7 @@ const QString DESCRIPTION_SETTINGS_KEY = "settings"; const QString SETTING_DEFAULT_KEY = "default"; const QString DESCRIPTION_NAME_KEY = "name"; const QString DESCRIPTION_GROUP_LABEL_KEY = "label"; +const QString DESCRIPTION_BACKUP_FLAG_KEY = "backup"; const QString SETTING_DESCRIPTION_TYPE_KEY = "type"; const QString DESCRIPTION_COLUMNS_KEY = "columns"; const QString CONTENT_SETTING_FLAG_KEY = "content_setting"; @@ -1173,7 +1174,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection } else if (url.path() == SETTINGS_BACKUP_PATH) { // grab the settings backup as an authenticated user // for the domain settings type only, excluding hidden and default values - auto currentDomainSettingsJSON = settingsResponseObjectForType("", true, true, false, false); + auto currentDomainSettingsJSON = settingsResponseObjectForType("", true, true, false, false, true); // setup headers that tell the client to download the file wth a special name Headers downloadHeaders; @@ -1240,13 +1241,15 @@ bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settings } foreach(const QJsonValue& descriptionSettingValue, descriptionGroupSettings) { - const QString VALUE_HIDDEN_FLAG_KEY = "value-hidden"; QJsonObject descriptionSettingObject = descriptionSettingValue.toObject(); - // we'll override this setting with the default or what is in the restore as long as it isn't hidden - if (!descriptionSettingObject[VALUE_HIDDEN_FLAG_KEY].toBool()) { + // we'll override this setting with the default or what is in the restore as long as + // it isn't specifically excluded from backups + bool isBackedUpSetting = !descriptionSettingObject.contains(DESCRIPTION_BACKUP_FLAG_KEY) + || descriptionSettingObject[DESCRIPTION_BACKUP_FLAG_KEY].toBool(); + if (isBackedUpSetting) { QString settingName = descriptionSettingObject[DESCRIPTION_NAME_KEY].toString(); // check if we have a matching setting for this in the restore @@ -1315,7 +1318,7 @@ bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settings QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QString& typeValue, bool isAuthenticated, bool includeDomainSettings, bool includeContentSettings, - bool includeDefaults) { + bool includeDefaults, bool isForBackup) { QJsonObject responseObject; if (!typeValue.isEmpty() || isAuthenticated) { @@ -1347,7 +1350,11 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt QJsonObject settingObject = settingValue.toObject(); // consider this setting as long as it isn't hidden - if (!settingObject[VALUE_HIDDEN_FLAG_KEY].toBool()) { + // and either this isn't for a backup or it's a value included in backups + bool includedInBackups = !settingObject.contains(DESCRIPTION_BACKUP_FLAG_KEY) + || settingObject[DESCRIPTION_BACKUP_FLAG_KEY].toBool(); + + if (!settingObject[VALUE_HIDDEN_FLAG_KEY].toBool() && (!isForBackup || includedInBackups)) { QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray(); if (affectedTypesArray.isEmpty()) { affectedTypesArray = groupObject[AFFECTED_TYPES_JSON_KEY].toArray(); @@ -1370,8 +1377,8 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt variantValue = _configMap.value(settingName); } - // final check for inclusion, either we include default values - // or we don't but this isn't a default value + // final check for inclusion + // either we include default values or we don't but this isn't a default value if (includeDefaults || !variantValue.isNull()) { QJsonValue result; @@ -1407,7 +1414,6 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt } } - return responseObject; } diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 00707c33e3..9b2427b344 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -132,7 +132,7 @@ private: QJsonArray filteredDescriptionArray(bool isContentSettings); QJsonObject settingsResponseObjectForType(const QString& typeValue, bool isAuthenticated = false, bool includeDomainSettings = true, bool includeContentSettings = true, - bool includeDefaults = true); + bool includeDefaults = true, bool isForBackup = false); bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType); void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap, From 37b8fa2c0c84af04bb259d969c9a89c3d5c708ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 7 Feb 2018 15:22:33 -0800 Subject: [PATCH 232/272] put back default values in settings response --- domain-server/resources/web/js/shared.js | 7 ++++--- domain-server/src/DomainServerSettingsManager.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index f5346ce024..69721ee924 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -164,11 +164,12 @@ function getDomainFromAPI(callback) { if (callback === undefined) { callback = function() {}; } - - var domainID = Settings.data.values.metaverse.id; - if (domainID === null || domainID === undefined || domainID === '') { + + if (!domainIDIsSet()) { callback({ status: 'fail' }); return null; + } else { + var domainID = Settings.data.values.metaverse.id; } pendingDomainRequest = $.ajax({ diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index b8d4a07238..8febbd5769 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -1162,7 +1162,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection // and exclude default values rootObject[SETTINGS_RESPONSE_VALUE_KEY] = settingsResponseObjectForType("", true, forDomainSettings, forContentSettings, - false); + true); connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json"); From e14f46101b47c55a4bd540060655ae8e9cadeed8 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 14 Feb 2018 13:49:43 -0800 Subject: [PATCH 233/272] fix tablet rotation when switching into and out of create mode --- scripts/system/libraries/WebTablet.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 05b4963280..a28de5abc2 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -47,7 +47,7 @@ function calcSpawnInfo(hand, landscape) { var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position; var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation; - var forward = Quat.getForward(headRot); + var forward = Quat.getForward(Quat.cancelOutRollAndPitch(headRot)); var FORWARD_OFFSET = 0.5 * MyAvatar.sensorToWorldScale; finalPosition = Vec3.sum(headPos, Vec3.multiply(FORWARD_OFFSET, forward)); var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.UNIT_Y)); @@ -269,8 +269,9 @@ WebTablet.prototype.setLandscape = function(newLandscapeValue) { } this.landscape = newLandscapeValue; + var cameraOrientation = Quat.cancelOutRollAndPitch(Camera.orientation); Overlays.editOverlay(this.tabletEntityID, - { rotation: Quat.multiply(Camera.orientation, this.landscape ? ROT_LANDSCAPE : ROT_Y_180) }); + { rotation: Quat.multiply(cameraOrientation, this.landscape ? ROT_LANDSCAPE : ROT_Y_180) }); var tabletWidth = getTabletWidthFromSettings() * MyAvatar.sensorToWorldScale; var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x; @@ -278,7 +279,7 @@ WebTablet.prototype.setLandscape = function(newLandscapeValue) { var screenWidth = 0.82 * tabletWidth; var screenHeight = 0.81 * tabletHeight; Overlays.editOverlay(this.webOverlayID, { - rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW), + rotation: Quat.multiply(cameraOrientation, ROT_LANDSCAPE_WINDOW), dimensions: {x: this.landscape ? screenHeight : screenWidth, y: this.landscape ? screenWidth : screenHeight, z: 0.1} }); }; From d466c079a4c4a89738ae9d045bcb946953861e7c Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Wed, 14 Feb 2018 17:00:52 -0500 Subject: [PATCH 234/272] Simple fix for 801 Uncaught TypeError (details below). entityProperties.js was throwing out: 801 Uncaught TypeError: Cannot read property 'split' of undefined This moves properties.modelURL related checks behind the property.type validation check to avoid calling the function on an undefined member if the object doesn't have that key defined. Changes Committed: modified: scripts/system/html/js/entityProperties.js --- scripts/system/html/js/entityProperties.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 35235634e9..b27c852974 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -798,10 +798,13 @@ function loaded() { // HTML workaround since image is not yet a separate entity type var IMAGE_MODEL_NAME = 'default-image-model.fbx'; - var urlParts = properties.modelURL.split('/') - var propsFilename = urlParts[urlParts.length - 1]; - if (properties.type === "Model" && propsFilename === IMAGE_MODEL_NAME) { - properties.type = "Image"; + if (properties.type === "Model") { + var urlParts = properties.modelURL.split('/'); + var propsFilename = urlParts[urlParts.length - 1]; + + if (propsFilename === IMAGE_MODEL_NAME) { + properties.type = "Image"; + } } // Create class name for css ruleset filtering From 4d4b42848b2b12adb53954cac675391978ee2b71 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 14 Feb 2018 16:31:28 -0800 Subject: [PATCH 235/272] add alert for moved content settings --- domain-server/resources/web/base-settings.html | 6 ------ domain-server/resources/web/settings/index.shtml | 8 ++++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/base-settings.html b/domain-server/resources/web/base-settings.html index 2f0fcbe73b..da5561d03d 100644 --- a/domain-server/resources/web/base-settings.html +++ b/domain-server/resources/web/base-settings.html @@ -1,10 +1,4 @@
    -
    -
    - -
    -
    -
    diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index d71692523a..bdc02c5dcc 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -8,6 +8,14 @@ }; +
    +
    +
    +
    Your domain content settings are now available in Content
    +
    +
    +
    + From 5a8b8d4ac84068c47d5a06d66632cb3fd21aaa4c Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 14 Feb 2018 16:44:02 -0800 Subject: [PATCH 236/272] Lots of changes --- .../qml/hifi/commerce/checkout/Checkout.qml | 132 +++++++++++++----- .../InspectionCertificate.qml | 1 + .../hifi/commerce/purchases/PurchasedItem.qml | 2 + interface/src/commerce/Ledger.cpp | 5 +- 4 files changed, 105 insertions(+), 35 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index bd3f706004..981d5c5b9a 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -40,8 +40,9 @@ Rectangle { 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 var buttonTextNormal: ["REZ IT", "WEAR IT", "REPLACE CONTENT SET", "INSTALL IT", "WEAR IT"]; + property var buttonTextClicked: ["REZZED", "WORN", "CONTENT SET REPLACED!", "INSTALLED", "WORN"] + property var buttonGlyph: [hifi.glyphs.wand, hifi.glyphs.hat, hifi.glyphs.globe, hifi.glyphs.install, hifi.glyphs.avatar]; property bool shouldBuyWithControlledFailure: false; property bool debugCheckoutSuccess: false; property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified(); @@ -102,7 +103,7 @@ Rectangle { } else { root.balanceReceived = true; root.balanceAfterPurchase = result.data.balance - root.itemPrice; - root.setBuyText(); + root.refreshBuyUI(); } } @@ -117,7 +118,7 @@ Rectangle { console.log("WARNING - Received 'Already Owned' status about different Marketplace ID!"); root.alreadyOwned = false; } - root.setBuyText(); + root.refreshBuyUI(); } } } @@ -131,11 +132,11 @@ Rectangle { onItemHrefChanged: { if (root.itemHref.indexOf(".fst") > -1) { root.itemType = "avatar"; - } else if (root.itemHref.endsWith('.json.gz')) { + } else if (root.itemHref.indexOf('.json.gz') > -1) { root.itemType = "contentSet"; - } else if (root.itemHref.endsWith('.json')) { + } else if (root.itemHref.indexOf('.json') > -1) { root.itemType = "entity"; // "wearable" type handled later - } else if (root.itemHref.endsWith('.js')) { + } else if (root.itemHref.indexOf('.js') > -1) { root.itemType = "app"; } else { console.log("WARNING - Item type is UNKNOWN!"); @@ -304,6 +305,31 @@ Rectangle { anchors.left: parent.left; anchors.right: parent.right; + Rectangle { + id: loading; + z: 997; + visible: !root.ownershipStatusReceived || !root.balanceReceived; + anchors.fill: parent; + color: Qt.rgba(0.0, 0.0, 0.0, 0.7); + + // This object is always used in a popup. + // This MouseArea is used to prevent a user from being + // able to click on a button/mouseArea underneath the popup/section. + MouseArea { + anchors.fill: parent; + hoverEnabled: true; + propagateComposedEvents: false; + } + + AnimatedImage { + source: "../common/images/loader.gif" + width: 96; + height: width; + anchors.verticalCenter: parent.verticalCenter; + anchors.horizontalCenter: parent.horizontalCenter; + } + } + RalewayRegular { id: confirmPurchaseText; anchors.top: parent.top; @@ -437,7 +463,7 @@ Rectangle { Rectangle { id: buyTextContainer; visible: buyText.text !== ""; - anchors.top: cancelPurchaseButton.bottom; + anchors.top: parent.top; anchors.topMargin: 16; anchors.left: parent.left; anchors.right: parent.right; @@ -480,10 +506,23 @@ Rectangle { // Alignment horizontalAlignment: Text.AlignLeft; verticalAlignment: Text.AlignVCenter; + } + } - onLinkActivated: { - sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName}); - } + // "View in My Purchases" button + HifiControlsUit.Button { + id: viewInMyPurchasesButton; + visible: false; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.light; + anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top; + anchors.topMargin: 16; + height: 40; + anchors.left: parent.left; + anchors.right: parent.right; + text: "VIEW THIS ITEM IN MY PURCHASES"; + onClicked: { + sendToScript({method: 'checkout_goToPurchases', filterText: root.itemName}); } } @@ -491,21 +530,38 @@ Rectangle { HifiControlsUit.Button { id: buyButton; enabled: (root.balanceAfterPurchase >= 0 && ownershipStatusReceived && balanceReceived) || (!root.isCertified); - color: hifi.buttons.blue; + color: viewInMyPurchasesButton.visible ? hifi.buttons.white : hifi.buttons.blue; colorScheme: hifi.colorSchemes.light; - anchors.top: checkoutActionButtonsContainer.top; + anchors.top: viewInMyPurchasesButton.visible ? viewInMyPurchasesButton.bottom : + (buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top); anchors.topMargin: 16; height: 40; anchors.left: parent.left; anchors.right: parent.right; - text: ((root.isCertified) ? ((ownershipStatusReceived && balanceReceived) ? "Confirm Purchase" : "--") : "Get Item"); + text: ((root.isCertified) ? ((ownershipStatusReceived && balanceReceived) ? + (viewInMyPurchasesButton.visible ? "Buy It Again" : "Confirm Purchase") : "--") : "Get Item"); onClicked: { if (root.isCertified) { - buyButton.enabled = false; if (!root.shouldBuyWithControlledFailure) { - Commerce.buy(itemId, itemPrice); + if (root.itemType === "contentSet" && !Entities.canReplaceContent()) { + lightboxPopup.titleText = "Purchase Content Set"; + lightboxPopup.bodyText = "You will not be able to replace this domain's content with " + root.itemName + + " until the server owner gives you 'Replace Content' permissions.

    Are you sure you want to purchase this content set?"; + lightboxPopup.button1text = "CANCEL"; + lightboxPopup.button1method = "root.visible = false;" + lightboxPopup.button2text = "CONFIRM"; + lightboxPopup.button2method = "Commerce.buy('" + root.itemId + "', " + root.itemPrice + ");" + + "root.visible = false; buyButton.enabled = false; loading.visible = true;"; + lightboxPopup.visible = true; + } else { + buyButton.enabled = false; + loading.visible = true; + Commerce.buy(root.itemId, root.itemPrice); + } } else { - Commerce.buy(itemId, itemPrice, true); + buyButton.enabled = false; + loading.visible = true; + Commerce.buy(root.itemId, root.itemPrice, true); } } else { if (urlHandler.canHandleUrl(itemHref)) { @@ -618,8 +674,10 @@ Rectangle { // "Rez" button HifiControlsUit.Button { id: rezNowButton; - enabled: root.canRezCertifiedItems || root.itemType === "wearable"; - buttonGlyph: hifi.glyphs.lightning; + enabled: (root.itemType === "entity" && root.canRezCertifiedItems) || + (root.itemType === "contentSet" && Entities.canReplaceContent()) || + root.itemType === "wearable"; + buttonGlyph: (root.buttonGlyph)[itemTypesArray.indexOf(root.itemType)]; color: hifi.buttons.red; colorScheme: hifi.colorSchemes.light; anchors.top: completeText2.bottom; @@ -631,11 +689,17 @@ Rectangle { onClicked: { 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.bodyText = "Rezzing this content set will replace the existing environment and all of the items in this domain. " + + "If you want to save the state of the content in this domain, create a backup before proceeding.

    " + + "For more information about backing up and restoring content, " + + "" + + "click here to open info on your desktop browser."; lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "sendToScript({method: 'checkout_rezClicked', itemHref: " + root.itemHref + ", itemType: " + root.itemType + "});"; + lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemId + "', '" + root.itemHref + "');" + + "root.visible = false;rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start();" + + "UserActivityLogger.commerceEntityRezzed('" + root.itemId + "', 'checkout', '" + root.itemType + "');"; lightboxPopup.visible = true; } else { sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, itemType: root.itemType}); @@ -919,7 +983,7 @@ Rectangle { itemHref = message.params.itemHref; referrer = message.params.referrer; itemAuthor = message.params.itemAuthor; - setBuyText(); + refreshBuyUI(); break; default: console.log('Unrecognized message from marketplaces.js:', JSON.stringify(message)); @@ -927,13 +991,13 @@ Rectangle { } signal sendToScript(var message); - function setBuyText() { + function refreshBuyUI() { if (root.isCertified) { if (root.ownershipStatusReceived && root.balanceReceived) { if (root.balanceAfterPurchase < 0) { if (root.alreadyOwned) { - buyText.text = "Your Wallet does not have sufficient funds to purchase this item again.
    " + - '
    View the copy you own in My Purchases'; + buyText.text = "Your Wallet does not have sufficient funds to purchase this item again."; + viewInMyPurchasesButton.visible = true; } else { buyText.text = "Your Wallet does not have sufficient funds to purchase this item."; } @@ -943,15 +1007,19 @@ Rectangle { buyGlyph.size = 54; } else { if (root.alreadyOwned) { - buyText.text = 'You already own this item.
    Purchasing it will buy another copy.
    View this item in My Purchases
    '; - buyTextContainer.color = "#FFD6AD"; - buyTextContainer.border.color = "#FAC07D"; - buyGlyph.text = hifi.glyphs.alert; - buyGlyph.size = 46; + viewInMyPurchasesButton.visible = true; } else { buyText.text = ""; } + + if (root.itemType === "contentSet" && !Entities.canReplaceContent()) { + buyText.text = "The domain owner must enable 'Replace Content' permissions for you in this " + + "domain's server settings before you can replace this domain's content with " + root.itemName + ""; + buyTextContainer.color = "#FFC3CD"; + buyTextContainer.border.color = "#F3808F"; + buyGlyph.text = hifi.glyphs.alert; + buyGlyph.size = 54; + } } } else { buyText.text = ""; @@ -973,7 +1041,7 @@ Rectangle { } root.balanceReceived = false; root.ownershipStatusReceived = false; - Commerce.inventory(); + Commerce.alreadyOwned(root.itemId); Commerce.balance(); } diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index f493747c5e..a622349d00 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -208,6 +208,7 @@ Rectangle { // able to click on a button/mouseArea underneath the popup/section. MouseArea { anchors.fill: parent; + hoverEnabled: true; propagateComposedEvents: false; } diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 9db847eada..d19a16e74e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -209,6 +209,8 @@ Item { "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"; + } else { + "" } } size: 16; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index f319881035..dff441f840 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -49,6 +49,7 @@ Handler(balance) Handler(inventory) Handler(transferHfcToNode) Handler(transferHfcToUsername) +Handler(alreadyOwned) void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, AccountManagerAuth::Type authType, QJsonObject request) { auto accountManager = DependencyManager::get(); @@ -337,13 +338,11 @@ void Ledger::transferHfcToUsername(const QString& hfc_key, const QString& userna signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_user", "transferHfcToUsernameSuccess", "transferHfcToUsernameFailure"); } -void Ledger::alreadyOwnedSuccess(QNetworkReply& reply) { apiResponse("alreadyOwned", reply); } -void Ledger::alreadyOwnedFailure(QNetworkReply& reply) { failResponse("alreadyOwned", reply); } void Ledger::alreadyOwned(const QString& marketplaceId) { auto wallet = DependencyManager::get(); QString endpoint = "already_owned"; QJsonObject request; request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys()); request["marketplace_item_id"] = marketplaceId; - send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::None, request); + send(endpoint, "alreadyOwnedSuccess", "alreadyOwnedFailure", QNetworkAccessManager::PutOperation, AccountManagerAuth::Required, request); } From 324eefc9146d0933ceb819145b2d206dafa38288 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 14 Feb 2018 12:56:34 -0800 Subject: [PATCH 237/272] remove fresnel, add unlit, fix overlays, cleanup --- .../qml/hifi/tablet/NewMaterialDialog.qml | 4 +- interface/src/Application.cpp | 16 +- interface/src/ui/overlays/ModelOverlay.cpp | 14 +- interface/src/ui/overlays/ModelOverlay.h | 4 +- interface/src/ui/overlays/Overlay.cpp | 8 +- interface/src/ui/overlays/Overlay.h | 4 +- .../src/avatars-renderer/Avatar.cpp | 12 +- .../src/avatars-renderer/Avatar.h | 4 +- libraries/avatars/src/AvatarData.h | 4 +- .../src/RenderableEntityItem.cpp | 8 +- .../src/RenderableEntityItem.h | 4 +- .../src/RenderableMaterialEntityItem.cpp | 14 +- .../src/RenderableMaterialEntityItem.h | 6 +- .../src/RenderableModelEntityItem.cpp | 12 +- .../src/RenderableModelEntityItem.h | 4 +- libraries/entities/src/EntityItem.cpp | 12 +- libraries/entities/src/EntityItem.h | 8 +- .../entities/src/EntityItemProperties.cpp | 120 +++++++-------- libraries/entities/src/EntityItemProperties.h | 12 +- libraries/entities/src/EntityPropertyFlags.h | 10 +- libraries/entities/src/EntityTree.cpp | 31 ++-- libraries/entities/src/EntityTree.h | 8 +- libraries/entities/src/MaterialEntityItem.cpp | 145 ++++++++---------- libraries/entities/src/MaterialEntityItem.h | 58 +++---- libraries/graphics/src/graphics/Material.h | 4 + .../src/model-networking/MaterialCache.cpp | 61 ++++++-- .../src/model-networking/MaterialCache.h | 17 +- libraries/octree/src/OctreePacketData.h | 4 +- libraries/render-utils/src/Model.cpp | 24 +-- libraries/render-utils/src/Model.h | 6 +- libraries/shared/src/MaterialMappingMode.cpp | 24 +++ .../{MaterialMode.h => MaterialMappingMode.h} | 12 +- libraries/shared/src/MaterialMode.cpp | 24 --- scripts/developer/tests/toolbarTest.js | 2 +- scripts/system/edit.js | 6 +- scripts/system/html/entityProperties.html | 12 +- scripts/system/html/js/entityProperties.js | 78 +++++----- 37 files changed, 417 insertions(+), 379 deletions(-) create mode 100644 libraries/shared/src/MaterialMappingMode.cpp rename libraries/shared/src/{MaterialMode.h => MaterialMappingMode.h} (54%) delete mode 100644 libraries/shared/src/MaterialMode.cpp diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml index d0bbd79a95..226c17e8e2 100644 --- a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -114,7 +114,7 @@ Rectangle { } ComboBox { - id: materialMode + id: materialMappingMode property var materialArray: ["UV space material", "3D projected material"] @@ -142,7 +142,7 @@ Rectangle { method: "newMaterialDialogAdd", params: { textInput: materialURL.text, - //comboBox: materialMode.currentIndex + //comboBox: materialMappingMode.currentIndex } }); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 717efa6e5a..70b94443ea 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1593,37 +1593,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } }); - EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->addMaterial(material, parentMaterialID); + avatar->addMaterial(material, parentMaterialName); return true; } return false; }); - EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName) { auto avatarManager = DependencyManager::get(); auto avatar = avatarManager->getAvatarBySessionID(avatarID); if (avatar) { - avatar->removeMaterial(material, parentMaterialID); + avatar->removeMaterial(material, parentMaterialName); return true; } return false; }); - EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->addMaterial(material, parentMaterialID); + overlay->addMaterial(material, parentMaterialName); return true; } return false; }); - EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName) { auto overlay = _overlays.getOverlay(overlayID); if (overlay) { - overlay->removeMaterial(material, parentMaterialID); + overlay->removeMaterial(material, parentMaterialName); return true; } return false; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ab7f55d6e7..e4ee889307 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -83,6 +83,7 @@ void ModelOverlay::update(float deltatime) { auto modelOverlay = static_cast(&data); modelOverlay->setSubRenderItemIDs(newRenderItemIDs); }); + processMaterials(); } if (_visibleDirty) { _visibleDirty = false; @@ -108,6 +109,7 @@ void ModelOverlay::update(float deltatime) { bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) { Volume3DOverlay::addToScene(overlay, scene, transaction); _model->addToScene(scene, transaction); + processMaterials(); return true; } @@ -633,17 +635,17 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const { return 0; } -void ModelOverlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { - Overlay::addMaterial(material, parentMaterialID); +void ModelOverlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + Overlay::addMaterial(material, parentMaterialName); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, parentMaterialID); + _model->addMaterial(material, parentMaterialName); } } -void ModelOverlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { - Overlay::removeMaterial(material, parentMaterialID); +void ModelOverlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + Overlay::removeMaterial(material, parentMaterialName); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, parentMaterialID); + _model->removeMaterial(material, parentMaterialName); } } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 6761b1508c..5735854b3b 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, const QString& parentMaterialID) override; - void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; protected: Transform evalRenderTransform() override; diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 04d6c2fe4d..766177e3a6 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, const QString& parentMaterialID) { +void Overlay::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].push(material); + _materials[parentMaterialName].push(material); } -void Overlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { +void Overlay::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].remove(material); + _materials[parentMaterialName].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 bd9f7942fd..ff45acddcf 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, const QString& parentMaterialID); - virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); protected: float updatePulse(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 3276a8fe89..796e73fcbc 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, const QString& parentMaterialID) { +void Avatar::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].push(material); + _materials[parentMaterialName].push(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->addMaterial(material, parentMaterialID); + _skeletonModel->addMaterial(material, parentMaterialName); } } -void Avatar::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { +void Avatar::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].remove(material); + _materials[parentMaterialName].remove(material); if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) { - _skeletonModel->removeMaterial(material, parentMaterialID); + _skeletonModel->removeMaterial(material, parentMaterialName); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 49aa664a9f..14283a9188 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, const QString& parentMaterialID) override; - void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 832585a483..48f7e19146 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, const QString& parentMaterialID) {} - virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) {} + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) {} + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) {} signals: void displayNameChanged(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 81d7dceb0d..9ccf58c04c 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, const QString& parentMaterialID) { +void EntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].push(material); + _materials[parentMaterialName].push(material); } -void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { +void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].remove(material); + _materials[parentMaterialName].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 6247a97c21..4fc50ccc9a 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, const QString& parentMaterialID); - virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + virtual void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); + virtual void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); signals: void requestRenderUpdate(); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 529aa03124..70d0234732 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -18,7 +18,7 @@ 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) { + if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { return true; } return false; @@ -30,9 +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(); + _materialMappingPos = entity->getMaterialMappingPos(); + _materialMappingScale = entity->getMaterialMappingScale(); + _materialMappingRot = entity->getMaterialMappingRot(); _renderTransform = getModelTransform(); const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); @@ -238,9 +238,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { 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)); + textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot))); + textureTransform.setScale(glm::vec3(_materialMappingScale, 1)); }); if (!parentID.isNull() || !drawMaterial) { return; diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 4af21d84f6..fef1a41138 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -34,9 +34,9 @@ private: QUuid _parentID; bool _clientOnly; QUuid _owningAvatarID; - glm::vec2 _materialPos; - glm::vec2 _materialScale; - float _materialRot; + glm::vec2 _materialMappingPos; + glm::vec2 _materialMappingScale; + float _materialMappingRot; Transform _renderTransform; std::shared_ptr _drawMaterial; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e28ba797d5..3205d68513 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, const QString& parentMaterialID) { - Parent::addMaterial(material, parentMaterialID); +void ModelEntityRenderer::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + Parent::addMaterial(material, parentMaterialName); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->addMaterial(material, parentMaterialID); + _model->addMaterial(material, parentMaterialName); } } -void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { - Parent::removeMaterial(material, parentMaterialID); +void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + Parent::removeMaterial(material, parentMaterialName); if (_model && _model->fetchRenderItemIDs().size() > 0) { - _model->removeMaterial(material, parentMaterialID); + _model->removeMaterial(material, parentMaterialName); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 3951deaa2d..9d9b98ba98 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, const QString& parentMaterialID) override; - void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) override; + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) override; protected: virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3ea81e5a36..3bb1406252 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2940,16 +2940,16 @@ void EntityItem::preDelete() { } } -void EntityItem::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { +void EntityItem::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].push(material); - emit addMaterialToRenderItem(material, parentMaterialID); + _materials[parentMaterialName].push(material); + emit addMaterialToRenderItem(material, parentMaterialName); } -void EntityItem::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { +void EntityItem::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { std::lock_guard lock(_materialsLock); - _materials[parentMaterialID].remove(material); - emit removeMaterialFromRenderItem(material, parentMaterialID); + _materials[parentMaterialName].remove(material); + emit removeMaterialFromRenderItem(material, parentMaterialName); } std::unordered_map EntityItem::getMaterials() { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 97d2f32a04..203b513a76 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, const QString& parentMaterialID); - void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); std::unordered_map getMaterials(); signals: void requestRenderUpdate(); - void addMaterialToRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); - void removeMaterialFromRenderItem(graphics::MaterialPointer material, const QString& parentMaterialID); + void addMaterialToRenderItem(graphics::MaterialPointer material, const QString& parentMaterialName); + void removeMaterialFromRenderItem(graphics::MaterialPointer material, const QString& parentMaterialName); protected: QHash _changeHandlers; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 450d0727f9..a2724c4cbf 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -115,15 +115,15 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_STATIC_MESH); } -QHash stringToMaterialModeLookup; +QHash stringToMaterialMappingModeLookup; -void addMaterialMode(MaterialMode mode) { - stringToMaterialModeLookup[MaterialModeHelpers::getNameForMaterialMode(mode)] = mode; +void addMaterialMappingMode(MaterialMappingMode mode) { + stringToMaterialMappingModeLookup[MaterialMappingModeHelpers::getNameForMaterialMappingMode(mode)] = mode; } -void buildStringToMaterialModeLookup() { - addMaterialMode(UV); - addMaterialMode(PROJECTED); +void buildStringToMaterialMappingModeLookup() { + addMaterialMappingMode(UV); + addMaterialMappingMode(PROJECTED); } QString getCollisionGroupAsString(uint8_t group) { @@ -270,18 +270,18 @@ void EntityItemProperties::setSkyboxModeFromString(const QString& skyboxMode) { } } -QString EntityItemProperties::getMaterialModeAsString() const { - return MaterialModeHelpers::getNameForMaterialMode(_materialMode); +QString EntityItemProperties::getMaterialMappingModeAsString() const { + return MaterialMappingModeHelpers::getNameForMaterialMappingMode(_materialMappingMode); } -void EntityItemProperties::setMaterialModeFromString(const QString& materialMode) { - if (stringToMaterialModeLookup.empty()) { - buildStringToMaterialModeLookup(); +void EntityItemProperties::setMaterialMappingModeFromString(const QString& materialMappingMode) { + if (stringToMaterialMappingModeLookup.empty()) { + buildStringToMaterialMappingModeLookup(); } - auto materialModeItr = stringToMaterialModeLookup.find(materialMode.toLower()); - if (materialModeItr != stringToMaterialModeLookup.end()) { - _materialMode = materialModeItr.value(); - _materialModeChanged = true; + auto materialMappingModeItr = stringToMaterialMappingModeLookup.find(materialMappingMode.toLower()); + if (materialMappingModeItr != stringToMaterialMappingModeLookup.end()) { + _materialMappingMode = materialMappingModeItr.value(); + _materialMappingModeChanged = true; } } @@ -356,12 +356,12 @@ 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_MAPPING_MODE, materialMappingMode); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); - 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); + CHECK_PROPERTY_CHANGE(PROP_PARENT_MATERIAL_NAME, parentMaterialName); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -661,12 +661,12 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool // Materials 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_GETTER(PROP_MATERIAL_MAPPING_MODE, materialMappingMode, getMaterialMappingModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); - 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); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_NAME, parentMaterialName); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); } if (!skipDefaults && !strictSemantics) { @@ -803,12 +803,12 @@ 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_ENUM(materialMode, MaterialMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMappingMode, MaterialMappingMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); - 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); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialName, QString, setParentMaterialName); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, glmVec2, setMaterialMappingPos); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1164,12 +1164,12 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue 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_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, 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); + ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -1557,12 +1557,12 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy // 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_MAPPING_MODE, (uint32_t)properties.getMaterialMappingMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); - 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()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, properties.getParentMaterialName()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, properties.getMaterialMappingPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, properties.getMaterialMappingScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, properties.getMaterialMappingRot()); } APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -1924,12 +1924,12 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int // 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_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); - 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); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, glmVec2, setMaterialMappingPos); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, glmVec2, setMaterialMappingScale); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -2106,12 +2106,12 @@ void EntityItemProperties::markAllChanged() { //_alphaFinishChanged = true; _materialURLChanged = true; - _materialModeChanged = true; + _materialMappingModeChanged = true; _priorityChanged = true; - _parentMaterialIDChanged = true; - _materialPosChanged = true; - _materialScaleChanged = true; - _materialRotChanged = true; + _parentMaterialNameChanged = true; + _materialMappingPosChanged = true; + _materialMappingScaleChanged = true; + _materialMappingRotChanged = true; // Certifiable Properties _itemNameChanged = true; @@ -2439,23 +2439,23 @@ QList EntityItemProperties::listChangedProperties() { if (materialURLChanged()) { out += "materialURL"; } - if (materialModeChanged()) { - out += "materialMode"; + if (materialMappingModeChanged()) { + out += "materialMappingMode"; } if (priorityChanged()) { out += "priority"; } - if (parentMaterialIDChanged()) { - out += "parentMaterialID"; + if (parentMaterialNameChanged()) { + out += "parentMaterialName"; } - if (materialPosChanged()) { - out += "materialPos"; + if (materialMappingPosChanged()) { + out += "materialMappingPos"; } - if (materialScaleChanged()) { - out += "materialScale"; + if (materialMappingScaleChanged()) { + out += "materialMappingScale"; } - if (materialRotChanged()) { - out += "materialRot"; + if (materialMappingRotChanged()) { + out += "materialMappingRot"; } // Certifiable Properties diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index daa2272e36..36ca47291c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -44,7 +44,7 @@ #include "TextEntityItem.h" #include "ZoneEntityItem.h" -#include "MaterialMode.h" +#include "MaterialMappingMode.h" const quint64 UNKNOWN_CREATED_TIME = 0; @@ -223,12 +223,12 @@ public: 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_ENUM(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode, UV); DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, 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); + DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString, "0"); + DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2, glm::vec2(0, 0)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2, glm::vec2(1, 1)); + DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, 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/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 6ed2186760..b65d5d1a3f 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -228,12 +228,12 @@ enum EntityPropertyList { PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts PROP_MATERIAL_URL, - PROP_MATERIAL_TYPE, + PROP_MATERIAL_MAPPING_MODE, PROP_MATERIAL_PRIORITY, - PROP_PARENT_MATERIAL_ID, - PROP_MATERIAL_POS, - PROP_MATERIAL_SCALE, - PROP_MATERIAL_ROT, + PROP_PARENT_MATERIAL_NAME, + PROP_MATERIAL_MAPPING_POS, + PROP_MATERIAL_MAPPING_SCALE, + PROP_MATERIAL_MAPPING_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 d8a4d2799e..8abd5efc13 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1740,18 +1740,15 @@ void EntityTree::fixupNeedsParentFixups() { }); entity->locationChanged(true); 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(); + } 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(); } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); doMove = true; iter.remove(); // and pull it out of the list - entity->postParentFixup(); } if (queryAACubeSuccess && doMove) { @@ -2394,30 +2391,30 @@ std::function Ent std::function EntityTree::_addMaterialToOverlayOperator = nullptr; std::function EntityTree::_removeMaterialFromOverlayOperator = nullptr; -bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { +bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName) { if (_addMaterialToAvatarOperator) { - return _addMaterialToAvatarOperator(avatarID, material, parentMaterialID); + return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName); } return false; } -bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialID) { +bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName) { if (_removeMaterialFromAvatarOperator) { - return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialID); + return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName); } return false; } -bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { +bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName) { if (_addMaterialToOverlayOperator) { - return _addMaterialToOverlayOperator(overlayID, material, parentMaterialID); + return _addMaterialToOverlayOperator(overlayID, material, parentMaterialName); } return false; } -bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialID) { +bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName) { if (_removeMaterialFromOverlayOperator) { - return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialID); + return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialName); } return false; } \ No newline at end of file diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index c37b6c8a81..568d552d8d 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -282,13 +282,13 @@ public: 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 bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName); + static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const QString& parentMaterialName); 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); + static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName); + static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const QString& parentMaterialName); signals: void deletingEntity(const EntityItemID& entityID); diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index fcca2d9803..91333e6e80 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -30,12 +30,12 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit 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(materialMappingMode, getMaterialMappingMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); - 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); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentMaterialName, getParentMaterialName); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingPos, getMaterialMappingPos); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingScale, getMaterialMappingScale); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingRot, getMaterialMappingRot); return properties; } @@ -43,12 +43,12 @@ 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(materialMappingMode, setMaterialMappingMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); - 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); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentMaterialName, setParentMaterialName); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingPos, setMaterialMappingPos); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingScale, setMaterialMappingScale); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingRot, setMaterialMappingRot); if (somethingChanged) { bool wantDebug = false; @@ -72,12 +72,12 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da 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_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode); READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); - 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); + READ_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName); + READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, glm::vec2, setMaterialMappingPos); + READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, glm::vec2, setMaterialMappingScale); + READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); return bytesRead; } @@ -87,12 +87,12 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); requestedProperties += PROP_MATERIAL_URL; - requestedProperties += PROP_MATERIAL_TYPE; + requestedProperties += PROP_MATERIAL_MAPPING_MODE; requestedProperties += PROP_MATERIAL_PRIORITY; - requestedProperties += PROP_PARENT_MATERIAL_ID; - requestedProperties += PROP_MATERIAL_POS; - requestedProperties += PROP_MATERIAL_SCALE; - requestedProperties += PROP_MATERIAL_ROT; + requestedProperties += PROP_PARENT_MATERIAL_NAME; + requestedProperties += PROP_MATERIAL_MAPPING_POS; + requestedProperties += PROP_MATERIAL_MAPPING_SCALE; + requestedProperties += PROP_MATERIAL_MAPPING_ROT; return requestedProperties; } @@ -106,26 +106,26 @@ 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_MAPPING_MODE, (uint32_t)getMaterialMappingMode()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - 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()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, getParentMaterialName()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, getMaterialMappingPos()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, getMaterialMappingScale()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, getMaterialMappingRot()); } void MaterialEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; - qCDebug(entities) << " material json:" << _materialURL; + qCDebug(entities) << " material url:" << _materialURL; qCDebug(entities) << " current material name:" << _currentMaterialName; - qCDebug(entities) << " material type:" << _materialMode; + qCDebug(entities) << " material mapping mode:" << _materialMappingMode; qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent material ID:" << _parentMaterialID; - qCDebug(entities) << " material pos:" << _materialPos; - qCDebug(entities) << " material scale:" << _materialRot; - qCDebug(entities) << " material rot:" << _materialScale; + qCDebug(entities) << " parent material name:" << _parentMaterialName; + qCDebug(entities) << " material mapping pos:" << _materialMappingPos; + qCDebug(entities) << " material mapping scale:" << _materialMappingRot; + qCDebug(entities) << " material mapping rot:" << _materialMappingScale; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); @@ -137,8 +137,8 @@ void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { } std::shared_ptr MaterialEntityItem::getMaterial() const { - auto material = _materials.find(_currentMaterialName); - if (material != _materials.end()) { + auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName); + if (material != _parsedMaterials.networkMaterials.end()) { return material.value(); } else { return nullptr; @@ -151,28 +151,14 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u removeMaterial(); _materialURL = materialURLString; - // TODO: if URL ends with ?string, try to set _currentMaterialName = string + if (materialURLString.contains("?")) { + auto split = materialURLString.split("?"); + _currentMaterialName = split.last(); + } 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()) { - auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(material.toObject()); - _materials[networkMaterial.first] = networkMaterial.second; - _materialNames.push_back(networkMaterial.first); - } - } - } else if (materialJSON.isObject()) { - auto networkMaterial = NetworkMaterialResource::parseJSONMaterial(materialJSON.object()); - _materials[networkMaterial.first] = networkMaterial.second; - _materialNames.push_back(networkMaterial.first); - } - } + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8())); + // Since our material changed, the current name might not be valid anymore, so we need to update setCurrentMaterialName(_currentMaterialName); applyMaterial(); @@ -180,8 +166,7 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u _networkMaterial = MaterialCache::instance().getMaterial(materialURLString); auto onMaterialRequestFinished = [&](bool success) { if (success) { - _materials[_networkMaterial->name] = _networkMaterial->networkMaterial; - _materialNames.push_back(_networkMaterial->name); + _parsedMaterials = _networkMaterial->parsedMaterials; setCurrentMaterialName(_currentMaterialName); applyMaterial(); @@ -199,11 +184,11 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u } void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) { - auto material = _materials.find(currentMaterialName); - if (material != _materials.end()) { + auto material = _parsedMaterials.networkMaterials.find(currentMaterialName); + if (material != _parsedMaterials.networkMaterials.end()) { _currentMaterialName = currentMaterialName; - } else if (_materialNames.size() > 0) { - _currentMaterialName = _materialNames[0]; + } else if (_parsedMaterials.names.size() > 0) { + _currentMaterialName = _parsedMaterials.names[0]; } } @@ -217,26 +202,26 @@ void MaterialEntityItem::setUserData(const QString& userData) { } } -void MaterialEntityItem::setMaterialPos(const glm::vec2& materialPos) { - if (_materialPos != materialPos) { +void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { + if (_materialMappingPos != materialMappingPos) { removeMaterial(); - _materialPos = materialPos; + _materialMappingPos = materialMappingPos; applyMaterial(); } } -void MaterialEntityItem::setMaterialScale(const glm::vec2& materialScale) { - if (_materialScale != materialScale) { +void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { + if (_materialMappingScale != materialMappingScale) { removeMaterial(); - _materialScale = materialScale; + _materialMappingScale = materialMappingScale; applyMaterial(); } } -void MaterialEntityItem::setMaterialRot(const float& materialRot) { - if (_materialRot != materialRot) { +void MaterialEntityItem::setMaterialMappingRot(const float& materialMappingRot) { + if (_materialMappingRot != materialMappingRot) { removeMaterial(); - _materialRot = materialRot; + _materialMappingRot = materialMappingRot; applyMaterial(); } } @@ -249,10 +234,10 @@ void MaterialEntityItem::setPriority(quint16 priority) { } } -void MaterialEntityItem::setParentMaterialID(const QString& parentMaterialID) { - if (_parentMaterialID != parentMaterialID) { +void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) { + if (_parentMaterialName != parentMaterialName) { removeMaterial(); - _parentMaterialID = parentMaterialID; + _parentMaterialName = parentMaterialName; applyMaterial(); } } @@ -293,16 +278,16 @@ void MaterialEntityItem::removeMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->removeMaterial(material, getParentMaterialID()); + entity->removeMaterial(material, getParentMaterialName()); return; } } - if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialID())) { + if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName())) { return; } - if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialID())) { + if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialName())) { return; } @@ -317,9 +302,9 @@ void MaterialEntityItem::applyMaterial() { return; } Transform textureTransform; - textureTransform.setTranslation(glm::vec3(_materialPos, 0)); - textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialRot))); - textureTransform.setScale(glm::vec3(_materialScale, 1)); + textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); + textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot))); + textureTransform.setScale(glm::vec3(_materialMappingScale, 1)); material->setTextureTransforms(textureTransform); material->setPriority(getPriority()); @@ -328,16 +313,16 @@ void MaterialEntityItem::applyMaterial() { if (tree) { EntityItemPointer entity = tree->findEntityByEntityItemID(parentID); if (entity) { - entity->addMaterial(material, getParentMaterialID()); + entity->addMaterial(material, getParentMaterialName()); return; } } - if (EntityTree::addMaterialToAvatar(parentID, material, getParentMaterialID())) { + if (EntityTree::addMaterialToAvatar(parentID, material, getParentMaterialName())) { return; } - if (EntityTree::addMaterialToOverlay(parentID, material, getParentMaterialID())) { + if (EntityTree::addMaterialToOverlay(parentID, material, getParentMaterialName())) { return; } diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index d015bae681..3c8df190bf 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -11,7 +11,7 @@ #include "EntityItem.h" -#include "MaterialMode.h" +#include "MaterialMappingMode.h" #include #include @@ -58,21 +58,21 @@ public: QString getCurrentMaterialName() const { return _currentMaterialName; } void setCurrentMaterialName(const QString& currentMaterialName); - MaterialMode getMaterialMode() const { return _materialMode; } - void setMaterialMode(MaterialMode mode) { _materialMode = mode; } + MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; } + void setMaterialMappingMode(MaterialMappingMode mode) { _materialMappingMode = mode; } quint16 getPriority() const { return _priority; } void setPriority(quint16 priority); - QString getParentMaterialID() const { return _parentMaterialID; } - void setParentMaterialID(const QString& parentMaterialID); + QString getParentMaterialName() const { return _parentMaterialName; } + void setParentMaterialName(const QString& parentMaterialName); - 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); + glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; } + void setMaterialMappingPos(const glm::vec2& materialMappingPos); + glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; } + void setMaterialMappingScale(const glm::vec2& materialMappingScale); + float getMaterialMappingRot() const { return _materialMappingRot; } + void setMaterialMappingRot(const float& materialMappingRot); std::shared_ptr getMaterial() const; @@ -91,33 +91,37 @@ public: 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 + // materialVersion: a uint for the version of this network material (currently, only 1 is supported) + // materials, which is either an object or an array of objects, each with the following properties: + // strings: + // name (NOT YET USED), model (NOT YET USED, should use "hifi_pbr") + // floats: + // opacity, roughness, metallic, scattering + // bool: + // unlit + // colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB): + // emissive, albedo + // urls to textures: + // emissiveMap, albedoMap (set opacityMap = albedoMap for transparency), metallicMap or specularMap, roughnessMap or glossMap, + // normalMap or bumpMap, occlusionMap, lightmapMap (broken, FIXME), scatteringMap (only works if normal mapped) QString _materialURL; // Type of material. "uv" or "projected". NOT YET IMPLEMENTED, only UV is used - MaterialMode _materialMode { UV }; + MaterialMappingMode _materialMappingMode { 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" }; + // parentMaterialName will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify. + QString _parentMaterialName { "0" }; // Offset position in UV-space of top left of material, (0, 0) to (1, 1) - glm::vec2 _materialPos { 0, 0 }; + glm::vec2 _materialMappingPos { 0, 0 }; // How much to scale this material within its parent's UV-space - glm::vec2 _materialScale { 1, 1 }; + glm::vec2 _materialMappingScale { 1, 1 }; // How much to rotate this material within its parent's UV-space (degrees) - float _materialRot { 0 }; + float _materialMappingRot { 0 }; NetworkMaterialResourcePointer _networkMaterial; - QHash> _materials; - std::vector _materialNames; + NetworkMaterialResource::ParsedMaterials _parsedMaterials; QString _currentMaterialName; bool _retryApply { false }; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 5abc090be3..4b1e7c82c1 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -361,6 +361,8 @@ public: const QString& getName() { return _name; } + void setModel(const QString& model) { _model = model; } + protected: QString _name { "" }; @@ -379,6 +381,8 @@ private: quint16 _priority { 0 }; + QString _model { "hifi_pbr" }; + }; typedef std::shared_ptr< Material > MaterialPointer; diff --git a/libraries/model-networking/src/model-networking/MaterialCache.cpp b/libraries/model-networking/src/model-networking/MaterialCache.cpp index 723448f65a..ef1d071d86 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.cpp +++ b/libraries/model-networking/src/model-networking/MaterialCache.cpp @@ -15,13 +15,10 @@ 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; - } + parsedMaterials.reset(); + + if (_url.toString().contains(".json")) { + parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data)); } // TODO: parse other material types @@ -46,6 +43,39 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& return false; } +NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) { + ParsedMaterials toReturn; + if (!materialJSON.isNull() && materialJSON.isObject()) { + QJsonObject materialJSONObject = materialJSON.object(); + for (auto& key : materialJSONObject.keys()) { + if (key == "materialVersion") { + auto value = materialJSONObject.value(key); + if (value.isDouble()) { + toReturn.version = (uint)value.toInt(); + } + } else if (key == "materials") { + auto materialsValue = materialJSONObject.value(key); + if (materialsValue.isArray()) { + QJsonArray materials = materialsValue.toArray(); + for (auto material : materials) { + if (!material.isNull() && material.isObject()) { + auto parsedMaterial = parseJSONMaterial(material.toObject()); + toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; + toReturn.names.push_back(parsedMaterial.first); + } + } + } else if (materialsValue.isObject()) { + auto parsedMaterial = parseJSONMaterial(materialsValue.toObject()); + toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second; + toReturn.names.push_back(parsedMaterial.first); + } + } + } + } + + return toReturn;; +} + std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) { QString name = ""; std::shared_ptr material = std::make_shared(); @@ -55,6 +85,11 @@ std::pair> NetworkMaterialResource::pa if (nameJSON.isString()) { name = nameJSON.toString(); } + } else if (key == "model") { + auto modelJSON = materialJSON.value(key); + if (modelJSON.isString()) { + material->setModel(modelJSON.toString()); + } } else if (key == "emissive") { glm::vec3 color; bool isSRGB; @@ -67,6 +102,11 @@ std::pair> NetworkMaterialResource::pa if (value.isDouble()) { material->setOpacity(value.toDouble()); } + } else if (key == "unlit") { + auto value = materialJSON.value(key); + if (value.isBool()) { + material->setUnlit(value.toBool()); + } } else if (key == "albedo") { glm::vec3 color; bool isSRGB; @@ -79,13 +119,6 @@ std::pair> NetworkMaterialResource::pa 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()) { diff --git a/libraries/model-networking/src/model-networking/MaterialCache.h b/libraries/model-networking/src/model-networking/MaterialCache.h index 1b0f1c577c..3188fd0094 100644 --- a/libraries/model-networking/src/model-networking/MaterialCache.h +++ b/libraries/model-networking/src/model-networking/MaterialCache.h @@ -22,9 +22,22 @@ public: virtual void downloadFinished(const QByteArray& data) override; - QString name { "" }; - std::shared_ptr networkMaterial { nullptr }; + typedef struct ParsedMaterials { + uint version { 1 }; + std::vector names; + QHash> networkMaterials; + void reset() { + version = 1; + names.clear(); + networkMaterials.clear(); + } + + } ParsedMaterials; + + ParsedMaterials parsedMaterials; + + static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON); static std::pair> parseJSONMaterial(const QJsonObject& materialJSON); private: diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 85100ec177..8d8f599fea 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -33,7 +33,7 @@ #include #include -#include "MaterialMode.h" +#include "MaterialMappingMode.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -263,7 +263,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, MaterialMappingMode& 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/Model.cpp b/libraries/render-utils/src/Model.cpp index 84687a46d0..15cab065f3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1527,29 +1527,29 @@ bool Model::isRenderable() const { return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } -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 +std::vector Model::getMeshIDsFromMaterialID(QString parentMaterialName) { + // try to find all meshes with materials that match parentMaterialName as a string + // if none, return parentMaterialName as a uint 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) { + if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) { + parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString("")); + for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) { + if (_modelMeshMaterialNames[i] == parentMaterialName) { toReturn.push_back(i); } } } if (toReturn.empty()) { - toReturn.push_back(parentMaterialID.toUInt()); + toReturn.push_back(parentMaterialName.toUInt()); } return toReturn; } -void Model::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { - std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); +void Model::addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialName); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { @@ -1573,8 +1573,8 @@ void Model::addMaterial(graphics::MaterialPointer material, const QString& paren AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } -void Model::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID) { - std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialID); +void Model::removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName) { + std::vector shapeIDs = getMeshIDsFromMaterialID(parentMaterialName); render::Transaction transaction; for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 67bc646473..6b59b62046 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, const QString& parentMaterialID); - void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialID); + void addMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); + void removeMaterial(graphics::MaterialPointer material, const QString& parentMaterialName); public slots: void loadURLFinished(bool success); @@ -473,7 +473,7 @@ private: void calculateTextureInfo(); - std::vector getMeshIDsFromMaterialID(QString parentMaterialID); + std::vector getMeshIDsFromMaterialID(QString parentMaterialName); }; Q_DECLARE_METATYPE(ModelPointer) diff --git a/libraries/shared/src/MaterialMappingMode.cpp b/libraries/shared/src/MaterialMappingMode.cpp new file mode 100644 index 0000000000..1ddad178a2 --- /dev/null +++ b/libraries/shared/src/MaterialMappingMode.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 "MaterialMappingMode.h" + +const char* materialMappingModeNames[] = { + "uv", + "projected" +}; + +static const size_t MATERIAL_MODE_NAMES = (sizeof(materialMappingModeNames) / sizeof((materialMappingModeNames)[0])); + +QString MaterialMappingModeHelpers::getNameForMaterialMappingMode(MaterialMappingMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) { + mode = (MaterialMappingMode)0; + } + + return materialMappingModeNames[(int)mode]; +} \ No newline at end of file diff --git a/libraries/shared/src/MaterialMode.h b/libraries/shared/src/MaterialMappingMode.h similarity index 54% rename from libraries/shared/src/MaterialMode.h rename to libraries/shared/src/MaterialMappingMode.h index a933693f75..848c2aa28c 100644 --- a/libraries/shared/src/MaterialMode.h +++ b/libraries/shared/src/MaterialMappingMode.h @@ -6,20 +6,20 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_MaterialMode_h -#define hifi_MaterialMode_h +#ifndef hifi_MaterialMappingMode_h +#define hifi_MaterialMappingMode_h #include "QString" -enum MaterialMode { +enum MaterialMappingMode { UV = 0, PROJECTED }; -class MaterialModeHelpers { +class MaterialMappingModeHelpers { public: - static QString getNameForMaterialMode(MaterialMode mode); + static QString getNameForMaterialMappingMode(MaterialMappingMode mode); }; -#endif // hifi_MaterialMode_h +#endif // hifi_MaterialMappingMode_h diff --git a/libraries/shared/src/MaterialMode.cpp b/libraries/shared/src/MaterialMode.cpp deleted file mode 100644 index cb656a7bf7..0000000000 --- a/libraries/shared/src/MaterialMode.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// 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/scripts/developer/tests/toolbarTest.js b/scripts/developer/tests/toolbarTest.js index dfc97ebe39..b713445927 100644 --- a/scripts/developer/tests/toolbarTest.js +++ b/scripts/developer/tests/toolbarTest.js @@ -92,7 +92,7 @@ var toolBar = (function() { newMaterialButton = toolBar.addButton({ objectName: "newMaterialButton", - imageURL: toolIconUrl + "model-01.svg", + imageURL: toolIconUrl + "material-01.svg", alpha: 0.9, visible: false }); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 15d4759a8a..0167b55810 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -400,10 +400,10 @@ var toolBar = (function () { function handleNewMaterialDialogResult(result) { if (result) { var materialURL = result.textInput; - //var materialMode; + //var materialMappingMode; //switch (result.comboBox) { // case MATERIAL_MODE_PROJECTED: - // materialMode = "projected"; + // materialMappingMode = "projected"; // break; // default: // shapeType = "uv"; @@ -414,7 +414,7 @@ var toolBar = (function () { createNewEntity({ type: "Material", materialURL: materialURL, - //materialMode: materialMode, + //materialMappingMode: materialMappingMode, priority: DEFAULT_LAYERED_MATERIAL_PRIORITY }); } diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 2ca0107d19..c53a2fa5bd 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -805,7 +805,7 @@